[java-idp-oidc] branch main updated: JOIDC-11 - Support for client_credentials grant
Scott Cantor
cantor.2 at osu.edu
Tue Jan 4 22:56:56 UTC 2022
This is an automated email from the git hooks/post-receive script.
scantor 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=1764b5645bc3585650037203c99b55e8f1c1eb22
The following commit(s) were added to refs/heads/main by this push:
new 1764b564 JOIDC-11 - Support for client_credentials grant
1764b564 is described below
commit 1764b5645bc3585650037203c99b55e8f1c1eb22
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Jan 4 17:56:53 2022 -0500
JOIDC-11 - Support for client_credentials grant
https://shibboleth.atlassian.net/browse/JOIDC-11
Early flow changes to add grant_type and fix scope validation.
---
.../context/OIDCAuthenticationResponseContext.java | 45 +++++-
.../logic/RequestedGrantTypesCondition.java | 68 +++++++++
.../context/logic/package-info.java} | 22 +--
.../AbstractTokenClaimsLookupFunction.java | 3 +-
.../TokenRequestRedirectURILookupFunction.java | 2 +-
.../navigate/TokenRequestScopeLookupFunction.java | 21 +--
.../UserInfoRequestClientIDLookupFunction.java | 4 +-
.../OIDCAuthenticationResponseContextTest.java | 24 ++-
.../impl/SetAccessTokenToResponseContext.java | 6 +-
.../impl/SetRefreshTokenToResponseContext.java | 3 +-
.../plugin/oidc/op/profile/impl/ValidateGrant.java | 52 ++++---
.../plugin/oidc/op/profile/impl/ValidatePKCE.java | 23 +--
.../oidc/op/profile/impl/ValidateRedirectURI.java | 4 +-
.../plugin/oidc/op/profile/impl/ValidateScope.java | 60 ++++++--
...uteConsentEnabledInTokenClaimsSetPredicate.java | 7 +-
.../idp/flows/oidc/token/token-beans.xml | 36 +++--
.../idp/flows/oidc/userinfo/userinfo-beans.xml | 11 +-
.../plugin/oidc/op/profile/flow/TokenFlowTest.java | 166 +++++++++-----------
.../SetRequestedClaimsToResponseContextTest.java | 4 +-
.../oidc/op/profile/impl/ValidateGrantTest.java | 107 +++++++------
.../oidc/op/profile/impl/ValidateScopeTest.java | 168 +++++++++++++++++++--
.../plugin/oidc/op/profile/impl/package-info.java | 23 +--
22 files changed, 559 insertions(+), 300 deletions(-)
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java
index e7a7b12d..4657d71b 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContext.java
@@ -101,9 +101,9 @@ public class OIDCAuthenticationResponseContext extends BaseContext {
@Nullable
private RefreshToken refreshToken;
- /** Token (authz code, access token) claims. */
+ /** Authorization grant (authz code, access token) claims. */
@Nullable
- private TokenClaimsSet tokenClaims;
+ private TokenClaimsSet authorizationGrantClaims;
/** Requested claims. */
@Nullable
@@ -171,22 +171,55 @@ public class OIDCAuthenticationResponseContext extends BaseContext {
}
/**
- * Get token claims.
+ * Get the claims representing the authorization grant, which may be derived from an
+ * authorization code, refresh token, or assertion.
*
* @return token claims
*/
@Nullable
+ public TokenClaimsSet getAuthorizationGrantClaimsSet() {
+ return authorizationGrantClaims;
+ }
+
+ /**
+ * Set the claims representing the authorization grant, which may be derived from an
+ * authorization code, refresh token, or assertion.
+ *
+ * @param claims token claims
+ */
+ public void setAuthorizationGrantClaimsSet(@Nullable final TokenClaimsSet claims) {
+ authorizationGrantClaims = claims;
+ }
+
+ /**
+ * Get the claims representing the authorization grant, which may be derived from an
+ * authorization code, refresh token, or assertion.
+ *
+ * <p>Renamed to {@link #getAuthorizationGrantClaimsSet()}.</p>
+ *
+ * @return token claims
+ *
+ * @deprecated
+ */
+ @Deprecated(since="3.1.0", forRemoval=true)
+ @Nullable
public TokenClaimsSet getTokenClaimsSet() {
- return tokenClaims;
+ return authorizationGrantClaims;
}
/**
- * Set token claims.
+ * Set the claims representing the authorization grant, which may be derived from an
+ * authorization code, refresh token, or assertion.
+ *
+ * <p>Renamed to {@link #setAuthorizationGrantClaimsSet(TokenClaimsSet)}.</p>
*
* @param claims token claims
+ *
+ * @deprecated
*/
+ @Deprecated(since="3.1.0", forRemoval=true)
public void setTokenClaimsSet(@Nullable final TokenClaimsSet claims) {
- tokenClaims = claims;
+ authorizationGrantClaims = claims;
}
/**
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/logic/RequestedGrantTypesCondition.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/logic/RequestedGrantTypesCondition.java
new file mode 100644
index 00000000..c2c7686c
--- /dev/null
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/logic/RequestedGrantTypesCondition.java
@@ -0,0 +1,68 @@
+/*
+ * 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.messaging.context.logic;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.oauth2.sdk.GrantType;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+
+/**
+ * Checks whether a {@link TokenRequest} was for one of a set of candidate grant_type values.
+ */
+public class RequestedGrantTypesCondition implements Predicate<ProfileRequestContext> {
+
+ /** Candidate grant types. */
+ @Nonnull @NonnullElements private Set<GrantType> candidates;
+
+ /** Constructor. */
+ public RequestedGrantTypesCondition() {
+ candidates = Collections.emptySet();
+ }
+
+ /**
+ * Set the candidate grant_type values to check for.
+ *
+ * @param types candidate types
+ */
+ public void setGrantTypes(@Nonnull @NonnullElements final Collection<GrantType> types) {
+ candidates = Set.copyOf(types);
+ }
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final ProfileRequestContext input) {
+ if (input.getInboundMessageContext() != null) {
+ final Object message = input.getInboundMessageContext().getMessage();
+ if (message instanceof TokenRequest) {
+ return candidates.contains(((TokenRequest) message).getAuthorizationGrant().getType());
+ }
+ }
+
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/logic/package-info.java
similarity index 54%
copy from idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java
copy to idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/logic/package-info.java
index ec39a3cd..d2122a69 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/logic/package-info.java
@@ -15,26 +15,8 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.context.navigate;
-
-import javax.annotation.Nonnull;
-
-import com.nimbusds.oauth2.sdk.Scope;
-
-import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
-
/**
- * For Token and UserInfo end points.
- *
- * A function that returns copy of requested scope via a lookup function. This lookup locates scope from token for token
- * request handling. If token claims are not available, null is returned.
+ * Conditions related to OIDC messaging.
*/
-public class TokenRequestScopeLookupFunction extends AbstractTokenClaimsLookupFunction<Scope> {
-
- /** {@inheritDoc} */
- @Override
- Scope doLookup(@Nonnull final TokenClaimsSet tokenClaims) {
- return tokenClaims.getScope();
- }
-}
\ No newline at end of file
+package net.shibboleth.idp.plugin.oidc.op.messaging.context.logic;
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractTokenClaimsLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractTokenClaimsLookupFunction.java
index 57eac1b1..f74cc2e9 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractTokenClaimsLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/AbstractTokenClaimsLookupFunction.java
@@ -54,12 +54,11 @@ public abstract class AbstractTokenClaimsLookupFunction<T>
if (oidcResponseContext == null) {
return null;
}
- final TokenClaimsSet tokenClaims = oidcResponseContext.getTokenClaimsSet();
+ final TokenClaimsSet tokenClaims = oidcResponseContext.getAuthorizationGrantClaimsSet();
if (tokenClaims == null) {
return null;
}
return doLookup(tokenClaims);
-
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestRedirectURILookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestRedirectURILookupFunction.java
index 79b513d5..81f4ce6d 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestRedirectURILookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestRedirectURILookupFunction.java
@@ -57,7 +57,7 @@ public class TokenRequestRedirectURILookupFunction extends AbstractTokenRequestL
try {
uri = new URI(redirectURI);
} catch (final URISyntaxException e) {
- log.error("Unable to parse uri from token request redirect_uri {}", redirectURI);
+ log.warn("Unable to parse uri from token request redirect_uri {}", redirectURI);
}
return uri;
}
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java
index ec39a3cd..3192b6a7 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java
@@ -20,21 +20,24 @@ package net.shibboleth.idp.plugin.oidc.op.profile.context.navigate;
import javax.annotation.Nonnull;
import com.nimbusds.oauth2.sdk.Scope;
-
-import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
+import com.nimbusds.oauth2.sdk.TokenRequest;
/**
- * For Token and UserInfo end points.
- *
- * A function that returns copy of requested scope via a lookup function. This lookup locates scope from token for token
- * request handling. If token claims are not available, null is returned.
+ * A function that returns a copy of requested scopes from a {@link TokenRequest}.
*/
-public class TokenRequestScopeLookupFunction extends AbstractTokenClaimsLookupFunction<Scope> {
+public class TokenRequestScopeLookupFunction extends AbstractTokenRequestLookupFunction<Scope> {
/** {@inheritDoc} */
@Override
- Scope doLookup(@Nonnull final TokenClaimsSet tokenClaims) {
- return tokenClaims.getScope();
+ Scope doLookup(@Nonnull final TokenRequest req) {
+
+ if (req.getScope() != null) {
+ final Scope requestParameterScope = new Scope();
+ requestParameterScope.addAll(req.getScope());
+ return requestParameterScope;
+ }
+
+ return null;
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/UserInfoRequestClientIDLookupFunction.java b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/UserInfoRequestClientIDLookupFunction.java
index f156a030..64a0f7c6 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/UserInfoRequestClientIDLookupFunction.java
+++ b/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/UserInfoRequestClientIDLookupFunction.java
@@ -56,10 +56,10 @@ public class UserInfoRequestClientIDLookupFunction implements ContextDataLookupF
return null;
}
final OIDCAuthenticationResponseContext ctx = msgCtx.getSubcontext(OIDCAuthenticationResponseContext.class);
- if (ctx == null || ctx.getTokenClaimsSet() == null) {
+ if (ctx == null || ctx.getAuthorizationGrantClaimsSet() == null) {
return null;
}
- return ctx.getTokenClaimsSet().getClientID();
+ return ctx.getAuthorizationGrantClaimsSet().getClientID();
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContextTest.java b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContextTest.java
index f1733f3c..ac4572c3 100644
--- a/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContextTest.java
+++ b/idp-oidc-extension-api/src/test/java/net/shibboleth/idp/plugin/oidc/op/messaging/context/OIDCAuthenticationResponseContextTest.java
@@ -39,8 +39,6 @@ import com.nimbusds.openid.connect.sdk.OIDCClaimsRequest;
import com.nimbusds.openid.connect.sdk.claims.IDTokenClaimsSet;
import com.nimbusds.openid.connect.sdk.claims.UserInfo;
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
-
/** Tests for {@link OIDCAuthenticationResponseContext}.*/
public class OIDCAuthenticationResponseContextTest {
@@ -62,7 +60,7 @@ public class OIDCAuthenticationResponseContextTest {
Assert.assertNull(ctx.getScope());
Assert.assertNull(ctx.getProcessedToken());
Assert.assertNull(ctx.getRequestedClaims());
- Assert.assertNull(ctx.getTokenClaimsSet());
+ Assert.assertNull(ctx.getAuthorizationGrantClaimsSet());
Assert.assertNull(ctx.getAuthorizationCode());
Assert.assertNull(ctx.getAccessToken());
Assert.assertNull(ctx.getRefreshToken());
@@ -74,27 +72,27 @@ public class OIDCAuthenticationResponseContextTest {
public void testSetters() throws URISyntaxException, ParseException {
ctx.setAcr("acrValue");
ctx.setAuthTime(Instant.ofEpochMilli(1));
- Issuer issuer = new Issuer("iss");
- Subject sub = new Subject("sub");
- List<Audience> aud = new ArrayList<Audience>();
+ final Issuer issuer = new Issuer("iss");
+ final Subject sub = new Subject("sub");
+ final List<Audience> aud = new ArrayList<Audience>();
aud.add(new Audience("aud"));
- IDTokenClaimsSet token = new IDTokenClaimsSet(issuer, sub, aud, new Date(), new Date());
+ final IDTokenClaimsSet token = new IDTokenClaimsSet(issuer, sub, aud, new Date(), new Date());
ctx.setIDToken(token);
ctx.setSubject("sub");
- URI uri = new URI("https://example.org");
+ final URI uri = new URI("https://example.org");
ctx.setRedirectURI(uri);
ctx.setRequestedSubject("sub");
- Scope scope = new Scope();
+ final Scope scope = new Scope();
ctx.setScope(scope);
- JWSHeader header = new JWSHeader(JWSAlgorithm.ES256);
- SignedJWT sJWT = new SignedJWT(header, token.toJWTClaimsSet());
+ final JWSHeader header = new JWSHeader(JWSAlgorithm.ES256);
+ final SignedJWT sJWT = new SignedJWT(header, token.toJWTClaimsSet());
ctx.setProcessedToken(sJWT);
Assert.assertEquals(ctx.getAcr().toString(), "acrValue");
ctx.setAcr(null);
- OIDCClaimsRequest claims = new OIDCClaimsRequest();
+ final OIDCClaimsRequest claims = new OIDCClaimsRequest();
ctx.setRequestedClaims(claims);
ctx.setSubjectType("pairwise");
- UserInfo info = new UserInfo(sub);
+ final UserInfo info = new UserInfo(sub);
ctx.setUserInfo(info);
Assert.assertNull(ctx.getAcr());
Assert.assertEquals(ctx.getAuthTime(), Instant.ofEpochMilli(1));
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContext.java
index 463b33ad..807fea1f 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetAccessTokenToResponseContext.java
@@ -30,6 +30,7 @@ import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
@@ -270,8 +271,9 @@ public class SetAccessTokenToResponseContext extends AbstractOIDCResponseAction
final AccessTokenClaimsSet claimsSet;
if (tokenClaimsSet != null) {
// We may not use original claims as input for scope / delivery claims as they may have been reduced.
- claimsSet = new AccessTokenClaimsSet(tokenClaimsSet, getOidcResponseContext().getScope(), claims, claimsUI,
- Instant.now(), dateExp);
+ claimsSet = new AccessTokenClaimsSet(tokenClaimsSet,
+ getOidcResponseContext().getScope() != null ? getOidcResponseContext().getScope() : new Scope(),
+ claims, claimsUI, Instant.now(), dateExp);
} else {
final OIDCAuthenticationResponseConsentContext consentCtx =
consentContextLookupStrategy.apply(profileRequestContext);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContext.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContext.java
index ec02b216..52361944 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContext.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContext.java
@@ -98,7 +98,8 @@ public class SetRefreshTokenToResponseContext extends AbstractOIDCResponseAction
return false;
}
- if (!getOidcResponseContext().getScope().contains(OIDCScopeValue.OFFLINE_ACCESS)) {
+ if (getOidcResponseContext().getScope() == null ||
+ !getOidcResponseContext().getScope().contains(OIDCScopeValue.OFFLINE_ACCESS)) {
log.debug("{} No offline_access scope, nothing to do", getLogPrefix());
return false;
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java
index 2f372fb4..a2875afd 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java
@@ -53,10 +53,17 @@ import net.shibboleth.utilities.java.support.security.DataSealer;
import net.shibboleth.utilities.java.support.security.DataSealerException;
/**
- * Action that validates authorization code / refresh token is a valid one. Code is valid if it is successfully
- * unwrapped, parsed as authz code/ refresh token , is not expired, is issued for the client and has not been used
- * before (authz code) or authz code used to produce it has not been revoked (refresh token). Validated code is stored
- * to response context retrievable as claims {@link OIDCAuthenticationResponseContext#getTokenClaimsSet()}.
+ * Action that validates an authorization grant.
+ *
+ * <p>A grant is valid if it is successfully unwrapped, parsed as a code or refresh token, is unexpired, was issued
+ * to the expected client and has not been used before (authz code) or the authz code used to produce it has not been
+ * revoked (refresh token).</p>
+ *
+ * <p> The validated claims from the grant are stored to response context via
+ * {@link OIDCAuthenticationResponseContext#getAuthorizationGrantClaimsSet()}.</p>
+ *
+ * <p>Note that the addition of support for the "client_credentials" grant type means that there may not in fact be a
+ * grant, or resulting claims set.</p>
*/
public class ValidateGrant extends AbstractOIDCTokenResponseAction {
@@ -153,38 +160,40 @@ public class ValidateGrant extends AbstractOIDCTokenResponseAction {
return true;
}
- // Checkstyle: CyclomaticComplexity OFF
-
+// Checkstyle: CyclomaticComplexity|MethodLength OFF
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final AuthorizationGrant grant = getTokenRequest().getAuthorizationGrant();
+
+ log.debug("{} Validating grant type: {}", getLogPrefix(),grant.getType());
+
TokenClaimsSet tokenClaimsSet = null;
- if (grant.getType().equals(GrantType.AUTHORIZATION_CODE)) {
+ if (GrantType.AUTHORIZATION_CODE.equals(grant.getType())) {
final AuthorizationCodeGrant codeGrant = (AuthorizationCodeGrant) grant;
if (codeGrant.getAuthorizationCode() != null && codeGrant.getAuthorizationCode().getValue() != null) {
try {
final AuthorizeCodeClaimsSet authzCodeClaimsSet =
AuthorizeCodeClaimsSet.parse(codeGrant.getAuthorizationCode().getValue(), dataSealer);
- log.debug("{} authz code unwrapped {}", getLogPrefix(), authzCodeClaimsSet.serialize());
+ log.debug("{} Authz code unwrapped {}", getLogPrefix(), authzCodeClaimsSet.serialize());
if (!replayCache.check(getClass().getName(), authzCodeClaimsSet.getID(),
authzCodeClaimsSet.getExp())) {
log.error("{} Replay detected of authz code {}", getLogPrefix(), authzCodeClaimsSet.getID());
if (!revocationCache.revoke(RevocationCacheContexts.AUTHORIZATION_CODE,
authzCodeClaimsSet.getID())) {
- log.error("{} Fatal error! Unable to set entry to revocation cache", getLogPrefix());
+ log.warn("{} Fatal error, unable to set entry to revocation cache", getLogPrefix());
}
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
return;
}
tokenClaimsSet = authzCodeClaimsSet;
} catch (final DataSealerException | ParseException e) {
- log.error("{} Obtaining authz code failed {}", getLogPrefix(), e.getMessage());
+ log.warn("{} Obtaining authz code failed {}", getLogPrefix(), e.getMessage());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
return;
}
}
- } else if (grant.getType().equals(GrantType.REFRESH_TOKEN)) {
+ } else if (GrantType.REFRESH_TOKEN.equals(grant.getType())) {
final RefreshTokenGrant refreshTokentokenGrant = (RefreshTokenGrant) grant;
if (refreshTokentokenGrant.getRefreshToken() != null
&& refreshTokentokenGrant.getRefreshToken().getValue() != null) {
@@ -193,37 +202,40 @@ public class ValidateGrant extends AbstractOIDCTokenResponseAction {
.parse(refreshTokentokenGrant.getRefreshToken().getValue(), dataSealer);
if (revocationCache.isRevoked(RevocationCacheContexts.AUTHORIZATION_CODE,
refreshTokenClaimsSet.getID())) {
- log.error("{} authorize code {} and all derived tokens have been revoked", getLogPrefix(),
+ log.error("{} Authz code {} and all derived tokens have been revoked", getLogPrefix(),
refreshTokenClaimsSet.getID());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
return;
}
tokenClaimsSet = refreshTokenClaimsSet;
} catch (final ParseException | DataSealerException e) {
- log.error("{} Obtaining refresh token failed {}", getLogPrefix(), e.getMessage());
+ log.warn("{} Obtaining refresh token failed {}", getLogPrefix(), e.getMessage());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
return;
}
}
+ } else if (GrantType.CLIENT_CREDENTIALS.equals(grant.getType())) {
+ return;
}
+
if (tokenClaimsSet == null) {
- log.error("{} Grant type not supported", getLogPrefix());
+ log.warn("{} Grant type not supported", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
return;
}
if (tokenClaimsSet.isExpired()) {
- log.error("{} token exp is in the past {}", getLogPrefix(), tokenClaimsSet.getExp());
+ log.warn("{} token exp is in the past {}", getLogPrefix(), tokenClaimsSet.getExp());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
return;
}
if (!tokenClaimsSet.getClientID().getValue().equals(rpCtx.getRelyingPartyId())) {
- log.error("{} token issued for client {}, expected value was {}", getLogPrefix(),
+ log.warn("{} token issued for client {}, expected value was {}", getLogPrefix(),
tokenClaimsSet.getClientID().getValue(), rpCtx.getRelyingPartyId());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
return;
}
- getOidcResponseContext().setTokenClaimsSet(tokenClaimsSet);
+ getOidcResponseContext().setAuthorizationGrantClaimsSet(tokenClaimsSet);
}
-
- // Checkstyle: CyclomaticComplexity ON
-}
+// Checkstyle: CyclomaticComplexity|MethodLength ON
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidatePKCE.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidatePKCE.java
index 8a65d32f..b80e2e6e 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidatePKCE.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidatePKCE.java
@@ -124,12 +124,13 @@ public class ValidatePKCE extends AbstractOIDCResponseAction {
if (!super.doPreExecute(profileRequestContext)) {
return false;
}
- if (getOidcResponseContext().getTokenClaimsSet() == null) {
- log.error("{} No validated token claims set available, missing a prior action", getLogPrefix());
+ if (getOidcResponseContext().getAuthorizationGrantClaimsSet() == null) {
+ log.warn("{} No validated authorization grant claims set available", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
return false;
}
- if (!AuthorizeCodeClaimsSet.VALUE_TYPE_AC.equals(getOidcResponseContext().getTokenClaimsSet().getType())) {
+ if (!AuthorizeCodeClaimsSet.VALUE_TYPE_AC.equals(
+ getOidcResponseContext().getAuthorizationGrantClaimsSet().getType())) {
log.debug("{} No authorization code presented, PKCE not applied, nothing to do", getLogPrefix());
return false;
}
@@ -137,7 +138,7 @@ public class ValidatePKCE extends AbstractOIDCResponseAction {
forcePKCE = forcePKCECondition.test(profileRequestContext);
plainPKCE = allowPKCEPlainCondition.test(profileRequestContext);
- codeChallenge = getOidcResponseContext().getTokenClaimsSet().getCodeChallenge();
+ codeChallenge = getOidcResponseContext().getAuthorizationGrantClaimsSet().getCodeChallenge();
// Checks whether PKCE needs to be validated.
if ((codeChallenge == null || codeChallenge.isEmpty()) && !forcePKCE) {
log.debug("{} No PKCE code challenge in request, nothing to do", getLogPrefix());
@@ -153,26 +154,26 @@ public class ValidatePKCE extends AbstractOIDCResponseAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
if (codeChallenge == null || codeChallenge.isEmpty()) {
// To save one action we have this late verification of the authentication request for PKCE parameter.
- log.error(
+ log.warn(
"{} No PKCE code challenge presented in authentication request" +
" even though required to access token endpoint", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
return;
}
if (codeVerifier == null || codeVerifier.isEmpty()) {
- log.error("{} No PKCE code verifier for code challenge presented in token request", getLogPrefix());
+ log.warn("{} No PKCE code verifier for code challenge presented in token request", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
return;
}
if (codeChallenge.startsWith("plain")) {
if (!plainPKCE) {
- log.error("{} Plain PKCE code challenge method not allowed", getLogPrefix());
+ log.warn("{} Plain PKCE code challenge method not allowed", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
return;
}
final String codeChallengeValue = codeChallenge.substring("plain".length());
if (!codeVerifier.equals(codeChallengeValue)) {
- log.error("{} PKCE code challenge {} not matching code verifier {}", getLogPrefix(), codeChallengeValue,
+ log.warn("{} PKCE code challenge {} not matching code verifier {}", getLogPrefix(), codeChallengeValue,
codeVerifier);
ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_AUTHN_ERROR);
return;
@@ -183,7 +184,7 @@ public class ValidatePKCE extends AbstractOIDCResponseAction {
try {
md = MessageDigest.getInstance("SHA-256");
} catch (final NoSuchAlgorithmException e) {
- log.error("{} PKCE S256 code challenge verification requires SHA-256", getLogPrefix(),
+ log.warn("{} PKCE S256 code challenge verification requires SHA-256", getLogPrefix(),
codeChallengeValue, codeVerifier);
ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_AUTHN_ERROR);
return;
@@ -191,13 +192,13 @@ public class ValidatePKCE extends AbstractOIDCResponseAction {
final byte[] hash = md.digest(codeVerifier.getBytes(Charset.forName("utf-8")));
final String codeChallengeComparisonValue = Base64URL.encode(hash).toString();
if (!codeChallengeComparisonValue.equals(codeChallengeValue)) {
- log.error("{} PKCE code challenge {} not matching code verifier {}({})", getLogPrefix(),
+ log.warn("{} PKCE code challenge {} not matching code verifier {}({})", getLogPrefix(),
codeChallengeValue, codeVerifier, codeChallengeComparisonValue);
ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_AUTHN_ERROR);
return;
}
} else {
- log.error("{} Unknown code challenge method", getLogPrefix());
+ log.warn("{} Unknown code challenge method", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
return;
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURI.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURI.java
index 1009c1c6..b0dcb075 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURI.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRedirectURI.java
@@ -83,14 +83,14 @@ public class ValidateRedirectURI extends AbstractOIDCAuthenticationResponseActio
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final URI requestRedirectURI = redirectURILookupStrategy.apply(profileRequestContext);
if (requestRedirectURI == null) {
- log.error("{} Redirection URI of the request not located for verification", getLogPrefix());
+ log.warn("{} Redirection URI of the request not located for verification", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_REDIRECT_URI);
return;
}
final Set<URI> redirectionURIs = validRedirectURIsLookupStrategy.apply(profileRequestContext);
if (redirectionURIs == null || redirectionURIs.isEmpty()) {
- log.error("{} Client has not registered Redirection URIs. Redirection URI cannot be validated.",
+ log.warn("{} Client has not registered Redirection URIs. Redirection URI cannot be validated.",
getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_REDIRECT_URI);
return;
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScope.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScope.java
index 85164721..f22098d4 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScope.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScope.java
@@ -21,6 +21,7 @@ import java.util.Iterator;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
@@ -33,11 +34,16 @@ import com.nimbusds.openid.connect.sdk.OIDCScopeValue;
import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestResponseTypeLookupFunction;
import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestedScopeLookupFunction;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * Action that validates requested scopes are registered ones. Validated scopes are stored to response context.
- * Offline_access scope is ignored in authentication endpoint validation unless response type contains code.
+ * Action that validates requested scopes are registered ones and stores the resulting set in the
+ * response context.
+ *
+ * <p>Explicitly requested scopes are also filtered against, and override, any scopes previously
+ * validated as part of an authorization grant claim set.</p>
+ *
+ * <p>The "offline_access" scope is ignored in authentication endpoint validation unless the
+ * response type includes "code".</p>
*/
public class ValidateScope extends AbstractOIDCAuthenticationResponseAction {
@@ -45,43 +51,68 @@ public class ValidateScope extends AbstractOIDCAuthenticationResponseAction {
@Nonnull private Logger log = LoggerFactory.getLogger(ValidateScope.class);
/** Strategy used to obtain the requested scope value. */
- @Nonnull private Function<ProfileRequestContext, Scope> scopeLookupStrategy;
-
+ @Nullable private Function<ProfileRequestContext,Scope> requestedScopesLookupStrategy;
+
/**
* Constructor.
*/
public ValidateScope() {
- scopeLookupStrategy = new DefaultRequestedScopeLookupFunction();
+ requestedScopesLookupStrategy = new DefaultRequestedScopeLookupFunction();
}
/**
- * Set the strategy used to locate the requested scope to use.
+ * Set the strategy used to locate the requested scope to validate.
*
* @param strategy lookup strategy
*/
- public void setScopeLookupStrategy(@Nonnull final Function<ProfileRequestContext, Scope> strategy) {
+ public void setScopeLookupStrategy(@Nullable final Function<ProfileRequestContext, Scope> strategy) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- scopeLookupStrategy = Constraint.isNotNull(strategy, "ScopeLookupStrategy lookup strategy cannot be null");
+
+ requestedScopesLookupStrategy = strategy;
}
+// Checkstyle: CyclomaticComplexity OFF
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ // These come from client metadata.
final Scope registeredScopes = getMetadataContext().getClientInformation().getMetadata().getScope();
if (registeredScopes == null || registeredScopes.isEmpty()) {
log.debug("{} No registered scopes for client {}, nothing to do", getLogPrefix(),
getMetadataContext().getClientInformation().getID());
return;
}
- final Scope requestedScopes = scopeLookupStrategy.apply(profileRequestContext);
+
+ // These come from a previous authorization grant (authz code or refresh token).
+ Scope previouslyGrantedScopes = null;
+ if (getOidcResponseContext().getAuthorizationGrantClaimsSet() != null) {
+ previouslyGrantedScopes = getOidcResponseContext().getAuthorizationGrantClaimsSet().getScope();
+ }
+
+ // These come from a request object or parameter. Absent by definition on the UserInfo endpoint.
+ Scope requestedScopes = requestedScopesLookupStrategy != null ?
+ requestedScopesLookupStrategy.apply(profileRequestContext) : null;
+ if (requestedScopes == null) {
+ // With none requested, simply swap requested for previously granted, if any.
+ // Set previous set to null since there's no need to filter against it.
+ requestedScopes = previouslyGrantedScopes;
+ previouslyGrantedScopes = null;
+ }
+
for (Iterator<Scope.Value> i = requestedScopes.iterator(); i.hasNext();) {
final Scope.Value scope = i.next();
if (!registeredScopes.contains(scope)) {
- log.warn("{} removing requested scope {} for rp {} as it is not a registered one", getLogPrefix(),
+ log.warn("{} Removing requested but unregistered scope {} for RP {}", getLogPrefix(),
+ scope.getValue(), getMetadataContext().getClientInformation().getID());
+ i.remove();
+ } else if (previouslyGrantedScopes != null && !previouslyGrantedScopes.contains(scope)) {
+ log.warn("{} Removing requested but previously ungranted scope {} for RP {}", getLogPrefix(),
scope.getValue(), getMetadataContext().getClientInformation().getID());
i.remove();
}
}
+
if (requestedScopes.contains(OIDCScopeValue.OFFLINE_ACCESS)) {
// DefaultRequestResponseTypeLookupFunction returns response type only in authentication end point.
// It is enough to remove offline_scope in this first validation turn.
@@ -91,6 +122,11 @@ public class ValidateScope extends AbstractOIDCAuthenticationResponseAction {
requestedScopes.remove(OIDCScopeValue.OFFLINE_ACCESS);
}
}
- getOidcResponseContext().setScope(requestedScopes);
+
+ if (!requestedScopes.isEmpty()) {
+ getOidcResponseContext().setScope(requestedScopes);
+ }
}
+// Checkstyle: CyclomaticComplexity ON
+
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/AttributeConsentEnabledInTokenClaimsSetPredicate.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/AttributeConsentEnabledInTokenClaimsSetPredicate.java
index c2fe1e2c..9b8172b6 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/AttributeConsentEnabledInTokenClaimsSetPredicate.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/AttributeConsentEnabledInTokenClaimsSetPredicate.java
@@ -28,7 +28,8 @@ import net.shibboleth.idp.profile.logic.AbstractRelyingPartyPredicate;
/**
* A predicate implementation that checks if attribute consent flag is enabled. The value is fetched from
- * {@link TokenClaimsSet#isConsentEnabled()} via #{@link OIDCAuthenticationResponseContext#getTokenClaimsSet()}
+ * {@link TokenClaimsSet#isConsentEnabled()} via
+ * {@link OIDCAuthenticationResponseContext#getAuthorizationGrantClaimsSet()}
* under outbound message context. Default value is false, if any of the objects in the chain is null.
*/
public class AttributeConsentEnabledInTokenClaimsSetPredicate extends AbstractRelyingPartyPredicate {
@@ -39,8 +40,8 @@ public class AttributeConsentEnabledInTokenClaimsSetPredicate extends AbstractRe
if (outboundMessageCtx != null) {
final OIDCAuthenticationResponseContext oidcResponseContext =
outboundMessageCtx.getSubcontext(OIDCAuthenticationResponseContext.class, false);
- if (oidcResponseContext != null && oidcResponseContext.getTokenClaimsSet() != null) {
- return oidcResponseContext.getTokenClaimsSet().isConsentEnabled();
+ if (oidcResponseContext != null && oidcResponseContext.getAuthorizationGrantClaimsSet() != null) {
+ return oidcResponseContext.getAuthorizationGrantClaimsSet().isConsentEnabled();
}
}
return false;
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 daa7c646..33dac13a 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
@@ -35,17 +35,29 @@
c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
p:replayCache-ref="shibboleth.ReplayCache"
p:revocationCache-ref="shibboleth.RevocationCache" />
-
- <bean id="ValidatePKCE" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidatePKCE" scope="prototype" />
- <bean id="ValidateRedirectURI" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateRedirectURI"
- scope="prototype" p:redirectURILookupStrategy-ref="shibboleth.TokenRequestRedirectURILookupStrategy"
- p:validRedirectURIsLookupStrategy-ref="shibboleth.TokenRequestValidRequestUrisLookupStrategy">
- <property name="activationCondition">
- <ref bean="GrantTypeAuthorizationCode" />
- </property>
+ <!-- Condition signaling that request was NOT for client_credentials grant. -->
+ <bean id="NotClientCredentialsGrantCondition" parent="shibboleth.Conditions.NOT">
+ <constructor-arg>
+ <bean class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.RequestedGrantTypesCondition"
+ p:grantTypes="T(com.nimbusds.oauth2.sdk.GrantType).CLIENT_CREDENTIALS" />
+ </constructor-arg>
</bean>
+ <!-- Condition signaling that request was for authorizaton_code grant. -->
+ <bean id="AuthorizationCodeGrantCondition"
+ class="net.shibboleth.idp.plugin.oidc.op.messaging.context.logic.RequestedGrantTypesCondition"
+ p:grantTypes="T(com.nimbusds.oauth2.sdk.GrantType).AUTHORIZATION_CODE" />
+
+ <bean id="ValidatePKCE" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidatePKCE" scope="prototype"
+ p:activationCondition-ref="NotClientCredentialsGrantCondition" />
+
+ <bean id="ValidateRedirectURI" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateRedirectURI"
+ scope="prototype"
+ p:activationCondition-ref="AuthorizationCodeGrantCondition"
+ p:redirectURILookupStrategy-ref="shibboleth.TokenRequestRedirectURILookupStrategy"
+ p:validRedirectURIsLookupStrategy-ref="shibboleth.TokenRequestValidRequestUrisLookupStrategy" />
+
<bean id="shibboleth.TokenRequestRedirectURILookupStrategy"
class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestRedirectURILookupFunction"
scope="prototype" />
@@ -188,14 +200,6 @@
</property>
</bean>
- <bean id="GrantTypeAuthorizationCode" parent="shibboleth.Conditions.Expression">
- <constructor-arg>
- <value>
- #profileContext.getInboundMessageContext().getMessage().getAuthorizationGrant().getType().equals(T(com.nimbusds.oauth2.sdk.GrantType).AUTHORIZATION_CODE)
- </value>
- </constructor-arg>
- </bean>
-
<bean id="PopulateTokenEndpointJwtSignatureValidationParameters"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.PopulateOIDCSignatureSigningParameters " scope="prototype"
p:configurationLookupStrategy-ref="shibboleth.oidc.SignatureValidationConfigurationLookup"
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
index 758b42b2..f64a95f5 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
@@ -34,13 +34,12 @@
class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.UserInfoRequestClientIDLookupFunction"
scope="prototype" />
- <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope" scope="prototype"
- p:scopeLookupStrategy-ref="shibboleth.TokenRequestScopeLookupStrategy" />
+ <bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope" scope="prototype">
+ <property name="scopeLookupStrategy">
+ <null/>
+ </property>
+ </bean>
- <bean id="shibboleth.TokenRequestScopeLookupStrategy"
- class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestScopeLookupFunction"
- scope="prototype" />
-
<bean id="SetRequestedClaimsToResponseContext"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.SetRequestedClaimsToResponseContext" scope="prototype"
p:requestedClaimsLookupStrategy-ref="shibboleth.TokenRequestRequestedClaimsLookupFunction"
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 6e0f61fb..677ff1dd 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
@@ -18,7 +18,6 @@
package net.shibboleth.idp.plugin.oidc.op.profile.flow;
import java.io.IOException;
-import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.time.Instant;
@@ -33,7 +32,6 @@ import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
-import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.SignedJWT;
@@ -43,8 +41,6 @@ import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
import com.nimbusds.oauth2.sdk.auth.ClientSecretJWT;
import com.nimbusds.oauth2.sdk.auth.JWTAuthentication;
-import com.nimbusds.oauth2.sdk.auth.Secret;
-import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.pkce.CodeChallenge;
import com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod;
import com.nimbusds.oauth2.sdk.pkce.CodeVerifier;
@@ -130,33 +126,30 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
assertErrorCode(result, OAuth2Error.INVALID_GRANT_CODE);
}
- protected void initializeGrantAndRequest(String clientId, Map<String, String> requestParameters)
- throws NoSuchAlgorithmException, URISyntaxException, DataSealerException, ComponentInitializationException,
- IOException {
+ protected void initializeGrantAndRequest(final String clientId, final Map<String, String> requestParameters)
+ throws IOException {
setHttpFormRequest("POST", requestParameters);
storeMetadata(storageService, clientId, clientSecret);
setBasicAuth(clientId, clientSecret);
}
@Test
- public void testValidGrant() throws ParseException, IOException, NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException {
+ public void testValidGrant() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientId), clientId));
storeConsent(storageService, "jdoe", clientId, "mail");
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
}
@Test
- public void testValidLegacyGrant() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidLegacyGrant() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildLegacyAuthorizationCode(clientId), clientId));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
final AccessToken accessToken = response.getTokens().getAccessToken();
Assert.assertNotNull(accessToken);
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
@@ -164,21 +157,19 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidLegacyConsentGrant() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidLegacyConsentGrant() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildLegacyAuthorizationCode(clientId, "mail"), clientId));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
final AccessToken accessToken = response.getTokens().getAccessToken();
Assert.assertNotNull(accessToken);
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
validateConsentFromAccessToken(response, true);
}
- protected void validateConsentFromAccessToken(final OIDCTokenResponse response, final boolean value) throws
- NoSuchAlgorithmException, DataSealerException, ComponentInitializationException,
- ParseException {
+ protected void validateConsentFromAccessToken(final OIDCTokenResponse response, final boolean value)
+ throws Exception {
final AccessTokenClaimsSet claims = unwrapAccessToken(response);
Assert.assertTrue(claims.getClaimsSet().getClaims().containsKey(TokenClaimsSet.KEY_CONSENT_ENABLED));
Assert.assertEquals(claims.getClaimsSet().getBooleanClaim(TokenClaimsSet.KEY_CONSENT_ENABLED).booleanValue(),
@@ -187,14 +178,13 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantSaml() throws ParseException, IOException, NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException, java.text.ParseException {
+ public void testValidGrantSaml() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdSaml), clientIdSaml));
setBasicAuth(clientIdSaml, clientSecretSaml);
storeConsent(storageService, "jdoe", clientIdSaml, "mail");
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
// the email-claim exists in id_token as it's defined to be always included in the SAML metadata
final JWT idToken = response.getOIDCTokens().getIDToken();
@@ -202,34 +192,32 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
Assert.assertEquals(idToken.getJWTClaimsSet().getClaim("email"), "jdoe at example.org");
}
- protected String buildAuthorizationCode(String clientId) throws NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException {
+ protected String buildAuthorizationCode(final String clientId) throws Exception {
return buildAuthorizationCode(clientId, null);
}
- protected String buildAuthorizationCode(String clientId, String verifier) throws NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ protected String buildAuthorizationCode(final String clientId, final String verifier) throws Exception {
return buildAuthorizationCode(clientId, verifier, null, null, null);
}
- protected String buildAuthorizationCode(String clientId, String verifier, JSONObject deliveryClaims,
- JSONObject deliveryClaimsIDToken, JSONObject deliveryClaimsUserInfo) throws NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ protected String buildAuthorizationCode(final String clientId, final String verifier,
+ final JSONObject deliveryClaims, final JSONObject deliveryClaimsIDToken,
+ final JSONObject deliveryClaimsUserInfo) throws Exception {
return ValidateGrantTest.buildAuthorizationCode(clientId, "https://op.example.org", "jdoe", "mock",
redirectUri, verifier, deliveryClaims, deliveryClaimsIDToken, deliveryClaimsUserInfo,
"openid profile email").toString();
}
- protected String buildLegacyAuthorizationCode(String clientId, String... consentedClaims) throws
- NoSuchAlgorithmException, URISyntaxException, DataSealerException, ComponentInitializationException {
+ protected String buildLegacyAuthorizationCode(final String clientId, final String... consentedClaims)
+ throws Exception {
final String json = buildJsonForLegacyToken("jdoe", clientId, Scope.parse("openid email"), "ac",
consentedClaims);
return new AuthorizationCode(BaseOIDCResponseActionTest.initializeDataSealer().wrap(json,
Instant.now().plusSeconds(30))).getValue();
}
- protected String buildLegacyRefreshToken(String clientId, String... consentedClaims) throws
- NoSuchAlgorithmException, URISyntaxException, DataSealerException, ComponentInitializationException {
+ protected String buildLegacyRefreshToken(final String clientId, final String... consentedClaims)
+ throws Exception {
final String json = buildJsonForLegacyToken("jdoe", clientId, Scope.parse("openid email"), "rf",
consentedClaims);
return new RefreshToken(BaseOIDCResponseActionTest.initializeDataSealer().wrap(json,
@@ -237,26 +225,23 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidSecretJWT() throws ParseException, IOException, NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException, JOSEException {
- ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret);
+ public void testValidSecretJWT() throws Exception {
+ final ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret);
final FlowExecutionResult result = launchWithJwtAuthentication(clientAuth, JWSAlgorithm.HS256);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
}
@Test
- public void testValidSecretJWTNoAlg() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException, JOSEException {
- ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret);
+ public void testValidSecretJWTNoAlg() throws Exception {
+ final ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret);
final FlowExecutionResult result = launchWithJwtAuthentication(clientAuth, null);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
}
@Test
- public void testValidGrantValidRequestMissingPlainPKCE() throws ParseException, IOException,
- NoSuchAlgorithmException, URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantValidRequestMissingPlainPKCE() throws Exception {
initializeGrantAndRequest(clientIdPkcePlain, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkcePlain, plainVerifier()), clientIdPkcePlain));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -265,8 +250,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantInvalidUnforcedPlainPKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantInvalidUnforcedPlainPKCE() throws Exception {
initializeGrantAndRequest(clientIdPkcePlainUnforced, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkcePlainUnforced, plainVerifier()), clientIdPkcePlainUnforced, null,
null, codeVerifier + "invalid"));
@@ -276,8 +260,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantInvalidPlainPKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantInvalidPlainPKCE() throws Exception {
initializeGrantAndRequest(clientIdPkcePlain, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkcePlain, plainVerifier()), clientIdPkcePlain, null, null,
codeVerifier + "invalid"));
@@ -287,30 +270,27 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantValidPlainPKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantValidPlainPKCE() throws Exception {
initializeGrantAndRequest(clientIdPkcePlain, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkcePlain, plainVerifier()), clientIdPkcePlain, null, null,
codeVerifier));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
}
@Test
- public void testValidGrantValidUnforcedPlainPKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantValidUnforcedPlainPKCE() throws Exception {
initializeGrantAndRequest(clientIdPkcePlainUnforced, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkcePlainUnforced, plainVerifier()), clientIdPkcePlainUnforced, null,
null, codeVerifier));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
}
@Test
- public void testValidGrantValidRequestMissingS256PKCE() throws ParseException, IOException,
- NoSuchAlgorithmException, URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantValidRequestMissingS256PKCE() throws Exception {
initializeGrantAndRequest(clientIdPkceS256, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkceS256, s256Verifier()), clientIdPkceS256));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -319,8 +299,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantInvalidUnforcedS256PKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantInvalidUnforcedS256PKCE() throws Exception {
initializeGrantAndRequest(clientIdPkcePlainUnforced, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkcePlainUnforced, s256Verifier()), clientIdPkcePlainUnforced, null,
"S256", codeVerifier + "invalid"));
@@ -330,8 +309,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantInvalidS256PKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantInvalidS256PKCE() throws Exception {
initializeGrantAndRequest(clientIdPkceS256, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkceS256, s256Verifier()), clientIdPkceS256, null, "S256",
codeVerifier + "invalid"));
@@ -341,37 +319,33 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantValidS256PKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantValidS256PKCE() throws Exception {
initializeGrantAndRequest(clientIdPkceS256, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientIdPkceS256, s256Verifier()), clientIdPkceS256, null, "S256",
codeVerifier));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
}
@Test
- public void testValidGrantValidUnforcedS256PKCE() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidGrantValidUnforcedS256PKCE() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientId, s256Verifier()), clientId, null, "S256", codeVerifier));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
Assert.assertNotNull(response.getTokens().getAccessToken());
}
@Test
- public void testInvalidSecretJWT() throws ParseException, IOException, NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException, JOSEException {
- ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret + "invalid");
+ public void testInvalidSecretJWT() throws Exception {
+ final ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret + "invalid");
final FlowExecutionResult result = launchWithJwtAuthentication(clientAuth, JWSAlgorithm.HS256);
assertErrorCode(result, OAuth2Error.INVALID_CLIENT_CODE);
}
@Test
- public void testValidGrantWrappedClaimsUI() throws NoSuchAlgorithmException, URISyntaxException,
- DataSealerException, ComponentInitializationException, IOException {
+ public void testValidGrantWrappedClaimsUI() throws Exception {
final String claimName = "name";
final String claimValue = "John Doe";
final JSONObject claimsUI = new JSONObject();
@@ -379,7 +353,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientId, null, null, null, claimsUI), clientId));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
final AccessTokenClaimsSet claimsSet = unwrapAccessToken(response);
Assert.assertNotNull(claimsSet);
final ClaimsSet dlClaimsSet = claimsSet.getUserinfoDeliveryClaims();
@@ -390,8 +364,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidGrantWrappedClaims() throws NoSuchAlgorithmException, URISyntaxException, DataSealerException,
- ComponentInitializationException, IOException {
+ public void testValidGrantWrappedClaims() throws Exception {
final String claimName = "name";
final String claimValue = "John Doe";
final JSONObject claims = new JSONObject();
@@ -399,7 +372,7 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
buildAuthorizationCode(clientId, null, claims, null, null), clientId));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
final AccessTokenClaimsSet claimsSet = unwrapAccessToken(response);
Assert.assertNotNull(claimsSet);
final ClaimsSet dlClaimsSet = claimsSet.getDeliveryClaims();
@@ -410,12 +383,11 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidLegacyRefreshTokenGrant() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidLegacyRefreshTokenGrant() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "refresh_token",
buildLegacyRefreshToken(clientId), clientId));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
final AccessToken accessToken = response.getTokens().getAccessToken();
Assert.assertNotNull(accessToken);
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
@@ -423,12 +395,11 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
@Test
- public void testValidLegacyConsentRefreshTokenGrant() throws ParseException, IOException, NoSuchAlgorithmException,
- URISyntaxException, DataSealerException, ComponentInitializationException {
+ public void testValidLegacyConsentRefreshTokenGrant() throws Exception {
initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "refresh_token",
buildLegacyRefreshToken(clientId, "mail"), clientId));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
- OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+ final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
final AccessToken accessToken = response.getTokens().getAccessToken();
Assert.assertNotNull(accessToken);
Assert.assertNotNull(response.getOIDCTokens().getIDToken());
@@ -448,7 +419,8 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
private String plainVerifier() {
- return "plain" + CodeChallenge.compute(CodeChallengeMethod.PLAIN, new CodeVerifier(codeVerifier)).getValue();
+ return "plain" + CodeChallenge.compute(
+ CodeChallengeMethod.PLAIN, new CodeVerifier(codeVerifier)).getValue();
}
private String s256Verifier() {
@@ -456,38 +428,37 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
}
protected FlowExecutionResult launchWithJwtAuthentication(final JWTAuthentication authnMethod, final JWSAlgorithm algorithm)
- throws NoSuchAlgorithmException, URISyntaxException, DataSealerException, ComponentInitializationException,
- IOException {
- String code = ValidateGrantTest.buildAuthorizationCode(clientId, "https://op.example.org", "jdoe", "mock",
+ throws Exception {
+ final String code = ValidateGrantTest.buildAuthorizationCode(clientId, "https://op.example.org", "jdoe", "mock",
redirectUri).toString();
storeMetadata(storageService, clientId, clientSecret, JWSAlgorithm.HS256,
ClientAuthenticationMethod.CLIENT_SECRET_JWT);
- Map<String, String> requestParameters = createRequestParameters(redirectUri, "authorization_code", code, clientId);
+ final Map<String, String> requestParameters =
+ createRequestParameters(redirectUri, "authorization_code", code, clientId);
populateClientAssertionParams(requestParameters, authnMethod);
setHttpFormRequest("POST", requestParameters);
return flowExecutor.launchExecution(FLOW_ID, null, externalContext);
}
protected FlowExecutionResult launchWithJwtAuthentication(final SignedJWT jwt, final JWSAlgorithm algorithm,
- final ClientAuthenticationMethod method)
- throws NoSuchAlgorithmException, URISyntaxException, DataSealerException, ComponentInitializationException,
- IOException {
- String code = ValidateGrantTest.buildAuthorizationCode(clientId, "https://op.example.org", "jdoe", "mock",
+ final ClientAuthenticationMethod method) throws Exception {
+ final String code = ValidateGrantTest.buildAuthorizationCode(clientId, "https://op.example.org", "jdoe", "mock",
redirectUri).toString();
if (ClientAuthenticationMethod.CLIENT_SECRET_JWT.equals(method)) {
storeMetadata(storageService, clientId, clientSecret, algorithm, method);
} else {
storeMetadata(storageService, clientId, null, algorithm, method, null, rsaPublicKey);
}
- Map<String, String> requestParameters = createRequestParameters(redirectUri, "authorization_code", code, clientId);
+ final Map<String, String> requestParameters =
+ createRequestParameters(redirectUri, "authorization_code", code, clientId);
populateClientAssertionParams(requestParameters, jwt);
setHttpFormRequest("POST", requestParameters);
return flowExecutor.launchExecution(FLOW_ID, null, externalContext);
}
- protected Map<String, String> createRequestParameters(String redirectUri, String grantType, String code,
- String clientId) {
- Map<String, String> parameters = new HashMap<>();
+ protected Map<String, String> createRequestParameters(final String redirectUri, final String grantType,
+ final String code, final String clientId) {
+ final Map<String, String> parameters = new HashMap<>();
addNonNullValue(parameters, "redirect_uri", redirectUri);
addNonNullValue(parameters, "grant_type", grantType);
if ("refresh_token".equals(grantType)) {
@@ -499,16 +470,17 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
return parameters;
}
- protected Map<String, String> createRequestParameters(String redirectUri, String grantType, String code,
- String clientId, String codeChallenge, String codeChallengeMethod, String codeVerifier) {
- Map<String, String> parameters = createRequestParameters(redirectUri, grantType, code, clientId);
+ protected Map<String, String> createRequestParameters(final String redirectUri, final String grantType,
+ final String code, final String clientId, final String codeChallenge, final String codeChallengeMethod,
+ final String codeVerifier) {
+ final Map<String, String> parameters = createRequestParameters(redirectUri, grantType, code, clientId);
addNonNullValue(parameters, "code_challenge", codeChallenge);
addNonNullValue(parameters, "code_challenge_method", codeChallengeMethod);
addNonNullValue(parameters, "code_verifier", codeVerifier);
return parameters;
}
- private void addNonNullValue(Map<String, String> map, String key, String value) {
+ private void addNonNullValue(final Map<String, String> map, final String key, final String value) {
if (value != null) {
map.put(key, value);
}
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestedClaimsToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestedClaimsToResponseContextTest.java
index 84dfbfa2..f13e29aa 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestedClaimsToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRequestedClaimsToResponseContextTest.java
@@ -56,7 +56,7 @@ public class SetRequestedClaimsToResponseContextTest extends BaseOIDCResponseAct
new Scope()).setACR(new ACR("0")).setClaims(OIDCClaimsRequest.parse("{\"id_token\":{\"email\":{\"essential\":true}},\"userinfo\":{\"name\":{\"essential\":true}}}")).build();
respCtx.setSubject("subject");
respCtx.setAuthTime(Instant.now());
- respCtx.setTokenClaimsSet(claims);
+ respCtx.setAuthorizationGrantClaimsSet(claims);
respCtx.setAcr("0");
respCtx.setRedirectURI(new URI("http://example.com"));
action = new SetRequestedClaimsToResponseContext();
@@ -72,7 +72,7 @@ public class SetRequestedClaimsToResponseContextTest extends BaseOIDCResponseAct
init();
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
- final JSONObject claims = (JSONObject) respCtx.getTokenClaimsSet().getClaimsSet().getClaim("claims");
+ final JSONObject claims = (JSONObject) respCtx.getAuthorizationGrantClaimsSet().getClaimsSet().getClaim("claims");
Assert.assertTrue(isEssential(claims, "id_token", "email"));
Assert.assertTrue(isEssential(claims, "userinfo", "name"));
}
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 6c997f42..d2fd0c96 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
@@ -18,31 +18,33 @@
package net.shibboleth.idp.plugin.oidc.op.profile.impl;
import net.minidev.json.JSONObject;
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
import net.shibboleth.idp.plugin.oidc.op.profile.OidcEventIds;
-import net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateGrant;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.token.support.RefreshTokenClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
-import net.shibboleth.utilities.java.support.security.DataSealerException;
import net.shibboleth.utilities.java.support.security.impl.SecureRandomIdentifierGenerationStrategy;
import java.net.URI;
-import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import org.opensaml.storage.ReplayCache;
import org.opensaml.storage.impl.MemoryStorageService;
+import org.testng.Assert;
import org.testng.annotations.Test;
import com.nimbusds.oauth2.sdk.AuthorizationCode;
import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
import com.nimbusds.oauth2.sdk.RefreshTokenGrant;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.Secret;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.token.RefreshToken;
import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
@@ -62,8 +64,7 @@ public class ValidateGrantTest extends BaseOIDCResponseActionTest {
URI callback;
- private void init()
- throws ComponentInitializationException, NoSuchAlgorithmException, URISyntaxException, DataSealerException {
+ private void init() throws Exception {
final Instant now = Instant.now();
acClaims =
new AuthorizeCodeClaimsSet.Builder(idGenerator, new ClientID(clientId), "issuer", "userPrin", "subject",
@@ -88,28 +89,27 @@ public class ValidateGrantTest extends BaseOIDCResponseActionTest {
action.initialize();
}
- public static AuthorizationCode buildAuthorizationCode(String clientId, String issuer, String userPrincipal,
- String sub, String callbackUrl)
- throws URISyntaxException, NoSuchAlgorithmException, DataSealerException, ComponentInitializationException {
+ static public AuthorizationCode buildAuthorizationCode(final String clientId, final String issuer,
+ final String userPrincipal, final String sub, final String callbackUrl) throws Exception {
return buildAuthorizationCode(clientId, issuer, userPrincipal, sub, callbackUrl, null);
}
- public static AuthorizationCode buildAuthorizationCode(String clientId, String issuer, String userPrincipal,
- String sub, String callbackUrl, String scope)
- throws URISyntaxException, NoSuchAlgorithmException, DataSealerException, ComponentInitializationException {
+ 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);
}
- public static AuthorizationCode buildAuthorizationCode(String clientId, String issuer, String userPrincipal,
- String sub, String callbackUrl, String codeChallenge, String scope)
- throws URISyntaxException, NoSuchAlgorithmException, DataSealerException, ComponentInitializationException {
+ 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);
}
- public static AuthorizationCode buildAuthorizationCode(String clientId, String issuer, String userPrincipal,
- String sub, String callbackUrl, String codeChallenge, JSONObject deliveryClaims,
- JSONObject deliveryClaimsIDToken, JSONObject deliveryClaimsUserInfo, String scope)
- throws URISyntaxException, NoSuchAlgorithmException, DataSealerException, ComponentInitializationException {
+ static public AuthorizationCode buildAuthorizationCode(final String clientId, final String issuer,
+ final String userPrincipal, final String sub, final String callbackUrl, final String codeChallenge,
+ final JSONObject deliveryClaims, final JSONObject deliveryClaimsIDToken,
+ final JSONObject deliveryClaimsUserInfo, final String scope) throws Exception {
final Instant now = Instant.now();
final ValidateGrantTest test = new ValidateGrantTest();
final AuthorizeCodeClaimsSet.Builder builder = new AuthorizeCodeClaimsSet.Builder(
@@ -131,77 +131,100 @@ public class ValidateGrantTest extends BaseOIDCResponseActionTest {
return new AuthorizationCode(acClaims.serialize(test.getDataSealer()));
}
-
@Test
- public void testAuthorizeCodeSuccess()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException, DataSealerException {
+ public void testAuthorizeCodeSuccess() throws Exception {
init();
ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
+ final OIDCAuthenticationResponseContext arc =
+ profileRequestCtx.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class);
+ Assert.assertNotNull(arc.getAuthorizationGrantClaimsSet());
}
@Test
- public void testAuthorizeCodeReplayed()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException, DataSealerException {
+ public void testAuthorizeCodeReplayed() throws Exception {
init();
ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
ActionTestingSupport.assertEvent(action.execute(requestCtx), OidcEventIds.INVALID_GRANT);
}
@Test
- public void testRefreshTokenSuccess()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException, DataSealerException {
+ public void testRefreshTokenSuccess() throws Exception {
init();
- TokenRequest req = new TokenRequest(callback, new ClientID(clientId), rfGrant);
+ final TokenRequest req = new TokenRequest(callback, new ClientID(clientId), rfGrant);
profileRequestCtx.getInboundMessageContext().setMessage(req);
ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
+ final OIDCAuthenticationResponseContext arc =
+ profileRequestCtx.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class);
+ Assert.assertNotNull(arc.getAuthorizationGrantClaimsSet());
}
@Test
- public void testRefreshTokenReplayed()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException, DataSealerException {
+ public void testRefreshTokenReplayed() throws Exception {
init();
- TokenRequest req = new TokenRequest(callback, new ClientID(clientId), rfGrant);
+ final TokenRequest req = new TokenRequest(callback, new ClientID(clientId), rfGrant);
profileRequestCtx.getInboundMessageContext().setMessage(req);
ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
+ final OIDCAuthenticationResponseContext arc =
+ profileRequestCtx.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class);
+ Assert.assertNotNull(arc.getAuthorizationGrantClaimsSet());
}
@Test
- public void testMixGrant()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException, DataSealerException {
+ public void testMixGrant() throws Exception {
init();
- TokenRequest req = new TokenRequest(callback, new ClientID(clientId),
+ final TokenRequest req = new TokenRequest(callback, new ClientID(clientId),
new RefreshTokenGrant(new RefreshToken(acClaims.serialize(getDataSealer()))));
profileRequestCtx.getInboundMessageContext().setMessage(req);
ActionTestingSupport.assertEvent(action.execute(requestCtx), OidcEventIds.INVALID_GRANT);
+ final OIDCAuthenticationResponseContext arc =
+ profileRequestCtx.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class);
+ Assert.assertNull(arc.getAuthorizationGrantClaimsSet());
}
@Test
- public void testWrongClient()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException, DataSealerException {
+ public void testWrongClient() throws Exception {
init();
- AuthorizationCode code =
+ final AuthorizationCode code =
buildAuthorizationCode("clientIdWrong", "issuer", "userPrin", "subject", "http://example.com");
- TokenRequest req =
+ final TokenRequest req =
new TokenRequest(callback, new ClientID(clientId), new AuthorizationCodeGrant(code, callback));
profileRequestCtx.getInboundMessageContext().setMessage(req);
ActionTestingSupport.assertEvent(action.execute(requestCtx), OidcEventIds.INVALID_GRANT);
+ final OIDCAuthenticationResponseContext arc =
+ profileRequestCtx.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class);
+ Assert.assertNull(arc.getAuthorizationGrantClaimsSet());
}
@Test
- public void testExpired()
- throws NoSuchAlgorithmException, ComponentInitializationException, URISyntaxException, DataSealerException {
+ public void testExpired() throws Exception {
init();
final Instant now = Instant.now();
rfClaims = new RefreshTokenClaimsSet(acClaims, now, now.minusMillis(10));
- TokenRequest req = new TokenRequest(callback, new ClientID(clientId),
+ final TokenRequest req = new TokenRequest(callback, new ClientID(clientId),
new RefreshTokenGrant(new RefreshToken(rfClaims.serialize(getDataSealer()))));
profileRequestCtx.getInboundMessageContext().setMessage(req);
ActionTestingSupport.assertEvent(action.execute(requestCtx), OidcEventIds.INVALID_GRANT);
+ final OIDCAuthenticationResponseContext arc =
+ profileRequestCtx.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class);
+ Assert.assertNull(arc.getAuthorizationGrantClaimsSet());
}
+ @Test
+ public void testClientCredentialsSuccess() throws Exception {
+ init();
+ final TokenRequest req = new TokenRequest(callback,
+ new ClientSecretBasic(new ClientID(clientId), new Secret("foo")),
+ new ClientCredentialsGrant());
+ profileRequestCtx.getInboundMessageContext().setMessage(req);
+ ActionTestingSupport.assertProceedEvent(action.execute(requestCtx));
+ final OIDCAuthenticationResponseContext arc =
+ profileRequestCtx.getOutboundMessageContext().getSubcontext(OIDCAuthenticationResponseContext.class);
+ Assert.assertNull(arc.getAuthorizationGrantClaimsSet());
+ }
+
@Test(expectedExceptions = ComponentInitializationException.class)
- public void testNoRevocationCache() throws NoSuchAlgorithmException, ComponentInitializationException {
+ public void testNoRevocationCache() throws ComponentInitializationException, NoSuchAlgorithmException {
action = new ValidateGrant(getDataSealer());
final ReplayCache replayCache = new ReplayCache();
final MemoryStorageService storageService = new MemoryStorageService();
@@ -213,14 +236,14 @@ public class ValidateGrantTest extends BaseOIDCResponseActionTest {
}
@Test(expectedExceptions = ComponentInitializationException.class)
- public void testNoReplayCache() throws NoSuchAlgorithmException, ComponentInitializationException {
+ public void testNoReplayCache() throws ComponentInitializationException, NoSuchAlgorithmException {
action = new ValidateGrant(getDataSealer());
action.setRevocationCache(new MockRevocationCache(false, true));
action.initialize();
}
@Test(expectedExceptions = ConstraintViolationException.class)
- public void testNoDataSealer() throws NoSuchAlgorithmException, ComponentInitializationException {
+ public void testNoDataSealer() {
action = new ValidateGrant(null);
}
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScopeTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScopeTest.java
index 374a6a00..0ab3d4e3 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScopeTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateScopeTest.java
@@ -19,9 +19,12 @@ package net.shibboleth.idp.plugin.oidc.op.profile.impl;
import java.net.URI;
import java.net.URISyntaxException;
+import java.time.Instant;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCMetadataContext;
-import net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope;
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestScopeLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
+import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -29,61 +32,202 @@ import org.springframework.webflow.execution.Event;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+
+import com.nimbusds.oauth2.sdk.AuthorizationCode;
+import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
import com.nimbusds.oauth2.sdk.Scope;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
+import com.nimbusds.oauth2.sdk.auth.Secret;
+import com.nimbusds.oauth2.sdk.http.HTTPRequest.Method;
import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
import com.nimbusds.openid.connect.sdk.OIDCScopeValue;
+import com.nimbusds.openid.connect.sdk.UserInfoRequest;
+import com.nimbusds.openid.connect.sdk.claims.ACR;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
/** {@link ValidateScope} unit test. */
public class ValidateScopeTest extends BaseOIDCResponseActionTest {
+ /** Action to test. */
private ValidateScope action;
+ /** Client metadata. */
private OIDCClientMetadata metaData;
@BeforeMethod
private void init() throws ComponentInitializationException, URISyntaxException {
action = new ValidateScope();
action.initialize();
- OIDCMetadataContext oidcCtx =
+ final OIDCMetadataContext oidcCtx =
profileRequestCtx.getInboundMessageContext().getSubcontext(OIDCMetadataContext.class, true);
metaData = new OIDCClientMetadata();
- Scope scope = new Scope();
+ final Scope scope = new Scope();
scope.add(OIDCScopeValue.OPENID);
scope.add(OIDCScopeValue.EMAIL);
scope.add(OIDCScopeValue.OFFLINE_ACCESS);
metaData.setScope(scope);
metaData.setRedirectionURI(new URI("https://notmatching.org"));
- OIDCClientInformation information =
+ final OIDCClientInformation information =
new OIDCClientInformation(new ClientID("test"), null, metaData, null, null, null);
oidcCtx.setClientInformation(information);
}
/**
- * Test that action filters our non valid scopes.
+ * Test that action filters out non valid scopes on front-channel.
+ *
+ * @throws ComponentInitializationException
*/
@Test
- public void testSuccess() throws ComponentInitializationException {
+ public void testAuthnSuccess() throws ComponentInitializationException {
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
// input is openid, profile, offline_access and email. profile and offline_access should be filtered out
// (offline because the request is implicit).
Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.OPENID));
Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.EMAIL));
- Assert.assertTrue(!respCtx.getScope().contains(OIDCScopeValue.OFFLINE_ACCESS));
- Assert.assertTrue(!respCtx.getScope().contains(OIDCScopeValue.PROFILE));
+ Assert.assertFalse(respCtx.getScope().contains(OIDCScopeValue.OFFLINE_ACCESS));
+ Assert.assertFalse(respCtx.getScope().contains(OIDCScopeValue.PROFILE));
}
- /**
- * Test that action copes if there are no registered scopes.
- */
+ /**
+ * Test that action copes if there are no registered scopes.
+ *
+ * @throws ComponentInitializationException
+ */
@Test
- public void testSuccessNoScopes() throws ComponentInitializationException {
+ public void testAuthnNoScopes() throws ComponentInitializationException {
metaData.setScope(null);
final Event event = action.execute(requestCtx);
ActionTestingSupport.assertProceedEvent(event);
Assert.assertNull(respCtx.getScope());
}
+ /**
+ * Test that action filters out unregistered scopes on back-channel with no prior grant.
+ *
+ * @throws ComponentInitializationException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void testTokenClientCredentials() throws ComponentInitializationException, URISyntaxException {
+
+ action = new ValidateScope();
+ action.setScopeLookupStrategy(new TokenRequestScopeLookupFunction());
+ action.initialize();
+
+ final TokenRequest req = new TokenRequest(new URI("http://localhost"),
+ new ClientSecretBasic(new ClientID("s6BhdRkqt3"), new Secret("foo")),
+ new ClientCredentialsGrant(),
+ Scope.parse("openid email profile offline_access"));
+ setTokenRequest(req);
+
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ // input is openid, profile, offline_access and email. profile should be filtered out.
+ Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.OPENID));
+ Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.EMAIL));
+ Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.OFFLINE_ACCESS));
+ Assert.assertFalse(respCtx.getScope().contains(OIDCScopeValue.PROFILE));
+ }
+
+ /**
+ * Test that action filters out unregistered scopes on back-channel with prior grant of nothing.
+ *
+ * @throws ComponentInitializationException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void testTokenNoGrantedScopes() throws ComponentInitializationException, URISyntaxException {
+
+ action = new ValidateScope();
+ action.setScopeLookupStrategy(new TokenRequestScopeLookupFunction());
+ action.initialize();
+
+ final TokenRequest req = new TokenRequest(new URI("http://localhost"),
+ new ClientSecretBasic(new ClientID("s6BhdRkqt3"), new Secret("foo")),
+ new AuthorizationCodeGrant(new AuthorizationCode("foo"), new URI("http://localhost")),
+ Scope.parse("openid email profile offline_access"));
+ setTokenRequest(req);
+
+ final TokenClaimsSet claims =
+ new AuthorizeCodeClaimsSet.Builder(idGenerator, new ClientID("s6BhdRkqt3"), "issuer", "userPrin",
+ "subject", Instant.now(), Instant.now(), Instant.now(), new URI("http://localhost"),
+ new Scope()).setACR(new ACR("0")).build();
+ respCtx.setAuthorizationGrantClaimsSet(claims);
+
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ Assert.assertNull(respCtx.getScope());
+ }
+
+ /**
+ * Test that action filters out unregistered scopes on back-channel with prior grants.
+ *
+ * @throws ComponentInitializationException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void testTokenGrantedScopes() throws ComponentInitializationException, URISyntaxException {
+
+ action = new ValidateScope();
+ action.setScopeLookupStrategy(new TokenRequestScopeLookupFunction());
+ action.initialize();
+
+ final TokenRequest req = new TokenRequest(new URI("http://localhost"),
+ new ClientSecretBasic(new ClientID("s6BhdRkqt3"), new Secret("foo")),
+ new AuthorizationCodeGrant(new AuthorizationCode("foo"), new URI("http://localhost")),
+ Scope.parse("openid email profile offline_access"));
+ setTokenRequest(req);
+
+ final TokenClaimsSet claims =
+ new AuthorizeCodeClaimsSet.Builder(idGenerator, new ClientID("s6BhdRkqt3"), "issuer", "userPrin",
+ "subject", Instant.now(), Instant.now(), Instant.now(), new URI("http://localhost"),
+ Scope.parse("openid email")).setACR(new ACR("0")).build();
+ respCtx.setAuthorizationGrantClaimsSet(claims);
+
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ // input is openid, profile, offline_access and email. profile should be filtered out.
+ Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.OPENID));
+ Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.EMAIL));
+ Assert.assertFalse(respCtx.getScope().contains(OIDCScopeValue.OFFLINE_ACCESS));
+ Assert.assertFalse(respCtx.getScope().contains(OIDCScopeValue.PROFILE));
+ }
+
+ /**
+ * Test that action filters out unregistered scopes on UserInfo with prior grants.
+ *
+ * @throws ComponentInitializationException
+ * @throws URISyntaxException
+ */
+ @Test
+ public void testUserInfoGrantedScopes() throws ComponentInitializationException, URISyntaxException {
+
+ action = new ValidateScope();
+ action.setScopeLookupStrategy(null);
+ action.initialize();
+
+ final UserInfoRequest req =
+ new UserInfoRequest(new URI("http://localhost"), Method.POST, new BearerAccessToken());
+ setUserInfoRequest(req);
+
+ final TokenClaimsSet claims =
+ new AuthorizeCodeClaimsSet.Builder(idGenerator, new ClientID("s6BhdRkqt3"), "issuer", "userPrin",
+ "subject", Instant.now(), Instant.now(), Instant.now(), new URI("http://localhost"),
+ Scope.parse("openid email")).setACR(new ACR("0")).build();
+ respCtx.setAuthorizationGrantClaimsSet(claims);
+
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ // input is openid, profile, offline_access and email. profile should be filtered out.
+ Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.OPENID));
+ Assert.assertTrue(respCtx.getScope().contains(OIDCScopeValue.EMAIL));
+ Assert.assertFalse(respCtx.getScope().contains(OIDCScopeValue.OFFLINE_ACCESS));
+ Assert.assertFalse(respCtx.getScope().contains(OIDCScopeValue.PROFILE));
+ }
+
}
\ No newline at end of file
diff --git a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/package-info.java
similarity index 54%
copy from idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java
copy to idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/package-info.java
index ec39a3cd..32f6334a 100644
--- a/idp-oidc-extension-api/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/context/navigate/TokenRequestScopeLookupFunction.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/package-info.java
@@ -15,26 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.plugin.oidc.op.profile.context.navigate;
-
-import javax.annotation.Nonnull;
-
-import com.nimbusds.oauth2.sdk.Scope;
-
-import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
-
/**
- * For Token and UserInfo end points.
- *
- * A function that returns copy of requested scope via a lookup function. This lookup locates scope from token for token
- * request handling. If token claims are not available, null is returned.
+ * Unit tests for profile action implementations related to OIDC.
*/
-public class TokenRequestScopeLookupFunction extends AbstractTokenClaimsLookupFunction<Scope> {
-
- /** {@inheritDoc} */
- @Override
- Scope doLookup(@Nonnull final TokenClaimsSet tokenClaims) {
- return tokenClaims.getScope();
- }
-
-}
\ No newline at end of file
+package net.shibboleth.idp.plugin.oidc.op.profile.impl;
\ 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