[java-idp-plugin-oidc-op-oidfed] 02/02: Improvements mainly for explicit registration request handling

Codeberg noreply at shibboleth.net
Fri Oct 9 10:19:50 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch main
in repository java-idp-plugin-oidc-op-oidfed.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-oidc-op-oidfed/commit/97aced6a3b1b9642f4cc80799eb01be7e242ccc5

commit 97aced6a3b1b9642f4cc80799eb01be7e242ccc5
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Oct 9 13:19:20 2026 +0300

    Improvements mainly for explicit registration request handling
    
    - Improved content type validation: only validate the mime-type
    - Copy the jwks from request to response as is, as mandated by the spec
    - Map explicit registration error events better to the error messages
    - Fixed some typos in the log messages
    - Improve testing
---
 .../ExplicitClientRegistrationRequestDecoder.java  | 37 +++++++---
 .../impl/AddExtensionsToClientInformation.java     |  2 +-
 .../impl/BuildExplicitRegistrationResponse.java    | 10 +--
 .../profile/impl/ValidateProvidedTrustChain.java   |  2 +-
 ...videdEntityConfigurationValidationStrategy.java |  2 +-
 ...aultPreSelectedTrustChainIDsLookupStrategy.java |  7 +-
 ...entRegistrationRequestJWKSetLookupFunction.java | 35 ++++++---
 .../META-INF/net.shibboleth.idp/postconfig.xml     | 36 +++++++++
 .../profile/flow/oidfed/RegistrationFlowTest.java  | 86 ++++++++++++++++++++--
 9 files changed, 177 insertions(+), 40 deletions(-)

diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/decoding/impl/ExplicitClientRegistrationRequestDecoder.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/decoding/impl/ExplicitClientRegistrationRequestDecoder.java
index 629195e..2345bc3 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/decoding/impl/ExplicitClientRegistrationRequestDecoder.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/decoding/impl/ExplicitClientRegistrationRequestDecoder.java
@@ -16,11 +16,14 @@ package net.shibboleth.idp.plugin.oidc.op.oidfed.decoding.impl;
 
 import java.io.IOException;
 import java.net.URI;
+import java.nio.charset.UnsupportedCharsetException;
 import java.util.List;
+import java.util.Objects;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.apache.hc.core5.http.ContentType;
 import org.opensaml.messaging.decoder.MessageDecodingException;
 import org.slf4j.Logger;
 
@@ -42,6 +45,7 @@ import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.logic.ConstraintViolationException;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.primitive.StringSupport;
 
 /**
  * Message decoder decoding OpenID Federation Explicit Registration request {@link ExplicitClientRegistrationRequest}.
@@ -91,8 +95,8 @@ public class ExplicitClientRegistrationRequestDecoder
                 throw new MessageDecodingException("Could not parse request URI");
             }
             final String contentType = request.getContentType();
-            if ("application/entity-statement+jwt".equals(contentType)) {
-                final String query = httpRequest.getQuery();
+            if (ContentType.create("application/entity-statement+jwt").isSameMimeType(ContentType.parse(contentType))) {
+                final String query = StringSupport.trimOrNull(httpRequest.getBody());
                 if (query != null) {
                     try {
                         assert objectMapper != null;
@@ -107,21 +111,30 @@ public class ExplicitClientRegistrationRequestDecoder
                     }
                 }
                 throw new MessageDecodingException("Could not deserialize entity configuration");
-            } else if ("application/trust-chain+json".equals(contentType)) {
-                final TypeReference<List<String>> typeReference = new TypeReference<List<String>>() {};
-                final List<String> strings = objectMapper.readValue(httpRequest.getQuery(), typeReference);
-                assert strings != null; assert objectMapper != null;
-                final List<EntityStatement<?>> trustChain =
-                        EntityStatementHelper.deserializeTrustChain(strings, objectMapper);
-                if (trustChain == null) {
-                    throw new MessageDecodingException("Could not deserialize trust chain");
+            } else if (ContentType.create("application/trust-chain+json").isSameMimeType(
+                    ContentType.parse(contentType))) {
+                final String body = StringSupport.trimOrNull(httpRequest.getBody());
+                if (body != null) {
+                    final TypeReference<List<String>> typeReference = new TypeReference<List<String>>() {};
+                    final List<String> rawStrings = objectMapper.readValue(body, typeReference);
+                    if (rawStrings == null) {
+                        throw new MessageDecodingException("Could not deserialize trust chain");
+                    }
+                    final List<String> strings = rawStrings.stream().filter(Objects::nonNull).toList();
+                    assert strings != null; assert objectMapper != null;
+                    final List<EntityStatement<?>> trustChain =
+                            EntityStatementHelper.deserializeTrustChain(strings, objectMapper);
+                    if (trustChain == null) {
+                        throw new MessageDecodingException("Could not deserialize trust chain");
+                    }
+                    return new ExplicitClientRegistrationRequest(uri, trustChain);
                 }
-                return new ExplicitClientRegistrationRequest(uri, trustChain);
+                throw new MessageDecodingException("Could not deserialize trust chain");
             } else {
                 log.warn("Unexpected content type {}", contentType);
                 throw new MessageDecodingException("Unexpected content type: " + contentType);
             }
-        } catch (final IOException e) {
+        } catch (final IOException | UnsupportedCharsetException e) {
             log.error("Could not create HTTP request from the request", e);
             throw new MessageDecodingException(e);
         }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java
index 979ab13..456cdf8 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/AddExtensionsToClientInformation.java
@@ -141,7 +141,7 @@ public class AddExtensionsToClientInformation extends AbstractProfileAction {
         final OIDCClientRegistrationResponseContext oidcResponseCtx =
                 oidcResponseContextLookupStrategy.apply(profileRequestContext);
         if (oidcResponseCtx == null || oidcResponseCtx.getClientInformation() == null) {
-            log.debug("{} No OIDC client informationt could be resolved with this profile request", 
+            log.debug("{} No OIDC client information could be resolved with this profile request", 
                     getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
             return false;            
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java
index 36aa568..c305782 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/BuildExplicitRegistrationResponse.java
@@ -17,6 +17,7 @@ package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.impl;
 import java.time.Instant;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -29,7 +30,6 @@ import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
 import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
 import org.slf4j.Logger;
 
-import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
 
@@ -60,7 +60,7 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
     @Nonnull private Function<ProfileRequestContext,OIDCClientRegistrationResponseContext> oidcResponseContextLookupStrategy;
 
     /** Strategy used to locate the JWK set to be included in the response entity statement. */
-    @Nonnull private Function<ProfileRequestContext,JWKSet> jwkSetLookupStrategy;
+    @Nonnull private Function<ProfileRequestContext,Map<String,Object>> jwkSetLookupStrategy;
 
     /** Strategy used to lookup the trust chain context. */
     @Nonnull private Function<ProfileRequestContext, RelyingPartyTrustChainContext> trustChainContextLookupStrategy;
@@ -112,7 +112,7 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
      * 
      * @param strategy lookup strategy
      */
-    public void setJwkSetLookupStrategy(@Nonnull final Function<ProfileRequestContext,JWKSet> strategy) {
+    public void setJwkSetLookupStrategy(@Nonnull final Function<ProfileRequestContext,Map<String,Object>> strategy) {
         checkSetterPreconditions();
         jwkSetLookupStrategy = Constraint.isNotNull(strategy, "JWK set loookup strategy cannot be null");
     }
@@ -189,13 +189,13 @@ public class BuildExplicitRegistrationResponse extends AbstractBuildEntityStatem
         builder.claim("metadata",
                 CollectionSupport.singletonMap("openid_relying_party", clientInformation.toJSONObject()));
 
-        final JWKSet jwkSet = jwkSetLookupStrategy.apply(profileRequestContext);
+        final Map<String,Object> jwkSet = jwkSetLookupStrategy.apply(profileRequestContext);
         if (jwkSet == null) {
             log.error("{} Coud not resolve JWK set to be included in the response statement", getLogPrefix());
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
             return false;
         }
-        builder.claim("jwks", jwkSet.toJSONObject(true));
+        builder.claim("jwks", CollectionSupport.copyToMap(jwkSet));
 
         final Instant expirationTime = trustChainContext.getSelectedMetadataExpiration();
         if (expirationTime == null) {
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java
index ee24179..0b931f9 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/impl/ValidateProvidedTrustChain.java
@@ -160,7 +160,7 @@ public class ValidateProvidedTrustChain extends AbstractTrustChainResolutionActi
             return false;
         }
         if (ignoreProvidedTrustChainCondition.test(profileRequestContext)) {
-            log.debug("{} Provided trust chains are configurd to be ignored, nothing to do", getLogPrefix());
+            log.debug("{} Provided trust chains are configured to be ignored, nothing to do", getLogPrefix());
             return false;
         }
         if (trustChain == null) {
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/logic/DefaultProvidedEntityConfigurationValidationStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/logic/DefaultProvidedEntityConfigurationValidationStrategy.java
index 936497b..44875c8 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/logic/DefaultProvidedEntityConfigurationValidationStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/logic/DefaultProvidedEntityConfigurationValidationStrategy.java
@@ -86,7 +86,7 @@ public class DefaultProvidedEntityConfigurationValidationStrategy extends Abstra
                     return true;
                 }
             } catch (final MetadataCacheException e) {
-                log.debug("{} Exception catched when validating entty configuration", e);
+                log.debug("Exception catched when validating entity configuration", e);
             }
            
         } else {
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultPreSelectedTrustChainIDsLookupStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultPreSelectedTrustChainIDsLookupStrategy.java
index 4ed4ff6..361bdfe 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultPreSelectedTrustChainIDsLookupStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/DefaultPreSelectedTrustChainIDsLookupStrategy.java
@@ -19,6 +19,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -92,7 +93,7 @@ public class DefaultPreSelectedTrustChainIDsLookupStrategy extends AbstractIdent
         return Optional.ofNullable(profileIdLookupStrategy.apply(input))
                 .map(profileId -> profileSpecificStrategies.get(profileId))
                 .map(function -> function.apply(input))
-                .orElse(defaultValue(input));
+                .orElseGet(defaultValue(input));
     }
 
     /**
@@ -101,8 +102,8 @@ public class DefaultPreSelectedTrustChainIDsLookupStrategy extends AbstractIdent
      * @param input profile request context
      * @return trust chain IDs
      */
-    private List<String> defaultValue(@Nullable final ProfileRequestContext input) {
-        return Optional.ofNullable(input)
+    private Supplier<List<String>> defaultValue(@Nullable final ProfileRequestContext input) {
+        return () -> Optional.ofNullable(input)
                 .filter(prc -> prc.getOutboundMessageContext() != null)
                 .map(prc -> prc.ensureOutboundMessageContext())
                 .filter(msgCtx -> msgCtx.containsSubcontext(OIDCAuthenticationResponseContext.class))
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/ExplicitClientRegistrationRequestJWKSetLookupFunction.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/ExplicitClientRegistrationRequestJWKSetLookupFunction.java
index 9152b6f..916a488 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/ExplicitClientRegistrationRequestJWKSetLookupFunction.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/profile/navigate/ExplicitClientRegistrationRequestJWKSetLookupFunction.java
@@ -14,31 +14,40 @@
 
 package net.shibboleth.idp.plugin.oidc.op.oidfed.profile.navigate;
 
+import java.text.ParseException;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
 
 import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
 
 import com.nimbusds.jose.jwk.JWKSet;
 
 import net.shibboleth.oidfed.messaging.impl.ExplicitClientRegistrationRequest;
 import net.shibboleth.oidfed.metadata.EntityConfiguration;
 import net.shibboleth.oidfed.metadata.EntityStatement;
+import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
- * A function that returns {@link JWKSet} from the entity configuration in the explicit registration request.
+ * A function that returns {@link JWKSet} as Map from the entity configuration in the explicit registration request.
  */
 @ThreadSafe
 public class ExplicitClientRegistrationRequestJWKSetLookupFunction
-    implements ContextDataLookupFunction<ProfileRequestContext, JWKSet> {
+    implements ContextDataLookupFunction<ProfileRequestContext, Map<String,Object>> {
+
+    /** Class logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(ExplicitClientRegistrationRequestJWKSetLookupFunction.class);
 
     /** {@inheritDoc} */
     @Nullable
-    public JWKSet apply(@Nullable final ProfileRequestContext input) {
+    public Map<String,Object> apply(@Nullable final ProfileRequestContext input) {
         return Optional.ofNullable(input)
                 .map(profileRequesContext -> profileRequesContext.getInboundMessageContext())
                 .map(messageContext -> messageContext.getMessage())
@@ -49,20 +58,26 @@ public class ExplicitClientRegistrationRequestJWKSetLookupFunction
     }
 
     /**
-     * Get the JSON Web Key Set from the explicit registration request.
+     * Get the JSON Web Key Set as Map from the explicit registration request.
      * 
      * @param request explicit registration request
-     * @return the JWKSet, or null if it cannot be parsed
+     * @return the contents of jwks, or null if it cannot be parsed
      */
-    @Nullable protected JWKSet getJWKSet(@Nullable final ExplicitClientRegistrationRequest request) {
+    @Nullable protected Map<String,Object> getJWKSet(@Nullable final ExplicitClientRegistrationRequest request) {
         if (request == null) {
             return null;
         }
         final EntityConfiguration entityConfiguration = request.getEntityConfiguration();
-        if (entityConfiguration != null) {
-            return entityConfiguration.getParsedPayload().getJwks();
+        try {
+            if (entityConfiguration != null) {
+                return entityConfiguration.getJwt().getJWTClaimsSet().getJSONObjectClaim("jwks");
+            }
+            final List<EntityStatement<?>> trustChain = request.getTrustChain();
+            return trustChain != null && !trustChain.isEmpty() ?
+                    trustChain.get(0).getJwt().getJWTClaimsSet().getJSONObjectClaim("jwks") : null;
+        } catch (final ParseException e) {
+            log.error("Could not parse jwks from the JWT claims set", e);
         }
-        final List<EntityStatement<?>> trustChain = request.getTrustChain();
-        return trustChain != null && !trustChain.isEmpty() ? trustChain.get(0).getParsedPayload().getJwks() : null;
+        return null;
     }
 }
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index c8a0eb5..be9d125 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -62,6 +62,42 @@
                     </key>
                     <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_client" c:_1="No acceptable trust chains could be resolved for the client" c:_2="401" />
                 </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.oidfed.profile.OidFederationEventIds.INVALID_PROVIDED_TRUST_CHAIN"/>
+                    </key>
+                    <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_client" c:_1="No acceptable trust chains could be resolved for the client" c:_2="401" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.oidfed.profile.OidFederationEventIds.MISSING_MANDATORY_PROVIDED_TRUST_CHAIN"/>
+                    </key>
+                    <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_client" c:_1="No mandatory trust chains could be resolved for the client" c:_2="401" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.idp.authn.AuthnEventIds.INVALID_CREDENTIALS"/>
+                    </key>
+                    <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_client" c:_1="No acceptable entity configuration could be resolved for the client" c:_2="401" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.oidfed.profile.OidFederationEventIds.INVALID_METADATA_POLICY"/>
+                    </key>
+                    <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_client" c:_1="No acceptable metadata policy could be resolved for the client" c:_2="401" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.oidfed.profile.OidFederationEventIds.INVALID_METADATA_AGAINST_POLICY"/>
+                    </key>
+                    <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_client" c:_1="No acceptable metadata could be resolved for the client against the metadata policy" c:_2="401" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.oidfed.profile.OidFederationEventIds.INVALID_TRUST_CHAIN_AGAINST_CONSTRAINTS"/>
+                    </key>
+                    <bean class="com.nimbusds.oauth2.sdk.ErrorObject" c:_0="invalid_client" c:_1="No acceptable trust chains could be resolved for the client against the policy constraints" c:_2="401" />
+                </entry>
             </map>
         </property>
     </bean>
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
index eb9f820..fd79083 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
@@ -86,6 +86,21 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         assertErrorCode(result, "invalid_request");
     }
 
+    @Test
+    public void testNullEntityConfiguration() throws Exception {
+        request.setMethod("POST");
+        request.setContentType("application/entity-statement+jwt");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+    }
+
+    @Test
+    public void testNullStringEntityConfiguration() throws Exception {
+        setRequest("POST", "null", "application/entity-statement+jwt");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+    }
+
     @Test
     public void testEmptyEntityConfiguration() throws Exception {
         setRequest("POST", "", "application/entity-statement+jwt");
@@ -105,7 +120,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
         verify(federationHttpClient, times(0)).executeOpen(any(),
                 argThat(new RequestUriMatcher(entityConfigurationUrl(clientId))), any());
-        assertErrorCode(result, "invalid_request");
+        assertErrorCode(result, "invalid_client");
     }
 
     @Test
@@ -129,6 +144,18 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         verifyAuthorizeEndpoint(clientId, redirectUri);
     }
 
+    @Test
+    public void testValidEntityConfigurationWithCharsetInContentType() throws Exception {
+        final String clientId = uniqueClientId();
+        rpConfigureMockHttpClient(clientId);
+        setRequest("POST", explicitRegistrationRequest(clientId), "application/entity-statement+jwt;charset=UTF-8");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        verify(federationHttpClient, times(0)).executeOpen(any(),
+                argThat(new RequestUriMatcher(entityConfigurationUrl(clientId))), any());
+        assertResponseStatement(parseSuccessResponse(result, ExplicitClientRegistrationResponse.class), clientId);
+        verifyAuthorizeEndpoint(clientId, redirectUri);
+    }
+
     @Test
     public void testValidEntityConfiguration_emptyMetadataPolicyCrit() throws Exception {
         final String clientId = uniqueClientId();
@@ -152,7 +179,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
         verify(federationHttpClient, times(0)).executeOpen(any(),
                 argThat(new RequestUriMatcher(entityConfigurationUrl(clientId))), any());
-        assertErrorCode(result, "invalid_request");
+        assertErrorCode(result, "invalid_client");
     }
 
     @Test
@@ -295,6 +322,35 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
                 + "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_client");
+    }
+
+    @Test
+    public void testNullTrustChain() throws Exception {
+        request.setMethod("POST");
+        request.setContentType("application/trust-chain+json");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+    }
+
+    @Test
+    public void testNullStringTrustChain() throws Exception {
+        setRequest("POST", "null", "application/trust-chain+json");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+    }
+
+    @Test
+    public void testEmptyTrustChain() throws Exception {
+        setRequest("POST", "", "application/trust-chain+json");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+    }
+
+    @Test
+    public void testNullMememberTrustChain() throws Exception {
+        setRequest("POST", "[null,null,null]", "application/trust-chain+json");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
         assertErrorCode(result, "invalid_request");
     }
 
@@ -314,6 +370,22 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         verifyAuthorizeEndpoint(clientId, redirectUri);
     }
 
+    @Test
+    public void testValidTrustChainWithCharsetInContentType() throws Exception {
+        final String clientId = uniqueClientId();
+        final String trustChain = "[\"" + explicitRegistrationRequest(clientId) + "\", \"" +
+                subordinateStatement(clientId, Map.of("openid_relying_party", new OIDCClientMetadata().toJSONObject()))
+                + "\", \"" + trustedAnchorConfiguration() + "\"]";
+        setRequest("POST", trustChain, "application/trust-chain+json;charset=UTF-8");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        verify(federationHttpClient, times(0)).executeOpen(any(),
+                argThat(new RequestUriMatcher(entityConfigurationUrl(clientId))), any());
+        verify(federationHttpClient, times(0)).executeOpen(any(),
+                argThat(new RequestUriMatcher(super.subordinateStatementUrl(anchorFetchEndpoint, clientId))), any());
+        assertResponseStatement(parseSuccessResponse(result, ExplicitClientRegistrationResponse.class), clientId);
+        verifyAuthorizeEndpoint(clientId, redirectUri);
+    }
+
     @Test
     public void testValidTrustChain_resolveApi() throws Exception {
         final String clientId = uniqueClientId();
@@ -360,7 +432,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
                         Map.of("max_path_length", Integer.valueOf(0))) + "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
-        assertErrorCode(result, "invalid_request");
+        assertErrorCode(result, "invalid_client");
     }
 
     @Test
@@ -377,7 +449,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
                         Map.of("max_path_length", Integer.valueOf(2))) + "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
-        assertErrorCode(result, "invalid_request");
+        assertErrorCode(result, "invalid_client");
     }
 
     @Test
@@ -406,7 +478,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
                 "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
-        assertErrorCode(result, "invalid_request");
+        assertErrorCode(result, "invalid_client");
     }
 
     @Test
@@ -459,7 +531,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
                         new OIDCClientMetadata().toJSONObject())) + "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
-        assertErrorCode(result, "invalid_request");
+        assertErrorCode(result, "invalid_client");
     }
 
     @Test
@@ -478,7 +550,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
                 argThat(new RequestUriMatcher(entityConfigurationUrl(clientId))), any());
         verify(federationHttpClient, times(0)).executeOpen(any(),
                 argThat(new RequestUriMatcher(super.subordinateStatementUrl(anchorFetchEndpoint, clientId))), any());
-        assertErrorCode(result, "invalid_request");
+        assertErrorCode(result, "invalid_client");
     }
 
     @Test

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list