[java-idp-oidc] branch maint-3.0 updated: JOIDC-65 JWT client authentication support is incomplete
Henri Mikkonen
henri.mikkonen at iki.fi
Tue Dec 28 13:04:29 UTC 2021
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch maint-3.0
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=6d6568a806d873cf3210b49275fe8c003c81abf8
The following commit(s) were added to refs/heads/maint-3.0 by this push:
new 6d6568a8 JOIDC-65 JWT client authentication support is incomplete
6d6568a8 is described below
commit 6d6568a806d873cf3210b49275fe8c003c81abf8
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Dec 28 15:03:05 2021 +0200
JOIDC-65 JWT client authentication support is incomplete
https://shibboleth.atlassian.net/browse/JOIDC-65
Refactored the incoming JWT authentication validation: created a new abstract-api-jwt -flow, which
is inherited by token, introspection and revocation flows. Its -beans.xml contains wiring of claims
validators for the required JWT claims. The bean is wired to the ValaidateEndpointAuthentication action.
---
.../impl/ValidateEndpointAuthentication.java | 97 ++++--------------
...entIDFromOIDCMetadataContextLookupFunction.java | 79 +++++++++++++++
.../claims/impl/JwtIdentifierClaimsValidator.java | 110 +++++++++++++++++++++
.../oauth2/introspection/introspection-beans.xml | 10 +-
.../oauth2/introspection/introspection-flow.xml | 2 +-
.../flows/oauth2/revocation/revocation-beans.xml | 10 +-
.../flows/oauth2/revocation/revocation-flow.xml | 2 +-
.../oidc-abstract-api-jwt-beans.xml | 56 +++++++++++
.../oidc-abstract-api-jwt-flow.xml | 11 +++
.../idp/flows/oidc/token/token-beans.xml | 12 +--
.../shibboleth/idp/flows/oidc/token/token-flow.xml | 2 +-
.../impl/ValidateEndpointAuthenticationTest.java | 105 ++++++++++++++------
.../impl/JwtIdentifierClaimsValidatorTest.java | 105 ++++++++++++++++++++
13 files changed, 462 insertions(+), 139 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthentication.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthentication.java
index 26774daf..a8dce0d6 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthentication.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthentication.java
@@ -18,8 +18,7 @@
package net.shibboleth.idp.plugin.oidc.op.profile.impl;
import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Date;
+import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@@ -51,19 +50,16 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.config.navigate.TokenEndpointAuthMethodLookupFunction;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCMetadataContext;
-import net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.IssuedAtClaimsValidator;
import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
+import net.shibboleth.oidc.jwt.claims.JWTClaimsValidation;
import net.shibboleth.oidc.jwt.claims.JWTValidationException;
import net.shibboleth.oidc.security.impl.JWTSignatureValidationUtil;
import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
-import net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator;
import net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidation;
-import net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.primitive.StringSupport;
/**
* Validates the endpoint authentication with the token_endpoint_auth_method stored to the client's metadata.
@@ -94,15 +90,9 @@ public class ValidateEndpointAuthentication extends AbstractOIDCRequestAction<Ab
*/
@Nonnull private Function<ProfileRequestContext, SecurityParametersContext> securityParametersLookupStrategy;
- /** The validator used for the expiration time of the incoming JWTs. */
- @Nonnull private ClaimsValidator expiryClaimsValidator;
-
- /** The validator used for the issuance time of the incoming JWTs. */
- @Nonnull private ClaimsValidator issuedAtClaimsValidator;
-
- /** The validator used for the audience of the incoming JWTs. */
- @Nonnull private ClaimsValidator audienceClaimsValidator;
-
+ /** The claims validator to be applied for validating the incoming JWTs. */
+ @NonnullAfterInit private JWTClaimsValidation claimsValidation;
+
/**
* Constructor.
*/
@@ -111,11 +101,6 @@ public class ValidateEndpointAuthentication extends AbstractOIDCRequestAction<Ab
new InboundMessageContextLookup());
tokenEndpointAuthMethodsLookupStrategy = new TokenEndpointAuthMethodLookupFunction();
securityParametersLookupStrategy = new ChildContextLookup<>(SecurityParametersContext.class);
- audienceClaimsValidator = new AudienceClaimsValidator();
- ((AudienceClaimsValidator) audienceClaimsValidator).setAudienceLookupStrategy(
- (P, J) -> getHttpServletRequest().getRequestURL().toString());
- expiryClaimsValidator = new ExpiryClaimsValidator();
- issuedAtClaimsValidator = new IssuedAtClaimsValidator();
}
/**
@@ -167,33 +152,13 @@ public class ValidateEndpointAuthentication extends AbstractOIDCRequestAction<Ab
}
/**
- * Set the validator used for the expiration time of the incoming JWTs.
+ * Set the claims validator used for validating the incoming JWTs.
*
- * @param validator What to set.
+ * @param validators What to set.
*/
- public void setExpiryClaimsValidator(@Nonnull final ClaimsValidator validator) {
+ public void setClaimsValidation(@Nonnull final JWTClaimsValidation validation) {
ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- expiryClaimsValidator = Constraint.isNotNull(validator, "ExpiryClaimsValidator cannot be null");
- }
-
- /**
- * Set the validator used for the issuance time of the incoming JWTs.
- *
- * @param validator What to set.
- */
- public void setIssuedAtClaimsValidator(@Nonnull final ClaimsValidator validator) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- issuedAtClaimsValidator = Constraint.isNotNull(validator, "IssuedAtClaimsValidator cannot be null");
- }
-
- /**
- * Set the validator used for the audience of the incoming JWTs.
- *
- * @param validator What to set.
- */
- public void setAudienceClaimsValidator(@Nonnull final ClaimsValidator validator) {
- ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
- audienceClaimsValidator = Constraint.isNotNull(validator, "AudienceClaimsValidator cannot be null");
+ claimsValidation = Constraint.isNotNull(validation, "Claims validator cannot be null");
}
@@ -205,6 +170,10 @@ public class ValidateEndpointAuthentication extends AbstractOIDCRequestAction<Ab
if (replayCache == null) {
throw new ComponentInitializationException("ReplayCache cannot be null");
}
+
+ if (claimsValidation == null) {
+ throw new ComponentInitializationException("ClaimsValidator cannot be null");
+ }
}
/** {@inheritDoc} */
@@ -288,52 +257,22 @@ public class ValidateEndpointAuthentication extends AbstractOIDCRequestAction<Ab
* @param profileRequestContext The profile request context.
* @return true if JWT meets the requirements, false otherwise.
*/
- protected boolean validateJwtClaims(final SignedJWT jwt, final String clientId, @Nonnull final ProfileRequestContext profileRequestContext ) {
+ protected boolean validateJwtClaims(final SignedJWT jwt, final String clientId,
+ @Nonnull final ProfileRequestContext profileRequestContext ) {
final JWTClaimsSet claimsSet;
try {
claimsSet = jwt.getJWTClaimsSet();
} catch (ParseException e) {
- log.error("{} Could not parse the JWT into claims set, it cannot be validated", getLogPrefix());
- return false;
- }
- final List<String> aud = claimsSet.getAudience();
- if (aud == null || aud.isEmpty()) {
- log.warn("{} The incoming JWT from {} is missing audience (aud)", getLogPrefix(), clientId);
- return false;
- }
- final Date exp = claimsSet.getExpirationTime();
- if (exp == null) {
- log.warn("{} The incoming JWT from {} is missing expiration time (exp)", getLogPrefix(), clientId);
+ log.error("{} Could not parse the JWT from {} into claims set, it cannot be validated",
+ getLogPrefix(), clientId);
return false;
}
- final String jit = claimsSet.getJWTID();
- if (StringSupport.trimOrNull(jit) == null) {
- log.warn("{} The incoming JWT from {} is missing JWT identifier (jit)", getLogPrefix(), clientId);
- return false;
- }
- final ChainingJWTClaimsValidation validatorChain = new ChainingJWTClaimsValidation();
- final List<ClaimsValidator> validators = new ArrayList<>();
-
- log.info("{} Validating against {}", getLogPrefix(), getHttpServletRequest().getRequestURL());
-
- final Date iat = claimsSet.getIssueTime();
- if (iat != null) {
- validators.add(issuedAtClaimsValidator);
- }
- validators.add(expiryClaimsValidator);
- validators.add(audienceClaimsValidator);
-
- validatorChain.setClaimValidators(validators);
try {
- validatorChain.validate(claimsSet, profileRequestContext);
+ claimsValidation.validate(claimsSet, profileRequestContext);
} catch (final JWTValidationException e) {
log.warn("{} JWT validation failed for the client {}", getLogPrefix(), clientId, e);
return false;
}
- if (!replayCache.check(getClass().getName(), jit, exp.toInstant())) {
- log.warn("{} Replay detected for the incoming JWT from {}", getLogPrefix(), clientId);
- return false;
- }
return true;
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/ClientIDFromOIDCMetadataContextLookupFunction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/ClientIDFromOIDCMetadataContextLookupFunction.java
new file mode 100644
index 00000000..b4029b70
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/ClientIDFromOIDCMetadataContextLookupFunction.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.profile.logic;
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCMetadataContext;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * A function that returns client_id via client information stored in {@link OIDCMetadataContext}.
+ *
+ * TODO: the class is temporarily located here due to OP plugin 3.0.3 patch.
+ */
+public class ClientIDFromOIDCMetadataContextLookupFunction
+ implements BiFunction<ProfileRequestContext, JWTClaimsSet, String> {
+
+ /** Strategy that will return {@link OIDCMetadataContext}. */
+ @Nonnull private Function<ProfileRequestContext, OIDCMetadataContext> oidcMetadataContextLookupStrategy;
+
+ /**
+ * Constructor.
+ */
+ public ClientIDFromOIDCMetadataContextLookupFunction() {
+ oidcMetadataContextLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
+ new InboundMessageContextLookup());
+ }
+
+ /**
+ * Set the strategy used to return the {@link OIDCMetadataContext}.
+ *
+ * @param strategy The lookup strategy.
+ */
+ public void setOidcMetadataContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
+ oidcMetadataContextLookupStrategy =
+ Constraint.isNotNull(strategy, "OIDCMetadataContext lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable
+ public String apply(@Nonnull final ProfileRequestContext prc, @Nullable final JWTClaimsSet claimsSet) {
+ final OIDCMetadataContext oidcMetadataContext = oidcMetadataContextLookupStrategy.apply(prc);
+ if (oidcMetadataContext == null) {
+ return null;
+ }
+ final OIDCClientInformation clientInformation = oidcMetadataContext.getClientInformation();
+ if (clientInformation == null || clientInformation.getID() == null) {
+ return null;
+ }
+ return clientInformation.getID().toString();
+ }
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/JwtIdentifierClaimsValidator.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/JwtIdentifierClaimsValidator.java
new file mode 100644
index 00000000..12d9cee3
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/JwtIdentifierClaimsValidator.java
@@ -0,0 +1,110 @@
+/*
+ * 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.security.jwt.claims.impl;
+
+import java.time.Duration;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.storage.ReplayCache;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+
+import net.shibboleth.oidc.jwt.claims.AbstractClaimsValidator;
+import net.shibboleth.oidc.jwt.claims.JWTValidationException;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Verifies the identifier (jit) from the JWT against repla via configurable {@link ReplayCache}. Single identifier is
+ * stored in the cache for the lifetime of the JWT: expiration instant is taken from the 'exp' -claim.
+ *
+ * TODO: the class is temporarily located here due to OP plugin 3.0.3 patch. To be moved to oidc-commons:
+ * net.shibboleth.oidc.security.jwt.claims.impl -package.
+ */
+public class JwtIdentifierClaimsValidator extends AbstractClaimsValidator {
+
+ /** Message replay cache instance to use. */
+ @NonnullAfterInit private ReplayCache replayCache;
+
+ /**
+ * Clock skew adjustment in both directions to consider still acceptable (Default value: 1 minute).
+ */
+ @Nonnull private Duration clockSkew;
+
+ /**
+ * Constructor.
+ */
+ public JwtIdentifierClaimsValidator() {
+ clockSkew = Duration.ofMinutes(1);
+ }
+
+ /**
+ * Set the replay cache instance to use.
+ *
+ * @param cache replay cache to set.
+ */
+ public void setReplayCache(@Nonnull final ReplayCache cache) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ replayCache = Constraint.isNotNull(cache, "ReplayCache cannot be null");
+ }
+
+ /**
+ * Set the clock skew.
+ *
+ * @param skew clock skew to set.
+ */
+ public void setClockSkew(@Nonnull final Duration skew) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ clockSkew = Constraint.isNotNull(skew, "Clock skew cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ if (replayCache == null) {
+ throw new ComponentInitializationException("ReplayCache can not be null");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doValidate(@Nonnull final JWTClaimsSet claims, @Nullable final ProfileRequestContext context)
+ throws JWTValidationException {
+
+ final Date exp = claims.getExpirationTime();
+ if (exp == null) {
+ throw new JWTValidationException("The claims set is missing required expiration time (exp)");
+ }
+ final String jit = claims.getJWTID();
+ if (StringSupport.trimOrNull(jit) == null) {
+ throw new JWTValidationException("The claims set is missing required JWT identifier (jit)");
+ }
+ if (!replayCache.check(getClass().getName(), jit, exp.toInstant().plus(clockSkew))) {
+ throw new JWTValidationException("Replay detected for jit '" + jit + "'");
+ }
+ }
+}
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml
index c919f4d3..7085f62d 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml
@@ -28,21 +28,13 @@
<bean id="ValidateEndpointAuthentication"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateEndpointAuthentication" scope="prototype"
p:httpServletRequest-ref="shibboleth.HttpServletRequest" p:replayCache-ref="shibboleth.ReplayCache"
- p:expiryClaimsValidator-ref="ExpiryClaimsValidator" p:issuedAtClaimsValidator-ref="IssuedAtClaimsValidator">
+ p:claimsValidation-ref="shibboleth.oidc.JWTClaimsValidation">
<property name="securityParametersLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
</bean>
-
- <bean id="ExpiryClaimsValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
- p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
-
- <bean id="IssuedAtClaimsValidator"
- class="net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.IssuedAtClaimsValidator"
- p:messageLifetime="%{idp.policy.messageLifetime:PT1M}" p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
<bean id="FormOutboundMessage"
class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.FormOutboundIntrospectionResponseMessage" scope="prototype"
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml
index a8174188..21548afc 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml
@@ -1,7 +1,7 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
- parent="oidc/abstract-api, oidc/metadata-lookup">
+ parent="oidc/abstract-api-jwt, oidc/metadata-lookup">
<action-state id="InitializeMandatoryContexts">
<evaluate expression="InitializeProfileRequestContext" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml
index 064193a9..3d93dcf5 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml
@@ -29,21 +29,13 @@
<bean id="ValidateEndpointAuthentication"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateEndpointAuthentication" scope="prototype"
p:httpServletRequest-ref="shibboleth.HttpServletRequest" p:replayCache-ref="shibboleth.ReplayCache"
- p:expiryClaimsValidator-ref="ExpiryClaimsValidator" p:issuedAtClaimsValidator-ref="IssuedAtClaimsValidator">
+ p:claimsValidation-ref="shibboleth.oidc.JWTClaimsValidation">
<property name="securityParametersLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
</bean>
-
- <bean id="ExpiryClaimsValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
- p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
-
- <bean id="IssuedAtClaimsValidator"
- class="net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.IssuedAtClaimsValidator"
- p:messageLifetime="%{idp.policy.messageLifetime:PT1M}" p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
<bean id="RevokeToken" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.RevokeToken" scope="prototype"
c:sealer-ref="#{'%{idp.oidc.tokenSealer:shibboleth.oidc.TokenSealer}'.trim()}"
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml
index 4b3edf0e..28c8fe83 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml
@@ -1,7 +1,7 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
- parent="oidc/abstract-api, oidc/metadata-lookup">
+ parent="oidc/abstract-api-jwt, oidc/metadata-lookup">
<action-state id="InitializeMandatoryContexts">
<evaluate expression="InitializeProfileRequestContext" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-jwt/oidc-abstract-api-jwt-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-jwt/oidc-abstract-api-jwt-beans.xml
new file mode 100644
index 00000000..190f66fc
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-jwt/oidc-abstract-api-jwt-beans.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+ default-init-method="initialize" default-destroy-method="destroy">
+
+ <bean id="shibboleth.oidc.JWTClaimsValidation"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidation"
+ p:claimValidators-ref="ClaimsValidators" />
+
+ <bean id="ClientIDFromOIDCMetadataContextLookupFunction"
+ class="net.shibboleth.idp.plugin.oidc.op.profile.logic.ClientIDFromOIDCMetadataContextLookupFunction" />
+
+ <bean id="ExpiryClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
+ p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
+
+ <bean id="IssuedAtClaimsValidator"
+ class="net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.IssuedAtClaimsValidator"
+ p:messageLifetime="%{idp.policy.messageLifetime:PT1M}" p:clockSkew="%{idp.policy.clockSkew:PT1M}"
+ p:requiredRule="false" />
+
+ <bean id="IssuerClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+ p:claimName="iss" p:valueToMatchLookupStrategy-ref="ClientIDFromOIDCMetadataContextLookupFunction" />
+
+ <bean id="SubjectClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+ p:claimName="sub" p:valueToMatchLookupStrategy-ref="ClientIDFromOIDCMetadataContextLookupFunction" />
+
+ <bean id="AudienceClaimsValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator">
+ <property name="audienceLookupStrategy">
+ <bean parent="shibboleth.BiFunctions.Expression"
+ c:expression="#custom.getRequestURL().toString()"
+ p:customObject-ref="shibboleth.HttpServletRequest" />
+ </property>
+ </bean>
+
+ <bean id="JwtIdentifierClaimsValidator"
+ class="net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.JwtIdentifierClaimsValidator"
+ p:clockSkew="%{idp.policy.clockSkew:PT1M}" p:replayCache-ref="shibboleth.ReplayCache" />
+
+ <util:list id="ClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
+ <ref bean="ExpiryClaimsValidator" />
+ <ref bean="IssuedAtClaimsValidator" />
+ <ref bean="IssuerClaimsValidator" />
+ <ref bean="SubjectClaimsValidator" />
+ <ref bean="AudienceClaimsValidator" />
+ <ref bean="JwtIdentifierClaimsValidator" />
+ </util:list>
+
+</beans>
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-jwt/oidc-abstract-api-jwt-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-jwt/oidc-abstract-api-jwt-flow.xml
new file mode 100644
index 00000000..ef4f26b2
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract-api-jwt/oidc-abstract-api-jwt-flow.xml
@@ -0,0 +1,11 @@
+<flow xmlns="http://www.springframework.org/schema/webflow"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+ parent="oidc/abstract-api"
+ abstract="true">
+
+ <!-- Actions common to OIDC/OAuth2 profile backend flows involving JWT client authentication. -->
+
+ <bean-import resource="../../oidc/abstract-api-jwt/oidc-abstract-api-jwt-beans.xml" />
+
+</flow>
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
index c6d5e264..9d1b98e9 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
@@ -27,22 +27,14 @@
<bean id="ValidateEndpointAuthentication"
class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateEndpointAuthentication" scope="prototype"
p:httpServletRequest-ref="shibboleth.HttpServletRequest" p:replayCache-ref="shibboleth.ReplayCache"
- p:expiryClaimsValidator-ref="ExpiryClaimsValidator" p:issuedAtClaimsValidator-ref="IssuedAtClaimsValidator">
+ p:claimsValidation-ref="shibboleth.oidc.JWTClaimsValidation">
<property name="securityParametersLookupStrategy">
<bean parent="shibboleth.Functions.Compose"
c:g-ref="shibboleth.ChildLookup.SecurityParameters"
c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
</bean>
-
- <bean id="ExpiryClaimsValidator"
- class="net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator"
- p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
-
- <bean id="IssuedAtClaimsValidator"
- class="net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.IssuedAtClaimsValidator"
- p:messageLifetime="%{idp.policy.messageLifetime:PT1M}" p:clockSkew="%{idp.policy.clockSkew:PT1M}" />
-
+
<bean id="ValidateGrantType" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateGrantType"
scope="prototype" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
index 0202592a..9f31a083 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
@@ -1,6 +1,6 @@
<flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
- parent="oidc/abstract-api, oidc/metadata-lookup, oidc/consent-lookup">
+ parent="oidc/abstract-api-jwt, oidc/metadata-lookup, oidc/consent-lookup">
<action-state id="InitializeMandatoryContexts">
<evaluate expression="InitializeProfileRequestContext" />
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthenticationTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthenticationTest.java
index 377e34f8..18562cf0 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthenticationTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthenticationTest.java
@@ -69,12 +69,20 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCMetadataContext;
+import net.shibboleth.idp.plugin.oidc.op.profile.logic.ClientIDFromOIDCMetadataContextLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.IssuedAtClaimsValidator;
+import net.shibboleth.idp.plugin.oidc.op.security.jwt.claims.impl.JwtIdentifierClaimsValidator;
import net.shibboleth.idp.profile.context.navigate.AbstractRelyingPartyLookupFunction;
import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.oidc.jwt.claims.JWTClaimsValidation;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
+import net.shibboleth.oidc.security.jwt.claims.impl.AudienceClaimsValidator;
+import net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidation;
+import net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator;
+import net.shibboleth.oidc.security.jwt.claims.impl.ExpiryClaimsValidator;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
/**
@@ -193,11 +201,34 @@ public class ValidateEndpointAuthenticationTest {
if (newFunction != null) {
action.setTokenEndpointAuthMethodsLookupStrategy(newFunction);
}
- action.setHttpServletRequest(new MockHttpServletRequest());
+ MockHttpServletRequest httpRequest = new MockHttpServletRequest();
+ action.setHttpServletRequest(httpRequest);
+ action.setClaimsValidation(constructClaimsValidation(httpRequest, replayCache));
action.initialize();
return action;
}
+ protected JWTClaimsValidation constructClaimsValidation(final MockHttpServletRequest httpRequest,
+ final ReplayCache replayCache) {
+ final ChainingJWTClaimsValidation claimsValidation = new ChainingJWTClaimsValidation();
+ final ExpiryClaimsValidator expValidator = new ExpiryClaimsValidator();
+ final IssuedAtClaimsValidator iatValidator = new IssuedAtClaimsValidator();
+ iatValidator.setRequiredRule(false);
+ final ExactMatchClaimsValidator issValidator = new ExactMatchClaimsValidator();
+ issValidator.setClaimName("iss");
+ issValidator.setValueToMatchLookupStrategy(new ClientIDFromOIDCMetadataContextLookupFunction());
+ final ExactMatchClaimsValidator subValidator = new ExactMatchClaimsValidator();
+ subValidator.setClaimName("sub");
+ subValidator.setValueToMatchLookupStrategy(new ClientIDFromOIDCMetadataContextLookupFunction());
+ final AudienceClaimsValidator audValidator = new AudienceClaimsValidator();
+ audValidator.setAudienceLookupStrategy((prc, claims) -> httpRequest.getRequestURL().toString());
+ final JwtIdentifierClaimsValidator jitValidator = new JwtIdentifierClaimsValidator();
+ jitValidator.setReplayCache(replayCache);
+ claimsValidation.setClaimValidators(List.of(expValidator, iatValidator, issValidator, subValidator,
+ audValidator, jitValidator));
+ return claimsValidation;
+ }
+
@Test
public void testNoEnabledMethods() throws Exception {
ValidateEndpointAuthentication action = constructAction(null);
@@ -267,55 +298,67 @@ public class ValidateEndpointAuthenticationTest {
public void testFailingPrivateKeyJwt() throws Exception {
testFailingClientAuth(ClientAuthenticationMethod.PRIVATE_KEY_JWT);
}
+
+ @Test
+ public void testInvalidSecretJwt_iatInTheFuture() throws Exception {
+ testFailingJwtAuth(ClientAuthenticationMethod.CLIENT_SECRET_JWT, createSecretJWT(claimsSetWithIatInTheFuture()));
+ }
+
+ @Test
+ public void testInvalidSecretJwt_expInThePast() throws Exception {
+ testFailingJwtAuth(ClientAuthenticationMethod.CLIENT_SECRET_JWT, createSecretJWT(claimsSetWithExpInThePast()));
+ }
+
+ @Test
+ public void testInvalidSecretJwt_withoutJit() throws Exception {
+ testFailingJwtAuth(ClientAuthenticationMethod.CLIENT_SECRET_JWT, createSecretJWT(claimsSetWithoutJit()));
+ }
+ @Test
+ public void testInvalidSecretJwt_jitReplayDetected() throws Exception {
+ testFailingJwtAuth(ClientAuthenticationMethod.CLIENT_SECRET_JWT, createSecretJWT(validClaimsSet()), true);
+ }
+
@Test
public void testInvalidPrivateKeyJwt_iatInTheFuture() throws Exception {
- ClientAuthenticationMethod method = ClientAuthenticationMethod.PRIVATE_KEY_JWT;
- ValidateEndpointAuthentication action =
- constructAction(new ListMethodsFunction(method));
- final SignedJWT jwt = createPrivateKeyJWT(claimsSetWithIatInTheFuture());
- final Event event =
- action.execute(initializeRequestCtx(
- initializeTokenRequest(method, jwt), method, true));
- ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
+ testFailingJwtAuth(ClientAuthenticationMethod.PRIVATE_KEY_JWT, createPrivateKeyJWT(claimsSetWithIatInTheFuture()));
}
@Test
public void testInvalidPrivateKeyJwt_expInThePast() throws Exception {
- ClientAuthenticationMethod method = ClientAuthenticationMethod.PRIVATE_KEY_JWT;
- ValidateEndpointAuthentication action =
- constructAction(new ListMethodsFunction(method));
- final SignedJWT jwt = createPrivateKeyJWT(claimsSetWithExpInThePast());
- final Event event =
- action.execute(initializeRequestCtx(
- initializeTokenRequest(method, jwt), method, true));
- ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
+ testFailingJwtAuth(ClientAuthenticationMethod.PRIVATE_KEY_JWT, createPrivateKeyJWT(claimsSetWithExpInThePast()));
}
@Test
public void testInvalidPrivateKeyJwt_withoutJit() throws Exception {
- ClientAuthenticationMethod method = ClientAuthenticationMethod.PRIVATE_KEY_JWT;
- ValidateEndpointAuthentication action =
- constructAction(new ListMethodsFunction(method));
- final SignedJWT jwt = createPrivateKeyJWT(claimsSetWithoutJit());
- final Event event =
- action.execute(initializeRequestCtx(
- initializeTokenRequest(method, jwt), method, true));
- ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
+ testFailingJwtAuth(ClientAuthenticationMethod.PRIVATE_KEY_JWT, createPrivateKeyJWT(claimsSetWithoutJit()));
}
@Test
public void testInvalidPrivateKeyJwt_jitReplayDetected() throws Exception {
- ClientAuthenticationMethod method = ClientAuthenticationMethod.PRIVATE_KEY_JWT;
+ testFailingJwtAuth(ClientAuthenticationMethod.PRIVATE_KEY_JWT, createPrivateKeyJWT(validClaimsSet()), true);
+ }
+
+ protected void testFailingJwtAuth(final ClientAuthenticationMethod method, final SignedJWT jwt) throws Exception {
ValidateEndpointAuthentication action =
constructAction(new ListMethodsFunction(method));
- final SignedJWT jwt = createPrivateKeyJWT(validClaimsSet());
final RequestContext requestCtx = initializeRequestCtx(
initializeTokenRequest(method, jwt), method, true);
- Assert.assertNull(action.execute(requestCtx));
ActionTestingSupport.assertEvent(action.execute(requestCtx), EventIds.ACCESS_DENIED);
}
-
+
+ protected void testFailingJwtAuth(final ClientAuthenticationMethod method, final SignedJWT jwt, boolean replay)
+ throws Exception {
+ ValidateEndpointAuthentication action =
+ constructAction(new ListMethodsFunction(method));
+ final RequestContext requestCtx = initializeRequestCtx(
+ initializeTokenRequest(method, jwt), method, true);
+ if (replay) {
+ Assert.assertNull(action.execute(requestCtx));
+ }
+ ActionTestingSupport.assertEvent(action.execute(requestCtx), EventIds.ACCESS_DENIED);
+ }
+
protected JWTClaimsSet claimsSetWithIatInTheFuture() {
return new JWTClaimsSet.Builder()
.subject(clientId.toString())
@@ -358,6 +401,10 @@ public class ValidateEndpointAuthenticationTest {
.jwtID("mockId")
.build();
}
+
+ protected SignedJWT createSecretJWT(final JWTClaimsSet claimsSet) throws JOSEException {
+ return createSecretJWT(claimsSet, clientSecret.getValue());
+ }
protected SignedJWT createSecretJWT(final JWTClaimsSet claimsSet, final String clientSecret)
throws JOSEException {
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/JwtIdentifierClaimsValidatorTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/JwtIdentifierClaimsValidatorTest.java
new file mode 100644
index 00000000..7925aded
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/JwtIdentifierClaimsValidatorTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.security.jwt.claims.impl;
+
+import java.time.Instant;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.storage.ReplayCache;
+import org.opensaml.storage.impl.MemoryStorageService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+
+import net.shibboleth.oidc.jwt.claims.JWTValidationException;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/**
+ * Test for the {@link JwtIdentifierClaimsValidator}.
+ *
+ * TODO: temporarily here for the OIDC OP 3.0.3 patch. To be included in commons.
+ */
+public class JwtIdentifierClaimsValidatorTest {
+
+ /** The validator to test. */
+ private JwtIdentifierClaimsValidator validator;
+
+ @Nonnull private ProfileRequestContext prc;
+
+ @BeforeMethod
+ public void setup() throws ComponentInitializationException {
+ validator = new JwtIdentifierClaimsValidator();
+ ReplayCache replayCache = new ReplayCache();
+ MemoryStorageService storageService = new MemoryStorageService();
+ storageService.setId("mockId");
+ storageService.initialize();
+ replayCache.setStorage(storageService);
+ validator.setReplayCache(replayCache);
+ validator.setId("test-validator");
+ validator.initialize();
+ prc = new ProfileRequestContext();
+ }
+
+ @Test(expectedExceptions = ComponentInitializationException.class)
+ public void testNoReplayCache() throws ComponentInitializationException {
+ validator = new JwtIdentifierClaimsValidator();
+ validator.setId("test-validator");
+ validator.initialize();
+ }
+
+ @Test(expectedExceptions = JWTValidationException.class)
+ public void doValidateTest_failsWhenNoExp() throws JWTValidationException {
+ final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+ .jwtID("mockId")
+ .build();
+ validator.doValidate(claimsSet, prc);
+ }
+
+ @Test(expectedExceptions = JWTValidationException.class)
+ public void doValidateTest_failsWhenNoJit() throws JWTValidationException {
+ final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+ .expirationTime(Date.from(Instant.now().plusSeconds(300)))
+ .build();
+ validator.doValidate(claimsSet, prc);
+ }
+
+ @Test
+ public void doValidateTest_success() throws JWTValidationException {
+ final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+ .jwtID("mockId")
+ .expirationTime(Date.from(Instant.now().plusSeconds(300)))
+ .build();
+ validator.doValidate(claimsSet, prc);
+
+ }
+
+ @Test(expectedExceptions = JWTValidationException.class)
+ public void doValidateTest_failsWhenReplayed() throws JWTValidationException {
+ final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+ .jwtID("mockId")
+ .expirationTime(Date.from(Instant.now().plusSeconds(300)))
+ .build();
+ validator.doValidate(claimsSet, prc);
+ validator.doValidate(claimsSet, prc);
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list