[java-idp-oidc] branch main updated: JOIDC-144 - Improve token audience handling with JWT authentication

Henri Mikkonen henri.mikkonen at iki.fi
Fri Apr 14 06:02:00 UTC 2023


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

hjmikkon pushed a commit to branch main
in repository java-idp-oidc.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=587c291fc83b3bd98cd7b2697465f1004235d03c

The following commit(s) were added to refs/heads/main by this push:
     new 587c291f JOIDC-144 - Improve token audience handling with JWT authentication
587c291f is described below

commit 587c291fc83b3bd98cd7b2697465f1004235d03c
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Apr 14 09:01:08 2023 +0300

    JOIDC-144 - Improve token audience handling with JWT authentication
    
    https://shibboleth.atlassian.net/browse/JOIDC-144
    
    Now uses the new AuthenticationAudienceClaimsValidator from commons for validating
    audience claim in JWT authn. The default configuration accepts the use of
    issuer claim (via responder ID lookup), the flow endpoint URL and token endpoint
    URL in token, introspection and revocation endpoints.
    
    A custom bean can be wired via idp.oauth2.jwtAuth.audienceValidator -property.
    
    For the default validator, endpoint targets where the token endpoint URL can
    be used may be modified via idp.oauth2.jwtAuth.audienceValidator.endpointTargets -property.
    Its default value '/profile/oauth2/introspection,/profile/oauth2/revocation' covers the
    introspection and revocation endpoints.
---
 .../idp/service/relying-party/postconfig.xml       |  8 ++++--
 .../idp/plugin/oidc/op/conf/oidc.properties        |  7 ++++-
 .../AbstractOidcClientAuthenticationFlowTest.java  | 32 ++++++++++++++++++++--
 .../op/profile/flow/IntrospectionFlowTest.java     |  1 +
 .../oidc/op/profile/flow/RevocationFlowTest.java   |  2 +-
 5 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index 0356dd18..21976c0e 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -514,8 +514,10 @@
         class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
         p:claimName="sub" p:valueToMatchLookupStrategy-ref="AdaptedRelyingPartyIdLookup" />
 
-    <bean id="AudienceClaimsValidator"
-        class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator">
+    <bean id="DefaultAuthenticationAudienceClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.AuthenticationAudienceClaimsValidator"
+        p:endpointTargets="%{idp.oauth2.jwtAuth.audienceValidator.endpointTargets:/profile/oauth2/introspection,/profile/oauth2/revocation}"
+        p:endpointReplacement="/profile/oidc/token">
         <property name="audienceLookupStrategy">
             <bean parent="shibboleth.BiFunctions.Expression"
                 c:expression="#custom.getRequestURL().toString()"
@@ -534,7 +536,7 @@
         <ref bean="IssuedAtClaimsValidator" />
         <ref bean="IssuerClaimsValidator" />
         <ref bean="SubjectClaimsValidator" />
-        <ref bean="AudienceClaimsValidator" />
+        <ref bean="%{idp.oauth2.jwtAuth.audienceValidator:DefaultAuthenticationAudienceClaimsValidator}" />
         <ref bean="JWTIdentifierClaimsValidator" />
     </util:list>
 
diff --git a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
index 34df0fb0..2e131d9b 100644
--- a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
+++ b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
@@ -155,4 +155,9 @@ idp.oidc.subject.salt = this_too_should_be_ch4ng3d
 #idp.oauth2.enforceRefreshTokenRotation = true
 
 # Revocation method: set to TOKEN to revoke single tokens (defaults to full chain (value = CHAIN))
-#idp.oauth2.revocationMethod = TOKEN
\ No newline at end of file
+#idp.oauth2.revocationMethod = TOKEN
+
+# Bean used to validate audience claim in the JWT authentication.
+#idp.oauth2.jwtAuth.audienceValidator = DefaultAuthenticationAudienceClaimsValidator
+# The default pattern also accepts token endpoint URL as the audience in introspection and revocation endpoints.
+#idp.oauth2.jwtAuth.audienceValidator.endpointTargets = /profile/oauth2/introspection,/profile/oauth2/revocation
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcClientAuthenticationFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcClientAuthenticationFlowTest.java
index 2680a955..48177765 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcClientAuthenticationFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcClientAuthenticationFlowTest.java
@@ -28,6 +28,7 @@ import java.util.Map;
 
 import org.opensaml.profile.action.EventIds;
 import org.springframework.webflow.executor.FlowExecutionResult;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.nimbusds.jose.JOSEException;
@@ -58,10 +59,12 @@ public abstract class AbstractOidcClientAuthenticationFlowTest extends AbstractO
     String clientIdSaml = "mockSamlClientId";
     String clientSecretSaml = "mockClientSecretmockClientSecretmockClientSecret";
 
-    String jwtAud = "http://localhost";
+    String jwtAud;
+    String issuer = "https://op.example.org";
     
     public AbstractOidcClientAuthenticationFlowTest(final String flowId) {
         super(flowId);
+        jwtAud = "http://localhost/idp/profile/" + flowId;
     }
 
     protected void populateClientAssertionParams(final Map<String, String> requestParameters, 
@@ -69,6 +72,11 @@ public abstract class AbstractOidcClientAuthenticationFlowTest extends AbstractO
         requestParameters.put("client_assertion", jwt.serialize());
         requestParameters.put("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
     }
+    
+    @BeforeMethod
+    public void setupRequestURI() {
+        request.setRequestURI("/idp/profile/" + flowId);
+    }
 
     @Test
     public void testInvalidSecretJWT_missingSub() throws Exception {
@@ -152,6 +160,22 @@ public abstract class AbstractOidcClientAuthenticationFlowTest extends AbstractO
         assertErrorDescriptionContains(result, getErrorDetaisForJWTValidation().getSecond());
     }
 
+    @Test
+    public void testValidSecretJWTHS256_TokenEndpointAudience() throws Exception {
+        final SignedJWT jwt = createSecretJWT(validClaimsSet("http://localhost/idp/profile/oidc/token"), clientSecret, JWSAlgorithm.HS256);
+        final FlowExecutionResult result = launchWithJwtAuthentication(jwt, null,
+                ClientAuthenticationMethod.CLIENT_SECRET_JWT);
+        assertSuccessResponse(result);
+    }
+
+    @Test
+    public void testValidSecretJWTHS256_IssuerAudience() throws Exception {
+        final SignedJWT jwt = createSecretJWT(validClaimsSet(issuer), clientSecret, JWSAlgorithm.HS256);
+        final FlowExecutionResult result = launchWithJwtAuthentication(jwt, null,
+                ClientAuthenticationMethod.CLIENT_SECRET_JWT);
+        assertSuccessResponse(result);
+    }
+
     @Test
     public void testValidSecretJWTHS256_noRegisteredAlg() throws Exception {
         final SignedJWT jwt = createSecretJWT(validClaimsSet(), clientSecret, JWSAlgorithm.HS256);
@@ -591,10 +615,14 @@ public abstract class AbstractOidcClientAuthenticationFlowTest extends AbstractO
     }
 
     protected JWTClaimsSet validClaimsSet() {
+        return validClaimsSet(jwtAud);
+    }
+
+    protected JWTClaimsSet validClaimsSet(final String audience) {
         return new JWTClaimsSet.Builder()
                 .subject(clientId)
                 .issuer(clientId)
-                .audience(jwtAud)
+                .audience(audience)
                 .expirationTime(Date.from(Instant.now().plusSeconds(600)))
                 .jwtID(idGenerator.generateIdentifier())
                 .build();
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java
index 387c6d2e..442d7825 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java
@@ -439,6 +439,7 @@ public class IntrospectionFlowTest extends AbstractOidcClientAuthenticationFlowT
     protected void assertSuccessResponse(final FlowExecutionResult result) {
         final TokenIntrospectionSuccessResponse resp =
                 parseSuccessResponse(result, TokenIntrospectionSuccessResponse.class);
+        Assert.assertNotNull(resp);
         Assert.assertTrue(resp.isActive());
         Assert.assertEquals(resp.getClientID().getValue(), clientId);
         Assert.assertEquals(resp.getScope(), scope);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java
index 2d331456..84f0438c 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java
@@ -301,6 +301,6 @@ public class RevocationFlowTest extends AbstractOidcClientAuthenticationFlowTest
     }
 
     protected void assertSuccessResponse(final FlowExecutionResult result) {
-        parseSuccessResponse(result, OAuth2RevocationSuccessResponse.class);
+        Assert.assertNotNull(parseSuccessResponse(result, OAuth2RevocationSuccessResponse.class));
     }
 }
\ No newline at end of file

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


More information about the commits mailing list