[java-idp-plugin-oidc-rp] branch main updated: Add access token hash validation
Phil Smart
philip.smart at jisc.ac.uk
Thu Dec 1 10:57:54 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=2832ca64987e49d8a104866bbe14178c2d7af001
The following commit(s) were added to refs/heads/main by this push:
new 2832ca6 Add access token hash validation
2832ca6 is described below
commit 2832ca64987e49d8a104866bbe14178c2d7af001
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Dec 1 10:57:51 2022 +0000
Add access token hash validation
---
.../navigate/IDTokenJOSEHeaderLookupStrategy.java | 76 ++++++++++++++++++++++
.../navigate/RawTokenResponseLookupStrategy.java | 70 ++++++++++++++++++++
.../oidc-relying-party-authn-beans.xml | 17 ++++-
.../authn/oidc/rp/conf/authn/oidc-rp.properties | 7 +-
4 files changed, 166 insertions(+), 4 deletions(-)
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenJOSEHeaderLookupStrategy.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenJOSEHeaderLookupStrategy.java
new file mode 100644
index 0000000..4f129fb
--- /dev/null
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/IDTokenJOSEHeaderLookupStrategy.java
@@ -0,0 +1,76 @@
+/*
+ * 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.config.navigate;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+
+import com.nimbusds.jose.Header;
+import com.nimbusds.jose.JWSHeader;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.AccessTokenResponseContext;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Function that extracts the JWS JOSE header from the id_token inside the {@link AccessTokenResponseContext}.*/
+ at ThreadSafe
+public class IDTokenJOSEHeaderLookupStrategy implements Function<ProfileRequestContext, JWSHeader> {
+
+ /** Strategy used to locate the {@link AccessTokenResponseContext} to extract the id_token from.*/
+ @Nonnull
+ private final Function<ProfileRequestContext, AccessTokenResponseContext> tokenResponseContextLookupStrategy;
+
+ /** Constructor.*/
+ public IDTokenJOSEHeaderLookupStrategy() {
+ tokenResponseContextLookupStrategy =
+ new ChildContextLookup<>(AccessTokenResponseContext.class, true).compose(
+ new InboundMessageContextLookup());
+ }
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param strategy the AccessTokenResponseContext lookup strategy to use.
+ */
+ public IDTokenJOSEHeaderLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, AccessTokenResponseContext> strategy) {
+ tokenResponseContextLookupStrategy =
+ Constraint.isNotNull(strategy, "AccessTokenResponseContext lookup strategy can not be null");
+ }
+
+ @Override
+ @Nullable public JWSHeader apply(@Nonnull final ProfileRequestContext prc) {
+ final AccessTokenResponseContext tokenContext = tokenResponseContextLookupStrategy.apply(prc);
+ if (tokenContext == null || tokenContext.getIdToken() == null) {
+ return null;
+ }
+ final Header header = tokenContext.getIdToken().getHeader();
+ if (header instanceof JWSHeader) {
+ return (JWSHeader) header;
+ }
+ return null;
+ }
+
+}
diff --git a/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/RawTokenResponseLookupStrategy.java b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/RawTokenResponseLookupStrategy.java
new file mode 100644
index 0000000..b62c8bd
--- /dev/null
+++ b/idp-oidc-rp-api/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/config/navigate/RawTokenResponseLookupStrategy.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate;
+
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.AccessTokenResponseContext;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Function that extracts the raw token response from the {@link AccessTokenResponseContext}.*/
+ at ThreadSafe
+public class RawTokenResponseLookupStrategy implements Function<ProfileRequestContext, Map<String, Object>> {
+
+ /** Strategy used to locate the {@link AccessTokenResponseContext} to extract the id_token from.*/
+ @Nonnull
+ private final Function<ProfileRequestContext, AccessTokenResponseContext> tokenResponseContextLookupStrategy;
+
+ /** Constructor.*/
+ public RawTokenResponseLookupStrategy() {
+ tokenResponseContextLookupStrategy =
+ new ChildContextLookup<>(AccessTokenResponseContext.class, true).compose(
+ new InboundMessageContextLookup());
+ }
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param strategy the AccessTokenResponseContext lookup strategy to use.
+ */
+ public RawTokenResponseLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext, AccessTokenResponseContext> strategy) {
+ tokenResponseContextLookupStrategy =
+ Constraint.isNotNull(strategy, "AccessTokenResponseContext lookup strategy can not be null");
+ }
+
+ @Override
+ @Nullable public Map<String, Object> apply(@Nonnull final ProfileRequestContext prc) {
+ final AccessTokenResponseContext tokenContext = tokenResponseContextLookupStrategy.apply(prc);
+ if (tokenContext == null) {
+ return null;
+ }
+ return tokenContext.getRawTokenResponse();
+ }
+
+}
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 9c21aae..45fda2e 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
@@ -648,6 +648,19 @@
<bean id="OIDCPeerEntityContextChildLookup" class="org.opensaml.messaging.context.navigate.ChildContextLookup"
c:type="#{ T(net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext) }" />
+
+ <bean id="AtHashValidator" class="net.shibboleth.oidc.security.jwt.claims.impl.AccessTokenHashValidator"
+ p:allowMissing="%{idp.authn.oidc.rp.client.tokenresponse.allowMissingAtHash:true}"
+ p:tokenResponseLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.TokenResponseLookupStrategy') ?:
+ getObject('shibboleth.authn.oidc.rp.jwt.DefaultTokenResponseLookupStrategy')}"
+ p:joseHeaderLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.jwt.IDTokenJOSEHeaderLookupStrategy') ?:
+ getObject('shibboleth.authn.oidc.rp.jwt.DefaultIDTokenJOSEHeaderLookupStrategy')}"/>
+
+ <bean id="shibboleth.authn.oidc.rp.jwt.DefaultTokenResponseLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.RawTokenResponseLookupStrategy"/>
+
+ <bean id="shibboleth.authn.oidc.rp.jwt.DefaultIDTokenJOSEHeaderLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.IDTokenJOSEHeaderLookupStrategy"/>
<util:list id="IDTokenClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
<ref bean="IDTokenRequiredClaimsValidator" />
@@ -659,8 +672,8 @@
<ref bean="IssuedAtClaimsValidator" />
<ref bean="NotBeforeClaimsValidator" />
<ref bean="NonceClaimValidator" />
- <!-- missing ACR? and auth_time, access_token at_hash. -->
- <!-- TODO at_hash if contained in id_token should exact match (via some steps) a derivation of the access_token -->
+ <ref bean="AtHashValidator"/>
+ <!-- missing ACR? and auth_time -->
</util:list>
diff --git a/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/oidc-rp.properties b/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/oidc-rp.properties
index 188f1b7..62786c7 100644
--- a/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/oidc-rp.properties
+++ b/idp-oidc-rp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/oidc/rp/conf/authn/oidc-rp.properties
@@ -20,9 +20,12 @@ idp.authn.oidc.rp.client.redirecturl.allowedOrigins = https://localhost:8443
#idp.authn.oidc.rp.client.idtoken.tlsServerValidationOnly = false
#idp.authn.oidc.rp.client.userinfo.enabled = true
-#idp.authn.oidc.rp.client.userinfo.requireJWTResponse = false
-## Use small fetch interval so we can re-run tests against the certification OP
+## Should validation be skipped if the at_hash is not present in the id_token response. Defaults to 'true' as
+## access token at_hash validation is optional in the Authorization Code Flow.
+#idp.authn.oidc.rp.client.tokenresponse.allowMissingAtHash = true
+
+## The OP's keyset document fetch interval i.e. how long should keys from the OP be cached.
#idp.authn.oidc.rp.provider.keyfetch.interval = PT30M
## Override the default response_mode for the given response_type
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list