[java-idp-oidc] branch main updated: JOIDC-199 - UserInfo JWT access token issued by the implicit authorize flow is not signed
Henri Mikkonen
henri.mikkonen at iki.fi
Wed Apr 3 16:13:33 UTC 2024
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=1d38d4321ea4761cb0a9c402a43f26a6a31a6426
The following commit(s) were added to refs/heads/main by this push:
new 1d38d432 JOIDC-199 - UserInfo JWT access token issued by the implicit authorize flow is not signed
1d38d432 is described below
commit 1d38d4321ea4761cb0a9c402a43f26a6a31a6426
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Wed Apr 3 19:13:12 2024 +0300
JOIDC-199 - UserInfo JWT access token issued by the implicit authorize flow is not signed
https://shibboleth.atlassian.net/browse/JOIDC-199
Updated the security configuration wiring for UserInfo JWT access tokens to exploit client
information in the same way as for ID token issuance.
Updated the issued JWT security tests to cover this access token too. Previously they already
covered the 3P JWT access tokens issued by the authorize endpoint.
---
.../idp/flows/oidc/authorize/authorize-beans.xml | 31 +++++++++----
.../flow/AbstractIssuedJWTSecurityTest.java | 54 +++++++++++++++++++++-
.../oidc/op/profile/flow/AuthorizeFlowTest.java | 3 +-
.../shibboleth/idp/module/conf/relying-party.xml | 2 +-
4 files changed, 79 insertions(+), 11 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
index e343b556..9be6caa6 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
@@ -546,21 +546,35 @@
<bean id="PopulateUserInfoAccessTokenSignatureSigningParameters"
class="net.shibboleth.oidc.profile.impl.PopulateJWTSignatureSigningParameters" scope="prototype"
- c:strategy-ref="shibboleth.MessageContextLookup.Outbound">
+ c:strategy-ref="shibboleth.MessageContextLookup.Inbound"
+ p:securityParametersContextLookupStrategy-ref="UserInfoAccessTokenSecurityParametersContextLookupStrategy">
<property name="configurationLookupStrategy">
<bean lazy-init="true"
class="net.shibboleth.oidc.profile.config.navigate.JWTSignatureSigningConfigurationLookupFunction" />
</property>
<property name="signatureSigningParametersResolver">
- <bean class="net.shibboleth.oidc.security.jose.impl.BasicSignatureSigningParametersResolver" />
- </property>
- <property name="securityParametersContextLookupStrategy">
- <bean parent="shibboleth.Functions.Compose"
- c:g-ref="shibboleth.oidc.ChildLookupOrCreate.JWTSecurityParameters"
- c:f-ref="shibboleth.ChildLookup.RelyingParty" />
+ <bean class="net.shibboleth.oidc.security.jose.impl.ClientInformationSignatureSigningParametersResolver">
+ <constructor-arg name="signatureAlgorithmLookupStrategy">
+ <bean
+ class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
+ c:keyName="id_token_signed_response_alg" />
+ </constructor-arg>
+ <constructor-arg name="defaultAlgorithmValue" value="RS256" />
+ </bean>
</property>
</bean>
+ <bean id="UserInfoAccessTokenSecurityParametersContextLookupStrategy" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.oidc.ChildLookupOrCreate.JWTSecurityParameters"
+ c:f-ref="shibboleth.ChildLookup.RelyingParty" />
+
+ <bean id="UserInfoAccessTokenSecurityParametersCreationViaMessageContextStrategy" parent="shibboleth.Functions.Compose">
+ <constructor-arg name="g" ref="UserInfoAccessTokenSecurityParametersContextLookupStrategy" />
+ <constructor-arg name="f">
+ <bean parent="shibboleth.Functions.Expression" c:expression="#input.getParent()" />
+ </constructor-arg>
+ </bean>
+
<bean id="BuildOIDCAccessToken"
class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildAccessToken" scope="prototype"
p:dataSealer="#{getObject('%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim())}"
@@ -578,6 +592,7 @@
<constructor-arg name="messageHandler">
<bean id="SignOIDCAccessTokenHandler"
class="net.shibboleth.oidc.security.impl.SignJWTHandler" scope="prototype" p:logName="Access Token"
+ p:securityParametersLookupStrategy-ref="UserInfoAccessTokenSecurityParametersCreationViaMessageContextStrategy"
p:typeHeader="at+jwt">
<property name="claimsToSignLookupStrategy">
<bean
@@ -952,4 +967,4 @@
</constructor-arg>
</bean>
-</beans>
+</beans>
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractIssuedJWTSecurityTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractIssuedJWTSecurityTest.java
index 04f54336..9767b4f8 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractIssuedJWTSecurityTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractIssuedJWTSecurityTest.java
@@ -101,7 +101,9 @@ public abstract class AbstractIssuedJWTSecurityTest extends AbstractOidcFlowTest
AUTHORIZE_ID_TOKEN,
AUTHORIZE_ACCESS_TOKEN,
-
+
+ AUTHORIZE_USER_INFO_ACCESS_TOKEN,
+
REQUEST_OBJECT,
ID_TOKEN_HINT,
@@ -160,6 +162,9 @@ public abstract class AbstractIssuedJWTSecurityTest extends AbstractOidcFlowTest
case AUTHORIZE_ACCESS_TOKEN:
return obtainAccessTokenFromAuthorizeEndpoint(clientId, clientSecret, publicKey, jwsAlgorithm,
jweAlgorithm, encryptionMethod);
+ case AUTHORIZE_USER_INFO_ACCESS_TOKEN:
+ return obtainUserInfoTokenFromAuthorizeEndpoint("mockClientIdJwtAccessToken", clientSecret, publicKey,
+ jwsAlgorithm, jweAlgorithm, encryptionMethod);
case LOGOUT_TOKEN:
return obtainLogoutToken(clientId, clientSecret, publicKey, jwsAlgorithm,
jweAlgorithm, encryptionMethod);
@@ -563,6 +568,53 @@ public abstract class AbstractIssuedJWTSecurityTest extends AbstractOidcFlowTest
return null;
}
+ protected JWT obtainUserInfoTokenFromAuthorizeEndpoint(final String clientId, final String clientSecret,
+ final PublicKey publicKey,final JWSAlgorithm storedJwsAlgorithm, final JWEAlgorithm storedJweAlgorithm,
+ final EncryptionMethod storedJweMethod) {
+ setBasicAuth("jdoe", "changeit");
+ request.setMethod("GET");
+ final String redirectUri = "https://example.org/cb";
+
+ AuthorizeFlowTest.setRequestParameters(request, List.of(new Pair<>("client_id", clientId),
+ new Pair<>("response_type", "id_token token"),
+ new Pair<>("scope", "openid profile"),
+ new Pair<>("redirect_uri", redirectUri),
+ new Pair<>("nonce", "idhas3h23hi13h1o2i32")));
+
+ final OIDCClientMetadata metadata = buildMetadataSkeleton();
+ metadata.setScope(Scope.parse("openid profile email offline_access"));
+ metadata.setResponseTypes(Set.of(ResponseType.IDTOKEN_TOKEN));
+ metadata.setIDTokenJWSAlg(storedJwsAlgorithm);
+
+ if (publicKey != null) {
+ metadata.setJWKSet(super.buildJWKSet(publicKey));
+ }
+
+ try {
+ metadata.setRedirectionURI(new URI(redirectUri));
+ super.storeMetadataObject(storageService, clientId, clientSecret, metadata);
+ } catch (final IOException | URISyntaxException e) {
+ Assert.fail(e.getMessage(), e);
+ }
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(flowId, null, externalContext);
+ try {
+ super.removeMetadata(storageService, clientId);
+ } catch (final IOException e) {
+ Assert.fail(e.getMessage(), e);
+ }
+ if (parseResponse(result).indicatesSuccess()) {
+ final AuthorizationResponse responseMessage = parseSuccessResponse(result, AuthorizationResponse.class);
+ final AuthorizationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getAccessToken());
+ return parseEncryptedOrSignedJWT(successResponse.getAccessToken().getValue());
+ }
+ return null;
+ }
+
protected JWT obtainLogoutToken(final String clientId, final String clientSecret,
final PublicKey publicKey,final JWSAlgorithm storedJwsAlgorithm, final JWEAlgorithm storedJweAlgorithm,
final EncryptionMethod storedJweMethod) {
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
index 63d618f6..ea8d57d5 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
@@ -99,7 +99,6 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
public void setup() {
setBasicAuth("jdoe", "changeit");
}
-
@Test
public void testWithAuthorizationCodeFlow() throws IOException, SessionException {
setRequestParameters(List.of(new Pair<>("client_id", "mockClientId"),
@@ -1764,6 +1763,8 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
return new Object[] {
new IssuedSignedJWTTest(AbstractIssuedJWTSecurityTest.JWT_FETCHING_TYPE.AUTHORIZE_ACCESS_TOKEN,
FLOW_ID),
+ new IssuedSignedJWTTest(AbstractIssuedJWTSecurityTest.JWT_FETCHING_TYPE.AUTHORIZE_USER_INFO_ACCESS_TOKEN,
+ FLOW_ID),
new IssuedEncryptedJWTTest(AbstractIssuedJWTSecurityTest.JWT_FETCHING_TYPE.AUTHORIZE_ACCESS_TOKEN,
FLOW_ID, true, false),
new IssuedEncryptedJWTTest(AbstractIssuedJWTSecurityTest.JWT_FETCHING_TYPE.AUTHORIZE_ACCESS_TOKEN,
diff --git a/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/module/conf/relying-party.xml b/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/module/conf/relying-party.xml
index cb096e57..0ffbe878 100644
--- a/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/module/conf/relying-party.xml
+++ b/idp-oidc-extension-impl/src/test/resources/net/shibboleth/idp/module/conf/relying-party.xml
@@ -218,7 +218,7 @@
<bean parent="RelyingPartyByName" c:relyingPartyIds="mockClientIdJwtAccessToken">
<property name="profileConfigurations">
<list>
- <bean parent="OIDC.SSO.MDDriven" />
+ <bean parent="OIDC.SSO.MDDriven" p:accessTokenType="JWT"/>
<bean parent="OAUTH2.Token.MDDriven" p:accessTokenType="JWT" p:encryptionOptional="true" />
</list>
</property>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list