[java-idp-oidc] branch main updated: JOIDC-90 - Revocation of individual tokens
Henri Mikkonen
henri.mikkonen at iki.fi
Mon Jun 27 12:15:29 UTC 2022
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=eacef6053533d411174b3a931cb57380c8ef98ef
The following commit(s) were added to refs/heads/main by this push:
new eacef605 JOIDC-90 - Revocation of individual tokens
eacef605 is described below
commit eacef6053533d411174b3a931cb57380c8ef98ef
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Mon Jun 27 15:13:18 2022 +0300
JOIDC-90 - Revocation of individual tokens
https://shibboleth.atlassian.net/browse/JOIDC-90
After a code review decided to change the revocation lifetime logic when revoking a single token:
in those cases the revocation lifetime is taken from the token expiration time.
Affected SWF actions: RevokeToken and SetRefreshTokenToResponseContext
Also added global configuration property idp.oauth2.revocationMethod and wired it to the revocation
configuration. Config was also missing wiring of idp.oidc.revocationCache.authorizeCode.lifetime.
---
.../oidc/op/oauth2/profile/impl/RevokeToken.java | 56 ++++++++++++------
.../impl/SetRefreshTokenToResponseContext.java | 23 +++++++-
...faultTokenRevocationLifetimeLookupStrategy.java | 66 ++++++++++++++++++++++
.../idp/service/relying-party/postconfig.xml | 16 +++++-
.../idp/plugin/oidc/op/conf/oidc.properties | 5 +-
.../op/oauth2/profile/impl/RevokeTokenTest.java | 27 ++++++++-
.../impl/SetRefreshTokenToResponseContextTest.java | 28 ++++++++-
7 files changed, 197 insertions(+), 24 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeToken.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeToken.java
index fb7df393..65aed21e 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeToken.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeToken.java
@@ -34,6 +34,7 @@ import com.nimbusds.jwt.JWTClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.oauth2.messaging.context.OAuth2TokenMgmtResponseContext;
import net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultRootTokenIdentifierLookupStrategy;
+import net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultTokenRevocationLifetimeLookupStrategy;
import net.shibboleth.idp.plugin.oidc.op.storage.RevocationCacheContexts;
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.idp.profile.IdPEventIds;
@@ -71,8 +72,11 @@ public class RevokeToken extends AbstractProfileAction {
*/
@Nonnull private Function<ProfileRequestContext,OAuth2TokenRevocationMethod> revocationMethodLookupStrategy;
- /** Lookup function to supply revocation lifetime. */
- @Nonnull private Function<ProfileRequestContext,Duration> revocationLifetimeLookupStrategy;
+ /** Lookup function to supply chain revocation lifetime. */
+ @Nonnull private Function<ProfileRequestContext,Duration> chainRevocationLifetimeLookupStrategy;
+
+ /** Lookup function to supply token revocation lifetime. */
+ @Nonnull private Function<JWTClaimsSet,Duration> tokenRevocationLifetimeLookupStrategy;
/** Lookup function to supply root token identifier. */
@Nonnull private Function<JWTClaimsSet,String> rootTokenIdentifierLookupStrategy;
@@ -83,12 +87,16 @@ public class RevokeToken extends AbstractProfileAction {
/** Revocation lifetime to use. */
private Duration revocationLifetime;
+ /** The claims set to operate on. */
+ private JWTClaimsSet claimsSet;
+
/**
* Constructor.
*/
public RevokeToken() {
revocationMethodLookupStrategy = new RevocationMethodLookupFunction();
- revocationLifetimeLookupStrategy = new RevocationLifetimeLookupFunction();
+ chainRevocationLifetimeLookupStrategy = new RevocationLifetimeLookupFunction();
+ tokenRevocationLifetimeLookupStrategy = new DefaultTokenRevocationLifetimeLookupStrategy();
rootTokenIdentifierLookupStrategy = new DefaultRootTokenIdentifierLookupStrategy();
}
@@ -113,13 +121,23 @@ public class RevokeToken extends AbstractProfileAction {
}
/**
- * Set a lookup strategy for the revocation lifetime.
+ * Set a lookup strategy for the chain revocation lifetime.
*
* @param strategy What to set.
*/
- public void setRevocationLifetimeLookupStrategy(
+ public void setChainRevocationLifetimeLookupStrategy(
@Nullable final Function<ProfileRequestContext,Duration> strategy) {
- revocationLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ chainRevocationLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Set a lookup strategy for the token revocation lifetime.
+ *
+ * @param strategy What to set.
+ */
+ public void setTokenRevocationLifetimeLookupStrategy(
+ @Nullable final Function<JWTClaimsSet,Duration> strategy) {
+ tokenRevocationLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
}
/**
@@ -155,8 +173,21 @@ public class RevokeToken extends AbstractProfileAction {
return false;
}
- revocationLifetime = revocationLifetimeLookupStrategy.apply(profileRequestContext);
- if (revocationLifetime == null) {
+ final OAuth2TokenMgmtResponseContext ctx = profileRequestContext.getOutboundMessageContext().getSubcontext(
+ OAuth2TokenMgmtResponseContext.class);
+ if (ctx == null || ctx.getTokenClaimsSet() == null) {
+ log.debug("{} No token validated for revocation, assumed to be invalid", getLogPrefix());
+ return false;
+ }
+ claimsSet = ctx.getTokenClaimsSet();
+
+ if (OAuth2TokenRevocationMethod.CHAIN.equals(revocationMethod)) {
+ revocationLifetime = chainRevocationLifetimeLookupStrategy.apply(profileRequestContext);
+ } else if (OAuth2TokenRevocationMethod.TOKEN.equals(revocationMethod)) {
+ revocationLifetime = tokenRevocationLifetimeLookupStrategy.apply(claimsSet);
+ }
+
+ if (revocationLifetime == null || Duration.ZERO.equals(revocationLifetime)) {
log.error("{} Unable to obtain revocation lifetime to use", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
return false;
@@ -167,15 +198,6 @@ public class RevokeToken extends AbstractProfileAction {
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
- final OAuth2TokenMgmtResponseContext ctx = profileRequestContext.getOutboundMessageContext().getSubcontext(
- OAuth2TokenMgmtResponseContext.class);
- if (ctx == null || ctx.getTokenClaimsSet() == null) {
- log.debug("{} No token validated for revocation, assumed to be invalid", getLogPrefix());
- return;
- }
-
- final JWTClaimsSet claimsSet = ctx.getTokenClaimsSet();
final String jti = claimsSet.getJWTID();
if (jti == null) {
log.error("{} No ID found in token claims set (this should be impossible)", getLogPrefix());
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 b3e151cd..2ce9ebd8 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
@@ -38,6 +38,7 @@ import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.openid.connect.sdk.OIDCScopeValue;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCAuthenticationResponseContext;
+import net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultTokenRevocationLifetimeLookupStrategy;
import net.shibboleth.idp.plugin.oidc.op.storage.RevocationCacheContexts;
import net.shibboleth.idp.plugin.oidc.op.token.support.AuthorizeCodeClaimsSet;
import net.shibboleth.idp.plugin.oidc.op.token.support.RefreshTokenClaimsSet;
@@ -94,6 +95,9 @@ public class SetRefreshTokenToResponseContext extends AbstractOIDCResponseAction
/** Strategy used to determine whether to revoke refresh tokens once they're used. */
@Nonnull private Predicate<ProfileRequestContext> enforceRefreshTokenRotationCondition;
+ /** Lookup function to supply token revocation lifetime. */
+ @Nonnull private Function<JWTClaimsSet,Duration> tokenRevocationLifetimeLookupStrategy;
+
/** Authorize Code / Refresh Token the refresh token will be based on. */
@Nullable private TokenClaimsSet tokenClaimsSet;
@@ -115,6 +119,7 @@ public class SetRefreshTokenToResponseContext extends AbstractOIDCResponseAction
new RefreshTokenClaimsSetManipulationStrategyLookupFunction();
idGeneratorLookupStrategy = FunctionSupport.constant(new SecureRandomIdentifierGenerationStrategy());
enforceRefreshTokenRotationCondition = new EnforceRefreshTokenRotationPredicate();
+ tokenRevocationLifetimeLookupStrategy = new DefaultTokenRevocationLifetimeLookupStrategy();
}
/**
@@ -178,6 +183,16 @@ public class SetRefreshTokenToResponseContext extends AbstractOIDCResponseAction
enforceRefreshTokenRotationCondition = Constraint.isNotNull(condition, "Condition cannot be null");
}
+ /**
+ * Set a lookup strategy for the token revocation lifetime.
+ *
+ * @param strategy What to set.
+ */
+ public void setTokenRevocationLifetimeLookupStrategy(
+ @Nullable final Function<JWTClaimsSet,Duration> strategy) {
+ tokenRevocationLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
/** {@inheritDoc} */
@Override
protected void doInitialize() throws ComponentInitializationException {
@@ -274,8 +289,14 @@ public class SetRefreshTokenToResponseContext extends AbstractOIDCResponseAction
if (enforceRefreshTokenRotationCondition.test(profileRequestContext) &&
tokenClaimsSet instanceof RefreshTokenClaimsSet) {
final String jti = tokenClaimsSet.getID();
+ final Duration lifetime = tokenRevocationLifetimeLookupStrategy.apply(tokenClaimsSet.getClaimsSet());
+ if (lifetime == null || Duration.ZERO.equals(lifetime)) {
+ log.error("{} Unable to fetch lifetime for the single token revocation", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+ return;
+ }
log.debug("{} Revoking the refresh token {} used for issuing the new one", getLogPrefix(), jti);
- if (!revocationCache.revoke(RevocationCacheContexts.SINGLE_ACCESS_OR_REFRESH_TOKENS, jti)) {
+ if (!revocationCache.revoke(RevocationCacheContexts.SINGLE_ACCESS_OR_REFRESH_TOKENS, jti, lifetime)) {
log.error("{} Unable to store revocation into the revocation cache", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
return;
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultTokenRevocationLifetimeLookupStrategy.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultTokenRevocationLifetimeLookupStrategy.java
new file mode 100644
index 00000000..66ba4f52
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultTokenRevocationLifetimeLookupStrategy.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.profile.logic;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+
+/**
+ * Default lookup function for fetching the token revocation lifetime from the given claims set. If an expiration
+ * time is found from the claims set, a difference between now and it is returned. If the expiration time is in the
+ * past, a {@link Duration#ZERO} is returned. If no expiration time is found, null is returned.
+ */
+public class DefaultTokenRevocationLifetimeLookupStrategy implements Function<JWTClaimsSet, Duration> {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(DefaultTokenRevocationLifetimeLookupStrategy.class);
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ public Duration apply(@Nullable final JWTClaimsSet claimsSet) {
+ if (claimsSet == null) {
+ log.error("The given claims set was null, returning null");
+ return null;
+ }
+ final Date expiration = claimsSet.getExpirationTime();
+ if (expiration == null) {
+ log.debug("No token expiration time found from the claims set, returning null");
+ return null;
+ }
+ final Instant now = Instant.now();
+ final Instant exp = expiration.toInstant();
+ if (now.isAfter(exp)) {
+ log.debug("Token expiration time was in the past, returning ZERO");
+ return Duration.ZERO;
+ }
+ return Duration.between(now, exp);
+ }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index c0ffe0ab..33144287 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -85,7 +85,9 @@
p:issuer-ref="shibboleth.oidc.issuer"
p:tokenEndpointAuthMethods="%{idp.oidc.dynreg.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
p:claimsValidator-ref="DefaultJWTClaimsValidator"
- p:issuedClaimsValidator-ref="DefaultRevocationJWTClaimsValidator" />
+ p:issuedClaimsValidator-ref="DefaultRevocationJWTClaimsValidator"
+ p:revocationMethod="%{idp.oauth2.revocationMethod:CHAIN}"
+ p:revocationLifetime="%{idp.oidc.revocationCache.authorizeCode.lifetime:PT6H}"/>
<!-- Metadata-driven variants. -->
@@ -486,8 +488,20 @@
p:propertyType="#{T(net.shibboleth.oidc.jwt.claims.ClaimsValidator)}"
p:defaultValue-ref="DefaultRevocationJWTClaimsValidator" />
</property>
+ <property name="revocationMethodLookupStrategy">
+ <bean parent="shibboleth.MDDrivenBeanProperty" p:propertyName="revocationMethod"
+ p:propertyType="#{T(net.shibboleth.oidc.profile.oauth2.config.OAuth2TokenRevocationConfiguration$OAuth2TokenRevocationMethod)}"
+ p:defaultValue-ref="RevocationMethod.%{idp.oauth2.revocationMethod:CHAIN}" />
+ </property>
+ <property name="revocationLifetimeLookupStrategy">
+ <bean parent="shibboleth.MDDrivenDurationProperty" p:propertyName="revocationLifetime"
+ p:defaultValue="%{idp.oidc.revocationCache.authorizeCode.lifetime:PT6H}" />
+ </property>
</bean>
+ <util:constant id="RevocationMethod.CHAIN" static-field="net.shibboleth.oidc.profile.oauth2.config.OAuth2TokenRevocationConfiguration$OAuth2TokenRevocationMethod.CHAIN" />
+ <util:constant id="RevocationMethod.TOKEN" static-field="net.shibboleth.oidc.profile.oauth2.config.OAuth2TokenRevocationConfiguration$OAuth2TokenRevocationMethod.TOKEN" />
+
<!-- Default client-auth JWT validation wiring. -->
<bean id="AdaptedRelyingPartyIdLookup" class="net.shibboleth.utilities.java.support.logic.BiFunctionSupport"
diff --git a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
index 49699e11..1df268c2 100644
--- a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
+++ b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
@@ -135,4 +135,7 @@ idp.oidc.subject.salt = this_too_should_be_ch4ng3d
#idp.oauth2.authn.flows = OAuth2Client
# Set true to enforce refresh token rotation (defaults to false)
-#idp.oauth2.enforceRefreshTokenRotation = true
\ No newline at end of file
+#idp.oauth2.enforceRefreshTokenRotation = true
+
+# Revocation method: set to TOKEN to revoke single tokens (defaults to full chain (value = CHAIN))
+#idp.oauth2.revocationMethod = TOKEN
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeTokenTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeTokenTest.java
index 6fed64f8..8e95531d 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeTokenTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/RevokeTokenTest.java
@@ -18,6 +18,7 @@
package net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl;
import java.time.Duration;
+import java.time.Instant;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.storage.RevocationCache;
@@ -33,6 +34,7 @@ import net.shibboleth.idp.plugin.oidc.op.token.support.AccessTokenClaimsSet;
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.testing.BaseTokenClaimsSetTest;
+import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.idp.profile.testing.RequestContextBuilder;
@@ -61,8 +63,13 @@ public class RevokeTokenTest extends BaseTokenClaimsSetTest {
private ProfileRequestContext prc;
private OAuth2TokenMgmtResponseContext tokenCtx;
-
+
protected void setUp(final OAuth2TokenRevocationMethod method, final String rootTokenId) throws Exception {
+ setUp(method, rootTokenId, exp);
+ }
+
+ protected void setUp(final OAuth2TokenRevocationMethod method, final String rootTokenId, final Instant exp)
+ throws Exception {
storageService = new MemoryStorageService();
storageService.setId("test");
@@ -98,7 +105,7 @@ public class RevokeTokenTest extends BaseTokenClaimsSetTest {
action.setRevocationCache(revocationCache);
action.setRevocationMethodLookupStrategy(
prc -> method);
- action.setRevocationLifetimeLookupStrategy(prc -> Duration.ofHours(1));
+ action.setChainRevocationLifetimeLookupStrategy(prc -> Duration.ofHours(1));
action.initialize();
src = new RequestContextBuilder().buildRequestContext();
@@ -182,7 +189,21 @@ public class RevokeTokenTest extends BaseTokenClaimsSetTest {
setUp(OAuth2TokenRevocationMethod.TOKEN, null);
ActionTestingSupport.assertProceedEvent(action.execute(src));
}
-
+
+ @Test
+ public void testSingleToken_ExpiredAccessToken() throws Exception {
+ setUp(OAuth2TokenRevocationMethod.TOKEN, null, Instant.now().minus(Duration.ofMinutes(10)));
+ tokenCtx.setTokenClaimsSet(atClaimsSet.getClaimsSet());
+ ActionTestingSupport.assertEvent(action.execute(src), IdPEventIds.INVALID_PROFILE_CONFIG);
+ }
+
+ @Test
+ public void testSingleToken_ExpiredRefreshToken() throws Exception {
+ setUp(OAuth2TokenRevocationMethod.TOKEN, null, Instant.now().minus(Duration.ofMinutes(10)));
+ tokenCtx.setTokenClaimsSet(rfClaimsSet.getClaimsSet());
+ ActionTestingSupport.assertEvent(action.execute(src), IdPEventIds.INVALID_PROFILE_CONFIG);
+ }
+
@Test
public void testSingleToken_RevokeAccessToken() throws Exception {
setUp(OAuth2TokenRevocationMethod.TOKEN, null);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContextTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContextTest.java
index 405e3d8e..99362102 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContextTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/SetRefreshTokenToResponseContextTest.java
@@ -33,6 +33,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
+import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.function.BiFunction;
@@ -217,7 +218,7 @@ public class SetRefreshTokenToResponseContextTest extends BaseOIDCResponseAction
.setPrincipal("userPrin")
.setSubject("subject")
.setIssuedAt(Instant.now())
- .setExpiresAt(Instant.now())
+ .setExpiresAt(Instant.now().plus(Duration.ofHours(1)))
.setAuthenticationTime(Instant.now())
.setRedirectURI(new URI("http://example.com"))
.setScope(new Scope())
@@ -238,6 +239,31 @@ public class SetRefreshTokenToResponseContextTest extends BaseOIDCResponseAction
Assert.assertTrue(revocationCache.isRevoked(RevocationCacheContexts.SINGLE_ACCESS_OR_REFRESH_TOKENS, jit));
}
+ @Test
+ public void testFailWithExpiredRefreshRotationEnforced() throws ComponentInitializationException, NoSuchAlgorithmException, URISyntaxException,
+ ParseException, DataSealerException {
+ final String rootTokenId = new SecureRandomIdentifierGenerationStrategy().generateIdentifier();
+ final TokenClaimsSet claims = new RefreshTokenClaimsSet.Builder()
+ .setJWTID(idGenerator)
+ .setClientID(new ClientID())
+ .setIssuer("issuer")
+ .setPrincipal("userPrin")
+ .setSubject("subject")
+ .setIssuedAt(Instant.now())
+ .setExpiresAt(Instant.now())
+ .setAuthenticationTime(Instant.now())
+ .setRedirectURI(new URI("http://example.com"))
+ .setScope(new Scope())
+ .setACR(new ACR("0"))
+ .setRootTokenIdentifier(rootTokenId)
+ .build();
+ final String jit = claims.getID();
+ respCtx.setAuthorizationGrantClaimsSet(claims);
+ enforceRotation = true;
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, IdPEventIds.INVALID_PROFILE_CONFIG);
+ }
+
/**
* There is no offline_access scope.
*
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list