[java-oidc-common] branch main updated: JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons

Henri Mikkonen henri.mikkonen at iki.fi
Fri Feb 3 12:59:10 UTC 2023


This is an automated email from the git hooks/post-receive script.

hjmikkon pushed a commit to branch main
in repository java-oidc-common.

View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=be3a5fbda22c06cfdba55f591f066ba637ca1abd

The following commit(s) were added to refs/heads/main by this push:
     new be3a5fb  JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons
be3a5fb is described below

commit be3a5fbda22c06cfdba55f591f066ba637ca1abd
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Feb 3 14:56:08 2023 +0200

    JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-41
    
    Added a new JWT signature security handler that can be used for verifying the signature
    algorithm to be as expected in the client information.
    
    This is supposed to make ClientInformationJWTTrustEngine obsolete and we can use the
    same ExplicitKeySignedJWTTrustEngine for both OP's and RP's puposes. TrustEngine is
    expected to verify the signature and the algorithm against the profile configuration,
    but this handler verifies the algorithm against the (runtime) RP metadata.
---
 .../impl/BaseJWTSignatureSecurityHandler.java      |   4 +-
 ...mationJWTSignatureAlgorithmSecurityHandler.java | 168 +++++++++++++++++++++
 2 files changed, 170 insertions(+), 2 deletions(-)

diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
index aea6f45..d9c4c0d 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
@@ -82,10 +82,10 @@ public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSec
     @Nullable private OIDCAuthorizationConfiguration profileConfiguration;
     
     /** The provider metadata found from the lookup strategy.*/
-    @Nullable private OIDCProviderMetadata providerMetadata;
+    @Nullable protected OIDCProviderMetadata providerMetadata;
 
     /** The client information found from the lookup strategy. */
-    @Nullable private OIDCClientInformation clientInformation;
+    @Nullable protected OIDCClientInformation clientInformation;
 
     /** Constructor.*/
     protected BaseJWTSignatureSecurityHandler() {
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ClientInformationJWTSignatureAlgorithmSecurityHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ClientInformationJWTSignatureAlgorithmSecurityHandler.java
new file mode 100644
index 0000000..9fee52c
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ClientInformationJWTSignatureAlgorithmSecurityHandler.java
@@ -0,0 +1,168 @@
+/*
+ * 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.oidc.security.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandler;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+
+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;
+
+/**
+ * A {@link MessageHandler} that uses a {@link OIDCClientInformation} to verify the signature of a signed JWT uses
+ * expected algorithm.
+ */
+public class ClientInformationJWTSignatureAlgorithmSecurityHandler extends BaseJWTSignatureSecurityHandler {
+    
+    /** Logger. */
+    @Nonnull private final Logger log =
+            LoggerFactory.getLogger(ClientInformationJWTSignatureAlgorithmSecurityHandler.class);
+    
+    /** Function that looks up a signed JWT token from the given message context to validate .*/
+    @NonnullAfterInit private Function<MessageContext, SignedJWT> jwtTokenLookupStrategy;
+
+    /** A lookup function for the signature algorithm in the client metadata. */
+    @NonnullAfterInit private Function<OIDCClientInformation, String> signatureAlgorithmLookupStrategy;
+
+    /** The extracted signed JWT that is to be validated.*/
+    @Nullable private SignedJWT signedJwt;
+    
+    /** The default algorithm value used if lookup strategy returned null. */
+    @Nullable private String defaultAlgorithmValue;
+
+    /**
+     * Set the strategy used to look up a {@link SignedJWT}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setJwtTokenLookupStrategy(
+            @Nonnull final Function<MessageContext, SignedJWT> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        jwtTokenLookupStrategy = Constraint.isNotNull(strategy,
+                "JwtToken lookup strategy cannot be null");
+    }
+
+    /**
+     * Set the strategy used to look up the signature algorithm in the client metadata.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setSignatureAlgorithmLookupStrategy(
+            @Nonnull final Function<OIDCClientInformation, String> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        signatureAlgorithmLookupStrategy = Constraint.isNotNull(strategy,
+                "Signature algorithm lookup strategy cannot be null");
+    }
+
+    /**
+     * Set the default algorithm value used if lookup strategy returned null.
+     * 
+     * @param value default value
+     */
+    public void setDefaultAlgorithmValue(@Nullable final String value) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        defaultAlgorithmValue = StringSupport.trimOrNull(value);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (jwtTokenLookupStrategy == null) {
+            throw new ComponentInitializationException("JwtTokenLookupStrategy cannot be null");
+        }
+        if (signatureAlgorithmLookupStrategy == null) {
+            throw new ComponentInitializationException("SignatureAlgorithmLookupStrategy cannot be null");            
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreInvoke(final MessageContext messageContext) throws MessageHandlerException {  
+        if (!super.doPreInvoke(messageContext)) {
+            return false;
+        }
+        
+        signedJwt = jwtTokenLookupStrategy.apply(messageContext);
+        if (signedJwt == null) {
+            log.debug("{} Extracted JWT was not a SignedJWT, cannot process signature",
+                    getLogPrefix());
+            throw new MessageHandlerException("Signed JWT was missing or unpopulated");
+        }
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInvoke(final MessageContext messageContext) throws MessageHandlerException {
+        final String tokenAlgorithm = signedJwt.getHeader().getAlgorithm().getName();
+        final String expectedAlgorithm = getExpectedAlgorithm(clientInformation);
+
+        if (expectedAlgorithm == null) {
+            log.debug("No expected algorithm defined, accepting {} from the token", tokenAlgorithm);
+            return;
+        }
+        if (tokenAlgorithm.equals(expectedAlgorithm)) {
+            log.debug("The algorithnm specified in the token was expected {}", tokenAlgorithm);
+            return;
+        }
+        log.warn("The algorithnm specified in the token {} was not expected {}", tokenAlgorithm, expectedAlgorithm);
+        throw new MessageHandlerException("Validation of JWS failed. The algorithm " + tokenAlgorithm + 
+                " was not the expected " + expectedAlgorithm);
+    }
+
+    /**
+     * Fetches the expected signature algorithm from the {@link OIDCClientInformation}.
+     * 
+     * @param clientInformation the client information/metadata.
+     * @return the expected algorithm value.
+     */
+    @Nullable protected String getExpectedAlgorithm(@Nullable final OIDCClientInformation clientInformation) {
+        if (clientInformation != null) {
+            final String storedAlgorithm = signatureAlgorithmLookupStrategy.apply(clientInformation);
+            if (StringSupport.trimOrNull(storedAlgorithm) == null) {
+                log.debug("No algorithm value specified in metadata, using default value {}", defaultAlgorithmValue);
+                return defaultAlgorithmValue;
+            } else {
+                log.debug("Found the expected algorithm from metadata: {}", storedAlgorithm);
+                return storedAlgorithm;
+            }
+        } else {
+            log.debug("No client information found, using default value {}", defaultAlgorithmValue);
+            return defaultAlgorithmValue;
+        }
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list