[java-oidc-common] branch main updated: Split signature validation API to accept a list of credentials

Phil Smart philip.smart at jisc.ac.uk
Fri Feb 5 12:12:03 UTC 2021


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

philsmart 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=977f490c30ffc30e3950b35a8fa5ccbd0ab61787

The following commit(s) were added to refs/heads/main by this push:
       new  977f490   Split signature validation API to accept a list of credentials
977f490 is described below

commit 977f490c30ffc30e3950b35a8fa5ccbd0ab61787
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Feb 5 12:12:00 2021 +0000

    Split signature validation API to accept a list of credentials
    
    In addition to an overloaded method with the existing security context.
---
 .../security/impl/JWTSignatureValidationUtil.java  | 49 +++++++++++++++++-----
 .../impl/JWTSignatureValidationUtilTest.java       | 26 +++++++++++-
 2 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtil.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtil.java
index 0f1d4a9..9b5efdf 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtil.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtil.java
@@ -20,8 +20,10 @@ package net.shibboleth.oidc.security.impl;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
 import java.util.Iterator;
+import java.util.List;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.security.credential.Credential;
@@ -52,19 +54,24 @@ public final class JWTSignatureValidationUtil {
     private JWTSignatureValidationUtil() {
 
     }
-
+    
+    
     /**
      * Validates the signature of the given JWT using the given security parameters context. If the validation fails for
      * any reason, including insufficient prequisities in the context, an event identifier is returned. Successful
-     * validation produces null result.
+     * validation produces a null result.
+     * 
+     * <p>Overloads {@link #validateSignature(SecurityParametersContext, SignedJWT, String)}, but with a 
+     * 'radically' different parameter.</p>
      * 
      * @param secParamCtx The {@link SecurityParametersContext} to use for signature validation.
      * @param signedJwt The signed JWT to be validated.
      * @param invalidJwtEventId The event identifier describing the invalid JWT.
-     * @return an event ID
+     * @return an event ID on failure, or {@literal null} if validation succeeds.
      */
-    public static String validateSignature(final SecurityParametersContext secParamCtx, final SignedJWT signedJwt,
-            final String invalidJwtEventId) {
+    @Nullable public static String validateSignature(@Nullable final SecurityParametersContext secParamCtx, 
+            @Nonnull final SignedJWT signedJwt, @Nullable final String invalidJwtEventId) {
+        
         if (secParamCtx == null) {
             log.error("No security parameters context is available");
             return EventIds.INVALID_SEC_CFG;
@@ -79,9 +86,27 @@ public final class JWTSignatureValidationUtil {
         if (signatureValidationParameters.getValidationCredentials().isEmpty()) {
             log.error("Unable to find any keys to validate given JWT signature");
             return EventIds.INVALID_SEC_CFG;            
-        }
+        }        
+        
+        return validateSignature(signatureValidationParameters.getValidationCredentials(), 
+                signedJwt, invalidJwtEventId);
+    }
+
+    /**
+     * Validates the signature of the given JWS against the given list of credentials. If the validation fails for
+     * any reason, including insufficient prequisities in the context, an event identifier is returned. Successful
+     * validation produces null result.
+     * 
+     * @param credentials The list of {@link JWKCredential credentials} to use for signature validation.
+     * @param signedJwt The signed JWT to be validated.
+     * @param invalidJwtEventId The event identifier describing the invalid JWT.
+     * @return an event ID on failure, or {@literal null} if validation succeeds.
+     */
+    public static String validateSignature(@Nonnull final List<JWKCredential> credentials,
+            @Nonnull final SignedJWT signedJwt, @Nullable final String invalidJwtEventId) {
+        
         final Algorithm algorithm = signedJwt.getHeader().getAlgorithm();
-        final Iterator<?> it = signatureValidationParameters.getValidationCredentials().iterator();
+        final Iterator<?> it = credentials.iterator();
         while (it.hasNext()) {
             final JWKCredential credential = (JWKCredential) it.next();
             if (!algorithm.equals(credential.getAlgorithm())) {
@@ -95,13 +120,15 @@ public final class JWTSignatureValidationUtil {
                         return EventIds.INVALID_SEC_CFG;
                     }
                     if (signedJwt.verify(verifier)) {
-                        log.debug("JWT {} verified using algorithm {} and key {}", signedJwt.serialize(),
-                                algorithm.getName(), credential.getKid());
+                        log.debug("JWT {} verified using algorithm {} {}", signedJwt.serialize(),
+                                algorithm.getName(), 
+                                credential.getKid() != null ? "and key " + credential.getKid() : "");
                         return null;
                     }
                     log.debug("Unable to validate given JWT with credential, picking next key");
-                } catch (final JOSEException e) {
-                    log.warn("Exception catched when validating given JWT with credential {}", credential.getKid(), e);
+                } catch (final JOSEException | IllegalStateException e) {
+                    log.warn("Exception caught when validating given JWT {}", 
+                            credential.getKid() != null ? "with credential " + credential.getKid() : "", e);
                 }
             }
         }
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtilTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtilTest.java
index 9a14434..f645980 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtilTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTSignatureValidationUtilTest.java
@@ -24,6 +24,7 @@ import java.security.PrivateKey;
 import java.security.SecureRandom;
 import java.security.interfaces.ECPrivateKey;
 import java.text.ParseException;
+import java.util.List;
 
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
@@ -70,7 +71,14 @@ public class JWTSignatureValidationUtilTest {
     
     @Test
     public void validateSignature_shouldReturnInvalidSecCfgWhenNoSecCtx() {
-        Assert.assertEquals(JWTSignatureValidationUtil.validateSignature(null, null, invalidJwtEventId),
+        Assert.assertEquals(JWTSignatureValidationUtil.validateSignature((SecurityParametersContext)null, null, invalidJwtEventId),
+                EventIds.INVALID_SEC_CFG);
+    }
+    
+    @Test
+    public void validateSignature_shouldReturnInvalidSecCfgWhenNoSecCtxObject() {
+        final SecurityParametersContext secContext = null;
+        Assert.assertEquals(JWTSignatureValidationUtil.validateSignature(secContext, null, invalidJwtEventId),
                 EventIds.INVALID_SEC_CFG);
     }
 
@@ -88,6 +96,7 @@ public class JWTSignatureValidationUtilTest {
         Assert.assertEquals(JWTSignatureValidationUtil.validateSignature(secCtx, null, invalidJwtEventId),
                 EventIds.INVALID_SEC_CFG);
     }
+   
 
     @Test
     public void validateSignature_shouldReturnNullWhenValidRSASignature()
@@ -137,6 +146,21 @@ public class JWTSignatureValidationUtilTest {
                 signMAC(generateSecretKey()), invalidJwtEventId), invalidJwtEventId);
         
     }
+    
+    @Test
+    public void validateSignature_credentialOnly_shouldReturnNullWhenValidMACSignature() 
+            throws JOSEException, ParseException {
+        Assert.assertNull(JWTSignatureValidationUtil.validateSignature(List.of(sharedCredential), 
+                signMAC(sharedCredential.getSecretKey()), invalidJwtEventId));
+    }
+
+    @Test
+    public void validateSignature_credentialOnly_shouldReturnEventIdWhenInvalidMACSignature() 
+            throws JOSEException, ParseException {
+        Assert.assertEquals(JWTSignatureValidationUtil.validateSignature(List.of(sharedCredential), 
+                signMAC(generateSecretKey()), invalidJwtEventId), invalidJwtEventId);
+        
+    }
 
     protected SignedJWT signRSA(final PrivateKey privateKey) throws JOSEException, ParseException {
         final JWSSigner signer = new RSASSASigner(privateKey);

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


More information about the commits mailing list