[java-idp-plugin-oidc-rp] branch main updated: Add nonce id_token validation if nonce present in authentication request
Phil Smart
philip.smart at jisc.ac.uk
Thu Feb 3 14:01:25 UTC 2022
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-rp.git;a=commit;h=e56b159d48b0ef135eb0073abdd7a17ad38573d3
The following commit(s) were added to refs/heads/main by this push:
new e56b159 Add nonce id_token validation if nonce present in authentication request
e56b159 is described below
commit e56b159d48b0ef135eb0073abdd7a17ad38573d3
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Feb 3 14:01:20 2022 +0000
Add nonce id_token validation if nonce present in authentication request
---
...henticationRequestNonceClaimLookupStrategy.java | 81 ++++++++++++++++++++++
.../impl/NonceValidationActivationCondition.java | 80 +++++++++++++++++++++
.../OIDCContextAudienceClaimLookupStrategy.java | 62 -----------------
.../rp/impl/OIDCIssuerClaimLookupStrategy.java | 68 ------------------
.../oidc-relying-party-authn-beans.xml | 45 ++++++------
.../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java | 3 +
6 files changed, 188 insertions(+), 151 deletions(-)
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthenticationRequestNonceClaimLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthenticationRequestNonceClaimLookupStrategy.java
new file mode 100644
index 0000000..7f38e72
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AuthenticationRequestNonceClaimLookupStrategy.java
@@ -0,0 +1,81 @@
+/*
+ * 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.authn.oidc.rp.impl;
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+
+import net.shibboleth.idp.authn.duo.context.DuoAuthenticationContext;
+import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Find the nonce from the {@link DuoAuthenticationContext}. Returns null if not found.
+ */
+ at ThreadSafe
+public final class AuthenticationRequestNonceClaimLookupStrategy
+ implements BiFunction<ProfileRequestContext,JWTClaimsSet, String> {
+
+ /** The strategy used to lookup the authentication request.*/
+ @Nonnull
+ private final Function<ProfileRequestContext, OIDCAuthenticationRequest> authenticationRequestLookupStrategy;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param strategy the lookup strategy to use
+ */
+ public AuthenticationRequestNonceClaimLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, OIDCAuthenticationRequest> strategy) {
+ authenticationRequestLookupStrategy =
+ Constraint.isNotNull(strategy, "Authentication request lookup strategy can not be null");
+ }
+
+ /** Constructor.*/
+ public AuthenticationRequestNonceClaimLookupStrategy() {
+ authenticationRequestLookupStrategy = prc -> {
+ final MessageContext messageContext = prc.getOutboundMessageContext();
+ if (messageContext != null &&
+ messageContext.getMessage() instanceof OIDCAuthenticationRequest) {
+ return (OIDCAuthenticationRequest)messageContext.getMessage();
+ }
+ return null;
+ };
+ }
+
+ @Override @Nullable public String apply(@Nonnull final ProfileRequestContext context,
+ @Nonnull final JWTClaimsSet cliams) {
+
+ final OIDCAuthenticationRequest request = authenticationRequestLookupStrategy.apply(context);
+ if (request == null) {
+ return null;
+ }
+ return request.getNonce().getValue();
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/NonceValidationActivationCondition.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/NonceValidationActivationCondition.java
new file mode 100644
index 0000000..5329631
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/NonceValidationActivationCondition.java
@@ -0,0 +1,80 @@
+/*
+ * 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.authn.oidc.rp.impl;
+
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+
+import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Determines if nonce validation should occur. True iff a nonce is present in the authentication request,
+ * false otherwise see section 3.1.3.7 of the OpenID Connect core 1.0 specification.
+ */
+ at ThreadSafe
+public class NonceValidationActivationCondition implements BiPredicate<ProfileRequestContext, JWTClaimsSet>{
+
+ /** The strategy used to lookup the authentication request.*/
+ @Nonnull
+ private final Function<ProfileRequestContext, OIDCAuthenticationRequest> authenticationRequestLookupStrategy;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param strategy the lookup strategy to use
+ */
+ public NonceValidationActivationCondition(
+ @Nonnull final Function<ProfileRequestContext, OIDCAuthenticationRequest> strategy) {
+ authenticationRequestLookupStrategy =
+ Constraint.isNotNull(strategy, "Authentication request lookup strategy can not be null");
+ }
+
+ /** Constructor.*/
+ public NonceValidationActivationCondition() {
+ // default is to pull out of the outbound message context
+ authenticationRequestLookupStrategy = prc -> {
+ final MessageContext messageContext = prc.getOutboundMessageContext();
+ if (messageContext != null &&
+ messageContext.getMessage() instanceof OIDCAuthenticationRequest) {
+ return (OIDCAuthenticationRequest)messageContext.getMessage();
+ }
+ return null;
+ };
+ }
+
+ @Override
+ public boolean test(@Nonnull final ProfileRequestContext context, @Nonnull final JWTClaimsSet claims) {
+
+ final OIDCAuthenticationRequest request = authenticationRequestLookupStrategy.apply(context);
+ if (request == null) {
+ return false;
+ }
+ return request.getNonce() != null;
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCContextAudienceClaimLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCContextAudienceClaimLookupStrategy.java
deleted file mode 100644
index c9069cc..0000000
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCContextAudienceClaimLookupStrategy.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.authn.oidc.rp.impl;
-
-import java.util.function.BiFunction;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-
-import com.nimbusds.jwt.JWTClaimsSet;
-import com.nimbusds.oauth2.sdk.id.ClientID;
-
-import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.OpenIDConnectContext;
-
-/**
- * Looks up the audience from the clientID in the {@link OpenIDConnectContext} inside the auth context.
- * Returns null if it fails to find the clientID. Used for JWT ID Token audience claims verification.
- */
- at ThreadSafe
-public final class OIDCContextAudienceClaimLookupStrategy
- implements BiFunction<ProfileRequestContext, JWTClaimsSet, String> {
-
- @Override @Nullable public String apply(@Nonnull final ProfileRequestContext context,
- @Nonnull final JWTClaimsSet cliams) {
-
- final AuthenticationContext authnContext = context.getSubcontext(AuthenticationContext.class);
- if (authnContext == null) {
- return null;
- }
-
- final OpenIDConnectContext oidcContext = authnContext.getSubcontext(OpenIDConnectContext.class);
- if (oidcContext == null) {
- return null;
- }
-
- final ClientID clientObject = oidcContext.getClientID();
- if (clientObject == null) {
- return null;
- }
- return clientObject.getValue();
- }
-
-}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCIssuerClaimLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCIssuerClaimLookupStrategy.java
deleted file mode 100644
index 69364c7..0000000
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCIssuerClaimLookupStrategy.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.authn.oidc.rp.impl;
-
-import java.util.function.BiFunction;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.opensaml.profile.context.ProfileRequestContext;
-
-import com.nimbusds.jwt.JWTClaimsSet;
-import com.nimbusds.oauth2.sdk.id.Issuer;
-import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
-
-import net.shibboleth.idp.authn.context.AuthenticationContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.OpenIDConnectContext;
-
-/**
- * Find the issuer from the OIDC metadata inside the {@link OpenIDConnectContext}. Returns null if not found.
- */
- at ThreadSafe
-public final class OIDCIssuerClaimLookupStrategy implements BiFunction<ProfileRequestContext, JWTClaimsSet, String> {
-
- /** {@inheritDoc} */
- @Override @Nullable public String apply(@Nonnull final ProfileRequestContext context,
- @Nonnull final JWTClaimsSet cliams) {
-
- final AuthenticationContext authnContext = context.getSubcontext(AuthenticationContext.class);
- if (authnContext == null) {
- return null;
- }
-
- final OpenIDConnectContext oidcContext = authnContext.getSubcontext(OpenIDConnectContext.class);
- if (oidcContext == null) {
- return null;
- }
-
- final OIDCProviderMetadata metadata = oidcContext.getoIDCProviderMetadata();
- if (metadata == null) {
- return null;
- }
-
- final Issuer issuer = metadata.getIssuer();
- if (issuer == null) {
- return null;
- }
-
- return issuer.getValue();
- }
-
-}
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
index e78d544..a8f2a01 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
@@ -366,18 +366,35 @@
</property>
</bean>
+ <bean id="nonceClaimValidator"
+ class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator"
+ p:claimName="nonce"
+ p:valueToMatchLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceLookupStrategy') ?:
+ getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy')}"
+ p:activationCondition="#{getObject('shibboleth.authn.oidc.rp.jwt.NonceActivationCondition') ?:
+ getObject('shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition')}"/>
+
+ <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.NonceValidationActivationCondition"/>
+
+ <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.AuthenticationRequestNonceClaimLookupStrategy"/>
+
+
<bean id="OIDCMetadataContextChildLookup"
class="org.opensaml.messaging.context.navigate.ChildContextLookup"
c:type="#{ T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext) }" />
<util:list id="ClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
- <ref bean="ExpiryClaimsValidator" />
- <ref bean="NotBeforeClaimsValidator" />
+ <ref bean="IssuerClaimsValidator" /> <!-- TODO prevent: if it contains additional audiences not trusted by the Client. -->
+ <ref bean="AudienceClaimsValidator" />
<ref bean="AzpClaimRequiredValidator"/>
- <ref bean="AzpClaimsValidator"/>
+ <ref bean="AzpClaimsValidator"/>
+ <ref bean="ExpiryClaimsValidator" />
<ref bean="IssuedAtClaimsValidator" />
- <ref bean="IssuerClaimsValidator" /> <!-- TODO prevent: if it contains additional audiences not trusted by the Client. -->
- <ref bean="AudienceClaimsValidator" />
+ <ref bean="NotBeforeClaimsValidator" />
+ <ref bean="nonceClaimValidator" />
+ <!-- missing ACR? nonce, and auth_time, access_token at_hash. -->
</util:list>
@@ -396,7 +413,7 @@
</bean>
<!-- Populate RP UI info from metadata? -->
- <util:constant id="shibboleth.authn.oidc.rp.populateUIInfo" static-field="java.lang.Boolean.FALSE" />
+
<bean id="ValidateIDTokenSignature"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateIDTokenSignature" />
@@ -407,21 +424,7 @@
<bean id="shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeActivationCondition"
class="net.shibboleth.oidc.security.jwt.claims.impl.ForcedAuthenticationActivationCondition"/>
-
- <bean id="shibboleth.authn.oidc.rp.jwt.DefaultAuthTimeRequested"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.OIDCAuthenticationTimeRequested"/>
-
- <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceActivationCondition"
- class="net.shibboleth.oidc.security.jwt.claims.impl.NonceValidationActivationCondition"/>
-
- <bean id="shibboleth.authn.oidc.rp.jwt.DefaultIssuerLookupStrategy"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.OIDCIssuerClaimLookupStrategy"/>
- <!--
- <bean id="shibboleth.authn.oidc.rp.jwt.DefaultNonceLookupStrategy"
- class="net.shibboleth.idp.plugin.authn.duo.impl.DuoNonceClaimLookupStrategy"/>
- -->
- <bean id="shibboleth.authn.oidc.rp.jwt.DefaultAudienceLookupStrategy"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.OIDCContextAudienceClaimLookupStrategy"/>
+
<!-- These represent the default set of id_token claims which are **required** by OIDC
https://openid.net/specs/openid-connect-core-1_0.html#IDToken -->
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
index c78dd11..ca6bd64 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
@@ -65,6 +65,7 @@ import com.nimbusds.oauth2.sdk.ResponseType;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.id.State;
import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser;
+import com.nimbusds.openid.connect.sdk.Nonce;
import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
@@ -282,6 +283,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
.issuer("https://op.example.com")
.audience(List.of("demo_rp","demo_rp2"))
.subject("jdoe")
+ .claim("nonce", "abadnonce")
.claim("azp", "demo_rp")
.expirationTime(Date.from(Instant.now().plusSeconds(120)))
.build();
@@ -370,6 +372,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
final MessageContext outMsgCtx = new MessageContext();
final OIDCAuthenticationRequest request = new OIDCAuthenticationRequest(new ClientID("https://op.example.com"));
request.setState(new State("8df98fd63a53fa5b5433d6f8754bca5d.65317332"));
+ request.setNonce(new Nonce("abadnonce"));
outMsgCtx.setMessage(request);
final OIDCPeerEntityContext peerCtx = new OIDCPeerEntityContext();
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list