[java-idp-oidc] branch main updated: JOIDC-71 Lack of openid scope in metadata doesn't prevent id_token issuance
Henri Mikkonen
henri.mikkonen at iki.fi
Tue Mar 1 12:38:36 UTC 2022
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=850be083fe513eb78755c7798079aa6068626cee
The following commit(s) were added to refs/heads/main by this push:
new 850be083 JOIDC-71 Lack of openid scope in metadata doesn't prevent id_token issuance
850be083 is described below
commit 850be083fe513eb78755c7798079aa6068626cee
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Mar 1 14:35:16 2022 +0200
JOIDC-71 Lack of openid scope in metadata doesn't prevent id_token issuance
https://shibboleth.atlassian.net/browse/JOIDC-71
Added activation condition to the actions dealing with id_token generation on the
token flow. id_token is now only returned if the validated scope (request verified
against scope in the metadata) contains 'openid'.
Also added flow tests to make sure that authorize-endpoint returns error if 'openid'
is not part of the requested scope. The Nimbus decoder requires the scope to exist,
as it's OIDC authentication request that is assumed. This should be refactored if
we want to support more generic OAuth2 authorization requests.
---
.../op/profile/logic/IssueIDTokenCondition.java | 70 +++++++++
.../idp/flows/oidc/token/token-beans.xml | 31 ++--
.../oidc/op/profile/flow/AbstractOidcFlowTest.java | 8 +-
.../oidc/op/profile/flow/AuthorizeFlowTest.java | 171 ++++++++++++++++++++-
.../plugin/oidc/op/profile/flow/TokenFlowTest.java | 22 ++-
.../oidc/op/profile/impl/ValidateGrantTest.java | 4 +-
6 files changed, 284 insertions(+), 22 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/IssueIDTokenCondition.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/IssueIDTokenCondition.java
new file mode 100644
index 00000000..3a42f922
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/IssueIDTokenCondition.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.profile.logic;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.openid.connect.sdk.OIDCScopeValue;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.ValidatedScopeLookupFunction;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Activation condition returning true if validated scope contains 'openid' scope.
+ */
+public class IssueIDTokenCondition implements Predicate<ProfileRequestContext> {
+
+ /** Lookup strategy for the validated scope. */
+ @Nonnull private Function<ProfileRequestContext, Scope> validatedScopeLookupStrategy;
+
+ /**
+ * Constructor.
+ */
+ public IssueIDTokenCondition() {
+ validatedScopeLookupStrategy = new ValidatedScopeLookupFunction();
+ }
+
+ /**
+ * Set the lookup strategy for the validated scope.
+ *
+ * @param strategy What to set.
+ */
+ public void setValidatedScopeLookupStrategy(final @Nonnull Function<ProfileRequestContext, Scope> strategy) {
+ validatedScopeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean test(final @Nullable ProfileRequestContext input) {
+ if (input == null) {
+ return false;
+ }
+ final Scope validatedScope = validatedScopeLookupStrategy.apply(input);
+ if (validatedScope == null || validatedScope.isEmpty()) {
+ return false;
+ }
+ return validatedScope.contains(OIDCScopeValue.OPENID);
+ }
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
index 26b35001..fc612f4e 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
@@ -173,6 +173,9 @@
<bean id="TokenRequestAudienceLookupStrategy"
class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestAudienceLookupFunction" />
+ <bean id="IssueIDTokenCondition"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.logic.IssueIDTokenCondition" />
+
<!--
Do a metadata lookup for the primary audience of the token for encryption purposes.
Contexts are stored under the outbound MessageContext, including the new RelyingPartyContext.
@@ -319,7 +322,8 @@
scope="prototype"
c:strategy-ref="shibboleth.MessageContextLookup.Inbound"
p:configurationLookupStrategy-ref="shibboleth.SignatureSigningConfigurationLookup"
- p:signatureSigningParametersResolver-ref="shibboleth.oidc.TokenSignatureSigningParametersResolver">
+ p:signatureSigningParametersResolver-ref="shibboleth.oidc.TokenSignatureSigningParametersResolver"
+ p:activationCondition-ref="IssueIDTokenCondition">
<property name="securityParametersContextLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookupOrCreate.SecurityParameters"
@@ -335,7 +339,8 @@
<bean id="PopulateIDTokenEncryptionParameters"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCEncryptionParameters" scope="prototype"
p:configurationLookupStrategy-ref="shibboleth.EncryptionConfigurationLookup"
- p:encryptionParametersResolver-ref="shibboleth.oidc.EncryptionParametersResolver" />
+ p:encryptionParametersResolver-ref="shibboleth.oidc.EncryptionParametersResolver"
+ p:activationCondition-ref="IssueIDTokenCondition" />
<bean id="shibboleth.oidc.EncryptionParametersResolver"
class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver"
@@ -351,32 +356,35 @@
c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}" />
<bean id="AddIDTokenShell" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddIDTokenShell"
- scope="prototype" />
+ scope="prototype" p:activationCondition-ref="IssueIDTokenCondition" />
<bean id="AddAttributeClaimsToIDToken"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAttributesToClaimsSet" scope="prototype"
p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
- p:reservedClaimNames="#{getObject('shibboleth.oidc.IDTokenReservedClaimNames') ?: getObject('shibboleth.oidc.DefaultIDTokenReservedClaimNames')}" />
+ p:reservedClaimNames="#{getObject('shibboleth.oidc.IDTokenReservedClaimNames') ?: getObject('shibboleth.oidc.DefaultIDTokenReservedClaimNames')}"
+ p:activationCondition-ref="IssueIDTokenCondition" />
<bean id="AddTokenDeliveryAttributesToIDToken"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddTokenDeliveryAttributesToClaimsSet" scope="prototype"
- p:targetIDToken="true" />
+ p:targetIDToken="true" p:activationCondition-ref="IssueIDTokenCondition" />
<bean id="AddAuthTimeToIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAuthTimeToIDToken"
- scope="prototype" />
+ scope="prototype" p:activationCondition-ref="IssueIDTokenCondition" />
<bean id="AddAcrToIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAcrToIDToken"
- scope="prototype" />
+ scope="prototype" p:activationCondition-ref="IssueIDTokenCondition" />
<bean id="AddNonceToIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddNonceToIDToken"
- scope="prototype" p:requestNonceLookupStrategy-ref="shibboleth.TokenRequestNonceLookupStrategy" />
+ scope="prototype" p:requestNonceLookupStrategy-ref="shibboleth.TokenRequestNonceLookupStrategy"
+ p:activationCondition-ref="IssueIDTokenCondition" />
<bean id="shibboleth.TokenRequestNonceLookupStrategy"
class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestNonceLookupFunction"
scope="prototype" />
<bean id="AddAccessTokenHashToIDToken"
- class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAccessTokenHashToIDToken" scope="prototype">
+ class="net.shibboleth.idp.plugin.oidc.op.profile.impl.AddAccessTokenHashToIDToken" scope="prototype"
+ p:activationCondition-ref="IssueIDTokenCondition">
<property name="securityParametersLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
@@ -384,7 +392,8 @@
</property>
</bean>
- <bean id="SignIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SignIDToken" scope="prototype">
+ <bean id="SignIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SignIDToken" scope="prototype"
+ p:activationCondition-ref="IssueIDTokenCondition">
<property name="securityParametersLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
@@ -393,7 +402,7 @@
</bean>
<bean id="EncryptIDToken" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.EncryptProcessedToken"
- scope="prototype" />
+ p:activationCondition-ref="IssueIDTokenCondition" scope="prototype" />
<bean id="FormOutboundMessage"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.FormOutboundTokenResponseMessage" scope="prototype" />
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
index 402f5de4..ed9a443c 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
@@ -136,7 +136,6 @@ public abstract class AbstractOidcFlowTest extends AbstractFlowTest {
protected void assertErrorDescriptionContains(final FlowExecutionResult result, final String errorDescription) {
final ErrorResponse errorResponse = parseErrorResponse(result);
Assert.assertNotNull(errorResponse.getErrorObject().getDescription());
- System.out.println("Error " + errorResponse.getErrorObject().getDescription());
Assert.assertTrue(errorResponse.getErrorObject().getDescription().contains(errorDescription));
}
@@ -211,6 +210,13 @@ public abstract class AbstractOidcFlowTest extends AbstractFlowTest {
}
final HashSet<ResponseType> responseTypes = new HashSet<>();
responseTypes.add(new ResponseType("code"));
+ // implicit flows
+ responseTypes.add(new ResponseType("id_token"));
+ responseTypes.add(new ResponseType("id_token", "token"));
+ // hybrid flows
+ responseTypes.add(new ResponseType("code", "id_token"));
+ responseTypes.add(new ResponseType("code", "token"));
+ responseTypes.add(new ResponseType("code", "id_token", "token"));
metadata.setResponseTypes(responseTypes);
metadata.setRedirectionURIs(uris);
metadata.setScope(scope);
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 5ab419ae..36b76eeb 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
@@ -86,7 +86,176 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
}
-
+
+ @Test
+ public void testWithAuthorizationCodeFlowNoOpenid() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code&scope=profile&redirect_uri="
+ + redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ }
+
+ @Test
+ public void testWithImplicitFlowNoNonce() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&redirect_uri="
+ + redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ }
+
+ @Test
+ public void testWithImplicitFlow() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=id_token&scope=openid%20profile&redirect_uri="
+ + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithImplicitTokenFlow() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
+ + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNotNull(successResponse.getAccessToken());
+ Assert.assertNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithImplicitTokenFlowNoNonce() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=id_token+token&scope=openid%20profile"
+ + "&redirect_uri="+ redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ }
+
+ @Test
+ public void testWithImplicitFlowNoOpenIdScope() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=id_token&scope=profile&redirect_uri="
+ + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ }
+
+ @Test
+ public void testWithHybridIdTokenFlow() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
+ + "&redirect_uri=" + redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithHybridIdTokenFlowNoNonce() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+id_token&scope=openid%20profile"
+ + "&redirect_uri=" + redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ }
+
+ @Test
+ public void testWithHybridTokenFlow() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+token&scope=openid%20profile"
+ + "&redirect_uri="+ redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ // success response as id_token is not involved and thus nonce is not required
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNull(successResponse.getIDToken());
+ Assert.assertNotNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithHybridIdTokenTokenFlow() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
+ + "&redirect_uri="+ redirectUri + "&nonce=idhas3h23hi13h1o2i32");
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNotNull(successResponse.getIDToken());
+ Assert.assertNotNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithHybridIdTokenTokenFlowNoNonce() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientId&response_type=code+id_token+token&scope=openid%20profile"
+ + "&redirect_uri="+ redirectUri);
+ storeMetadata(storageService, clientId, clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ Assert.assertEquals("ErrorView", result.getOutcome().getId());
+ }
+
@Test
public void testWithAuthorizationCodeFlowUnforcedPKCE() throws IOException, ParseException, SessionException {
request.setMethod("GET");
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
index 04f9be26..951f0840 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
@@ -35,6 +35,7 @@ import org.testng.annotations.Test;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
import com.nimbusds.oauth2.sdk.AuthorizationCode;
import com.nimbusds.oauth2.sdk.OAuth2Error;
import com.nimbusds.oauth2.sdk.Scope;
@@ -130,9 +131,6 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
@Test
public void testNoScopes() throws Exception {
- // TODO: This test should probably be failing. The absence of scopes should prevent an id_token from
- // being issued, but isn't. The sub claim is there via the authorization code even if it isn't
- // "released" by the filter policy.
setHttpFormRequest("POST",
createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientId), clientId));
@@ -140,9 +138,8 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
setBasicAuth(clientId, clientSecret);
storeConsent(storageService, "jdoe", clientId, "mail");
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final AccessTokenResponse response = parseSuccessResponse(result, AccessTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
- Assert.assertNotNull(response.getOIDCTokens().getIDToken());
}
protected void initializeGrantAndRequest(final String clientId, final Map<String, String> requestParameters)
@@ -269,6 +266,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
final FlowExecutionResult result = launchWithJwtAuthentication(clientAuth, JWSAlgorithm.HS256);
final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
+ Assert.assertNotNull(response.getOIDCTokens().getIDToken());
}
@Test
@@ -277,6 +275,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
final FlowExecutionResult result = launchWithJwtAuthentication(clientAuth, null);
final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
+ Assert.assertNotNull(response.getOIDCTokens().getIDToken());
}
@Test
@@ -465,15 +464,24 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
private String s256Verifier() {
return "S256" + CodeChallenge.compute(CodeChallengeMethod.S256, new CodeVerifier(codeVerifier)).getValue();
}
-
+
protected FlowExecutionResult launchWithJwtAuthentication(final JWTAuthentication authnMethod, final JWSAlgorithm algorithm)
throws Exception {
+ return launchWithJwtAuthentication(authnMethod, algorithm, null);
+ }
+
+ protected FlowExecutionResult launchWithJwtAuthentication(final JWTAuthentication authnMethod, final JWSAlgorithm algorithm,
+ final String requestedScope)
+ throws Exception {
final String code = ValidateGrantTest.buildAuthorizationCode(clientId, "https://op.example.org", "jdoe", "mock",
- redirectUri).toString();
+ redirectUri, scope.toString()).toString();
storeMetadata(storageService, clientId, clientSecret, scope, JWSAlgorithm.HS256,
ClientAuthenticationMethod.CLIENT_SECRET_JWT);
final Map<String, String> requestParameters =
createRequestParameters(redirectUri, "authorization_code", code, clientId);
+ if (requestedScope != null) {
+ requestParameters.put("scope", requestedScope);
+ }
populateClientAssertionParams(requestParameters, authnMethod);
setHttpFormRequest("POST", requestParameters);
return flowExecutor.launchExecution(FLOW_ID, null, externalContext);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java
index 57d8075f..e1959bdd 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrantTest.java
@@ -107,13 +107,13 @@ public class ValidateGrantTest extends BaseOIDCResponseActionTest {
static public AuthorizationCode buildAuthorizationCode(final String clientId, final String issuer,
final String userPrincipal, final String sub, final String callbackUrl, final String scope)
throws Exception {
- return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, null, null);
+ return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, null, scope);
}
static public AuthorizationCode buildAuthorizationCode(final String clientId, final String issuer,
final String userPrincipal, final String sub, final String callbackUrl, final String codeChallenge,
final String scope) throws Exception {
- return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, codeChallenge, null, null, null, null);
+ return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, codeChallenge, null, null, null, scope);
}
static public AuthorizationCode buildAuthorizationCode(final String clientId, final String issuer,
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list