[java-idp-plugin-oidc-op-oidfed] branch dev/CACHE-REFACTOR updated: Include the use of jwks_uri into the automatic registration tests

Codeberg noreply at shibboleth.net
Fri Mar 20 11:22:38 UTC 2026


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

codeberg pushed a commit to branch dev/CACHE-REFACTOR
in repository java-idp-plugin-oidc-op-oidfed.

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

The following commit(s) were added to refs/heads/dev/CACHE-REFACTOR by this push:
     new 92123fc  Include the use of jwks_uri into the automatic registration tests
92123fc is described below

commit 92123fc7168b473d8b846e96dad85bac267e7ebd
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Mar 20 13:21:51 2026 +0200

    Include the use of jwks_uri into the automatic registration tests
---
 .../flow/oidfed/AbstractFederationFlowTest.java    | 27 ++++++++++++-
 .../AuthorizeFlowAutomaticRegistrationTest.java    | 46 ++++++++++++++++++++++
 ...shedAuthorizeFlowAutomaticRegistrationTest.java | 29 ++++++++++++++
 .../oidfed/TokenFlowAutomaticRegistrationTest.java | 46 ++++++++++++++++++++++
 .../net/shibboleth/idp/module/conf/global.xml      |  6 +++
 5 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java
index 9b26b9f..b31d518 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java
@@ -116,7 +116,11 @@ public class AbstractFederationFlowTest extends AbstractOidcFlowTest {
     @Autowired
     @Qualifier("shibboleth.oidfed.HttpClient")
     protected HttpClient federationHttpClient;
-    
+
+    @Autowired
+    @Qualifier("shibboleth.oidc.NonBrowser.HttpClient")
+    protected HttpClient vanillaOidcHttpClient;
+
     protected AbstractFederationFlowTest(final String flowId) {
         super(flowId);
     }
@@ -215,6 +219,12 @@ public class AbstractFederationFlowTest extends AbstractOidcFlowTest {
             .thenReturn(classicResponse);
     }
 
+    protected void mapVanillaOidcResponse(final String requestUri, final ClassicHttpResponse classicResponse)
+        throws IOException {
+        when(vanillaOidcHttpClient.executeOpen(any(), argThat(new RequestUriMatcher(requestUri)), any()))
+            .thenReturn(classicResponse);
+    }
+
     protected ClassicHttpResponse mockResponse(final String contents)
             throws UnsupportedOperationException, IOException {
         return mockResponse(200, "application/entity-statement+jwt", contents);
@@ -502,6 +512,21 @@ public class AbstractFederationFlowTest extends AbstractOidcFlowTest {
         }
     }
 
+    protected void rpConfigureMockHttpClient(final String clientId, final URI jwksUri) {
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        try {
+            metadata.setRedirectionURI(new URI(redirectUri));
+            metadata.setJWKSetURI(jwksUri);
+            mapResponse(entityConfigurationUrl(clientId), mockResponse(rpEntityConfiguration(clientId, metadata)));
+            mapResponse(entityConfigurationUrl(anchorId), mockResponse(trustedAnchorConfiguration()));
+            mapResponse(subordinateStatementUrl(anchorFetchEndpoint, clientId),
+                    mockResponse(subordinateStatement(clientId, Map.of("openid_relying_party",
+                            new OIDCClientMetadata().toJSONObject()))));
+        } catch (UnsupportedOperationException | IOException | URISyntaxException e) {
+            Assert.fail("Could not initialize mock HTTP client", e);
+        }
+    }
+
     protected void rpConfigureMockHttpClient(final String clientId, final JWK leafKey) {
         try {
             mapResponse(entityConfigurationUrl(clientId),
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java
index 762f251..9d9469b 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java
@@ -121,6 +121,52 @@ public class AuthorizeFlowAutomaticRegistrationTest extends AbstractFederationFl
         Assert.assertEquals(unwrapTrustChainFromAuthorizeCode(successResponse), List.of(clientId, anchorId));
     }
 
+    @Test
+    public void testWithValidTrustChain_signedRequestObject_jwksUri()
+            throws IOException, UnsupportedOperationException, URISyntaxException {
+        final String clientId = uniqueClientId();
+        final String jwksUri = clientId + "/jwks";
+        rpConfigureMockHttpClient(clientId, URI.create(jwksUri));
+        mapVanillaOidcResponse(jwksUri, mockResponse(200, "application/json",
+                new JWKSet(rpKey.toPublicJWK()).toString()));
+        final FlowExecutionResult result =
+                launchAuthenticationRequest(clientId, "openid profile", signedRequestObject(Map.of(
+                        "iss", clientId,
+                        "client_id", clientId,
+                        "aud", issuer,
+                        "exp", Instant.now().plus(Duration.ofMinutes(5)).toEpochMilli(),
+                        "jti", UUID.randomUUID(),
+                        "response_type", "code",
+                        "scope", "openid profile",
+                        "redirect_uri", redirectUri)));
+        final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+        final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+        Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+        Assert.assertNull(successResponse.getIDToken());
+        Assert.assertNull(successResponse.getAccessToken());
+        Assert.assertNotNull(successResponse.getAuthorizationCode());
+        Assert.assertEquals(unwrapTrustChainFromAuthorizeCode(successResponse), List.of(clientId, anchorId));
+    }
+
+    @Test
+    public void testWithValidTrustChain_signedRequestObject_invalidJwksUri()
+            throws IOException, UnsupportedOperationException, URISyntaxException {
+        final String clientId = uniqueClientId();
+        final String jwksUri = clientId + "/jwks";
+        rpConfigureMockHttpClient(clientId, URI.create(jwksUri));
+        final FlowExecutionResult result =
+                launchAuthenticationRequest(clientId, "openid profile", signedRequestObject(Map.of(
+                        "iss", clientId,
+                        "client_id", clientId,
+                        "aud", issuer,
+                        "exp", Instant.now().plus(Duration.ofMinutes(5)).toEpochMilli(),
+                        "jti", UUID.randomUUID(),
+                        "response_type", "code",
+                        "scope", "openid profile",
+                        "redirect_uri", redirectUri)));
+        Assert.assertEquals(result.getOutcome().getId(), "ErrorView");
+    }
+
     @Test
     public void testWithValidTrustChain_signedRequestObject_emptyMetadataPolicyCrit()
             throws IOException, UnsupportedOperationException, URISyntaxException {
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/PushedAuthorizeFlowAutomaticRegistrationTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/PushedAuthorizeFlowAutomaticRegistrationTest.java
index 206f314..2ffdd13 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/PushedAuthorizeFlowAutomaticRegistrationTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/PushedAuthorizeFlowAutomaticRegistrationTest.java
@@ -103,6 +103,35 @@ public class PushedAuthorizeFlowAutomaticRegistrationTest extends AbstractFedera
         verifyAuthorizeEndpoint(clientId, response.getRequestURI().toString());
     }
 
+    @Test
+    public void testSuccess_jwksUri() throws Exception {
+        final String clientId = uniqueClientId();
+        final String jwksUri = clientId + "/jwks";
+        rpConfigureMockHttpClient(clientId, URI.create(jwksUri));
+        mapVanillaOidcResponse(jwksUri, mockResponse(200, "application/json",
+                new JWKSet(rpKey.toPublicJWK()).toString()));
+        final SignedJWT jwt = createPrivateKeyJWT(validJwtAuthenticationClaimsSet(clientId, issuer),
+                rpKey.toRSAKey().toRSAPrivateKey(), JWSAlgorithm.RS512);
+        final FlowExecutionResult result = launchWithJwtAuthentication(jwt, null,
+                ClientAuthenticationMethod.PRIVATE_KEY_JWT, rpKey.toRSAKey().toPublicKey());
+        assertSuccessResponse(result, clientId);
+        final PushedAuthorizationSuccessResponse response =
+                parseSuccessResponse(result, PushedAuthorizationSuccessResponse.class);
+        verifyAuthorizeEndpoint(clientId, response.getRequestURI().toString());
+    }
+
+    @Test
+    public void testFails_invalidJwksUri() throws Exception {
+        final String clientId = uniqueClientId();
+        final String jwksUri = clientId + "/jwks";
+        rpConfigureMockHttpClient(clientId, URI.create(jwksUri));
+        final SignedJWT jwt = createPrivateKeyJWT(validJwtAuthenticationClaimsSet(clientId, issuer),
+                rpKey.toRSAKey().toRSAPrivateKey(), JWSAlgorithm.RS512);
+        final FlowExecutionResult result = launchWithJwtAuthentication(jwt, null,
+                ClientAuthenticationMethod.PRIVATE_KEY_JWT, rpKey.toRSAKey().toPublicKey());
+        assertErrorCode(result, OAuth2Error.INVALID_CLIENT_CODE);
+    }
+
     @Test
     public void testUnmatchingRpConfigurationSignature() throws Exception {
         final String clientId = uniqueClientId();
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/TokenFlowAutomaticRegistrationTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/TokenFlowAutomaticRegistrationTest.java
index ead63e7..6e6af99 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/TokenFlowAutomaticRegistrationTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/TokenFlowAutomaticRegistrationTest.java
@@ -29,6 +29,7 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jwt.JWT;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.SignedJWT;
@@ -80,6 +81,51 @@ public class TokenFlowAutomaticRegistrationTest extends AbstractFederationFlowTe
         Assert.assertNotNull(response.getOIDCTokens().getIDToken().getJWTClaimsSet().getClaim("at_hash"));
     }
 
+    @Test
+    public void testSuccess_jwksUri() throws Exception {
+        final String clientId = uniqueClientId();
+        final String jwksUri = clientId + "/jwks";
+        rpConfigureMockHttpClient(clientId, URI.create(jwksUri));
+        mapVanillaOidcResponse(jwksUri, mockResponse(200, "application/json",
+                new JWKSet(rpKey.toPublicJWK()).toString()));
+        final SignedJWT jwt = createPrivateKeyJWT(validJwtAuthenticationClaimsSet(clientId, issuer),
+                rpKey.toRSAKey().toRSAPrivateKey(), JWSAlgorithm.RS512);
+        final Map<String,String> requestParameters = new HashMap<>(Map.of(
+                "redirect_uri", redirectUri,
+                "grant_type", "authorization_code",
+                "code", buildAuthorizationCode(clientId, List.of(clientId, anchorId)),
+                "client_id", clientId));
+        final FlowExecutionResult result = launchWithJwtAuthentication(jwt, JWSAlgorithm.RS512,
+                ClientAuthenticationMethod.PRIVATE_KEY_JWT, null, requestParameters);
+        final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+        Assert.assertNotNull(response.getTokens().getAccessToken());
+        final AccessTokenClaimsSet tokenClaims =
+                AccessTokenClaimsSet.parse(response.getTokens().getAccessToken().getValue(), getDataSealer());
+        final JWTClaimsSet claimsSet = tokenClaims.getClaimsSet();
+        assert claimsSet != null;
+        Assert.assertEquals(claimsSet.getStringListClaim(ClaimsSetExtensionSupport.KEY_AUTO_REGISTERED_TRUST_CHAIN),
+                List.of(clientId, anchorId));
+        Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+        Assert.assertNotNull(response.getOIDCTokens().getIDToken().getJWTClaimsSet().getClaim("at_hash"));
+    }
+
+    @Test
+    public void testFails_invalidJwksUri() throws Exception {
+        final String clientId = uniqueClientId();
+        final String jwksUri = clientId + "/jwks";
+        rpConfigureMockHttpClient(clientId, URI.create(jwksUri));
+        final SignedJWT jwt = createPrivateKeyJWT(validJwtAuthenticationClaimsSet(clientId, issuer),
+                rpKey.toRSAKey().toRSAPrivateKey(), JWSAlgorithm.RS512);
+        final Map<String,String> requestParameters = new HashMap<>(Map.of(
+                "redirect_uri", redirectUri,
+                "grant_type", "authorization_code",
+                "code", buildAuthorizationCode(clientId, List.of(clientId, anchorId)),
+                "client_id", clientId));
+        final FlowExecutionResult result = launchWithJwtAuthentication(jwt, JWSAlgorithm.RS512,
+                ClientAuthenticationMethod.PRIVATE_KEY_JWT, null, requestParameters);
+        assertErrorCode(result, OAuth2Error.INVALID_CLIENT_CODE);
+    }
+
     @Test
     public void testSuccess_resolveApi() throws Exception {
         final String clientId = uniqueClientId();
diff --git a/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/global.xml b/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/global.xml
index 07602b6..90f8968 100644
--- a/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/global.xml
+++ b/idp-oidfed-op-impl/src/test/resources/net/shibboleth/idp/module/conf/global.xml
@@ -89,6 +89,12 @@
         <constructor-arg value="#{T(org.apache.hc.client5.http.classic.HttpClient)}" />
     </bean>
 
+    <bean id="shibboleth.oidc.NonBrowser.HttpClient"
+        factory-bean="MockitoMockFactory"
+        factory-method="mock">
+        <constructor-arg value="#{T(org.apache.hc.client5.http.classic.HttpClient)}" />
+    </bean>
+
     <bean id="HeaderUseResolveApiCondition" parent="shibboleth.Conditions.Expression"
         p:customObject-ref="shibboleth.HttpServletRequestSupplier"
         c:expression="'true'.equals(#custom.get().getHeader('useCustomResolverApi'))" />

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


More information about the commits mailing list