[java-oidc-common] branch main updated: Generalize JWT signature checking, deprecate original methods.
Scott Cantor
cantor.2 at osu.edu
Wed Jan 26 19:44:53 UTC 2022
This is an automated email from the git hooks/post-receive script.
scantor 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=87c7a056346cb91d58c891fa6e533cd1d86070fb
The following commit(s) were added to refs/heads/main by this push:
new 87c7a05 Generalize JWT signature checking, deprecate original methods.
87c7a05 is described below
commit 87c7a056346cb91d58c891fa6e533cd1d86070fb
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jan 26 14:44:50 2022 -0500
Generalize JWT signature checking, deprecate original methods.
---
.../security/impl/JWTSignatureValidationUtil.java | 79 +++++++++++++++-------
.../impl/JWTSignatureValidationUtilTest.java | 69 ++++++++++++++++---
2 files changed, 112 insertions(+), 36 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 ea5ff4b..4aedef5 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
@@ -68,7 +68,10 @@ public final class JWTSignatureValidationUtil {
* @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.
+ *
+ * @deprecated
*/
+ @Deprecated(since="1.2.0", forRemoval=true)
@Nullable public static String validateSignature(@Nullable final SecurityParametersContext secParamCtx,
@Nonnull final SignedJWT signedJwt, @Nullable final String invalidJwtEventId) {
@@ -88,7 +91,7 @@ public final class JWTSignatureValidationUtil {
return EventIds.INVALID_SEC_CFG;
}
- return validateSignature(signatureValidationParameters.getValidationCredentials(),
+ return validateSignatureEx(signatureValidationParameters.getValidationCredentials(),
signedJwt, invalidJwtEventId);
}
@@ -97,39 +100,65 @@ public final class JWTSignatureValidationUtil {
* 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 credentials The list of {@link JWKCredential}s 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.
+ *
+ * @deprecated
*/
+ @Deprecated(since="1.2.0", forRemoval=true)
public static String validateSignature(@Nonnull final List<JWKCredential> credentials,
@Nonnull final SignedJWT signedJwt, @Nullable final String invalidJwtEventId) {
+ return validateSignatureEx(credentials, 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 Credential}s 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 validateSignatureEx(@Nonnull final List<? extends Credential> credentials,
+ @Nonnull final SignedJWT signedJwt, @Nullable final String invalidJwtEventId) {
final Algorithm algorithm = signedJwt.getHeader().getAlgorithm();
- final Iterator<?> it = credentials.iterator();
+ final Iterator<? extends Credential> it = credentials.iterator();
while (it.hasNext()) {
- final JWKCredential credential = (JWKCredential) it.next();
- if (!algorithm.equals(credential.getAlgorithm())) {
- log.debug("Credential alg {} not matching jwt header alg {}", credential.getAlgorithm().getName(),
- algorithm.getName());
- } else {
- try {
- final JWSVerifier verifier = initializeVerifier(algorithm, credential);
- if (verifier == null) {
- log.warn("No verifier for given JWT for alg {}", algorithm.getName());
- return EventIds.INVALID_SEC_CFG;
- }
- if (signedJwt.verify(verifier)) {
- log.debug("JWT {} verified using algorithm {} {}", signedJwt.serialize(),
+ final Credential credential = it.next();
+ if (credential instanceof JWKCredential && !algorithm.equals(((JWKCredential) credential).getAlgorithm())) {
+ log.debug("Credential alg {} not matching jwt header alg {}",
+ ((JWKCredential) credential).getAlgorithm().getName(), algorithm.getName());
+ continue;
+ }
+
+ try {
+ final JWSVerifier verifier = initializeVerifier(algorithm, credential);
+ if (verifier == null) {
+ log.debug("No verifier for given JWT and Credential pair for alg {}", algorithm.getName());
+ continue;
+ }
+ if (signedJwt.verify(verifier)) {
+ if (log.isDebugEnabled()) {
+ final String kid = credential instanceof JWKCredential ?
+ ((JWKCredential) credential).getKid() : null;
+ log.debug("JWT {} verified using algorithm {}{}", signedJwt.serialize(),
algorithm.getName(),
- credential.getKid() != null ? "and key " + credential.getKid() : "");
- return null;
+ kid != null ? " and key " + kid : "");
}
- log.debug("Unable to validate given JWT with credential, picking next key");
- } catch (final JOSEException | IllegalStateException e) {
- log.warn("Exception caught when validating given JWT {}",
- credential.getKid() != null ? "with credential " + credential.getKid() : "", e);
+ return null;
}
+ log.debug("Unable to validate given JWT with credential, picking next key");
+ } catch (final JOSEException | IllegalStateException e) {
+ final String kid = credential instanceof JWKCredential ?
+ ((JWKCredential) credential).getKid() : null;
+ log.warn("Exception caught when validating given JWT{}",
+ kid != null ? " with credential " + kid : "", e);
}
}
log.warn("Unable to validate given JWT with any of the credentials");
@@ -145,13 +174,13 @@ public final class JWTSignatureValidationUtil {
*/
private static JWSVerifier initializeVerifier(final Algorithm algorithm, final Credential credential)
throws JOSEException {
- if (JWSAlgorithm.Family.HMAC_SHA.contains(algorithm)) {
+ if (JWSAlgorithm.Family.HMAC_SHA.contains(algorithm) && credential.getSecretKey() != null) {
return new MACVerifier(credential.getSecretKey());
}
- if (JWSAlgorithm.Family.RSA.contains(algorithm)) {
+ if (JWSAlgorithm.Family.RSA.contains(algorithm) && credential.getPublicKey() instanceof RSAPublicKey) {
return new RSASSAVerifier((RSAPublicKey) credential.getPublicKey());
}
- if (JWSAlgorithm.Family.EC.contains(algorithm)) {
+ if (JWSAlgorithm.Family.EC.contains(algorithm) && credential.getPublicKey() instanceof ECPublicKey) {
return new ECDSAVerifier((ECPublicKey) credential.getPublicKey());
}
return null;
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 f645980..f4d7ed6 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
@@ -30,6 +30,8 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.opensaml.profile.action.EventIds;
+import org.opensaml.security.credential.BasicCredential;
+import org.opensaml.security.credential.Credential;
import org.opensaml.xmlsec.SignatureSigningParameters;
import org.opensaml.xmlsec.context.SecurityParametersContext;
import org.testng.Assert;
@@ -57,16 +59,24 @@ public class JWTSignatureValidationUtilTest {
final String invalidJwtEventId = "invalid_jwt";
BasicJWKCredential rsaCredential;
-
BasicJWKCredential ecCredential;
-
BasicJWKCredential sharedCredential;
+
+ BasicCredential rsaCredentialBasic;
+ BasicCredential ecCredentialBasic;
+
+ List<Credential> credentialList;
@BeforeClass
public void init() throws NoSuchAlgorithmException {
- rsaCredential = createKeyPairCredential("RSA", "RS256", "mockRSAKey", 2048);
- ecCredential = createKeyPairCredential("EC", "ES256", "mockECKey", 256);
+ rsaCredential = createJWKKeyPairCredential("RSA", "RS256", "mockRSAKey", 2048);
+ ecCredential = createJWKKeyPairCredential("EC", "ES256", "mockECKey", 256);
sharedCredential = createSharedSecretCredential("HS256", "mockSharedSecret");
+
+ rsaCredentialBasic = createBasicKeyPairCredential("RSA", 2048);
+ ecCredentialBasic = createBasicKeyPairCredential("EC", 256);
+
+ credentialList = List.of(rsaCredential, ecCredential, sharedCredential, rsaCredentialBasic, ecCredentialBasic);
}
@Test
@@ -97,7 +107,6 @@ public class JWTSignatureValidationUtilTest {
EventIds.INVALID_SEC_CFG);
}
-
@Test
public void validateSignature_shouldReturnNullWhenValidRSASignature()
throws JOSEException, ParseException, NoSuchAlgorithmException {
@@ -105,16 +114,31 @@ public class JWTSignatureValidationUtilTest {
Assert.assertNull(JWTSignatureValidationUtil.validateSignature(secCtx, signRSA(rsaCredential.getPrivateKey()),
invalidJwtEventId));
}
-
+
+ @Test
+ public void validateSignature_shouldReturnNullWhenValidRSASignatureEx()
+ throws JOSEException, ParseException, NoSuchAlgorithmException {
+ Assert.assertNull(JWTSignatureValidationUtil.validateSignatureEx(credentialList,
+ signRSA(rsaCredentialBasic.getPrivateKey()), invalidJwtEventId));
+ }
+
@Test
public void validateSignature_shouldReturnEventIdWhenInvalidRSASignature()
throws NoSuchAlgorithmException, JOSEException, ParseException {
- final BasicJWKCredential anotherRsaCredential = createKeyPairCredential("RSA", "RS256", "mockRSAKey2", 2048);
+ final BasicJWKCredential anotherRsaCredential = createJWKKeyPairCredential("RSA", "RS256", "mockRSAKey2", 2048);
final SecurityParametersContext secCtx = initSecurityParamsContext("RS256", rsaCredential);
Assert.assertEquals(JWTSignatureValidationUtil.validateSignature(secCtx,
signRSA(anotherRsaCredential.getPrivateKey()), invalidJwtEventId), invalidJwtEventId);
}
-
+
+ @Test
+ public void validateSignature_shouldReturnEventIdWhenInvalidRSASignatureEx()
+ throws NoSuchAlgorithmException, JOSEException, ParseException {
+ final BasicJWKCredential anotherRsaCredential = createJWKKeyPairCredential("RSA", "RS256", "mockRSAKey2", 2048);
+ Assert.assertEquals(JWTSignatureValidationUtil.validateSignatureEx(credentialList,
+ signRSA(anotherRsaCredential.getPrivateKey()), invalidJwtEventId), invalidJwtEventId);
+ }
+
@Test
public void validateSignature_shouldReturnNullWhenValidECSignature()
throws JOSEException, ParseException, NoSuchAlgorithmException {
@@ -123,15 +147,30 @@ public class JWTSignatureValidationUtilTest {
signEC((ECPrivateKey) ecCredential.getPrivateKey()), invalidJwtEventId));
}
+ @Test
+ public void validateSignature_shouldReturnNullWhenValidECSignatureEx()
+ throws JOSEException, ParseException, NoSuchAlgorithmException {
+ Assert.assertNull(JWTSignatureValidationUtil.validateSignatureEx(credentialList,
+ signEC((ECPrivateKey) ecCredentialBasic.getPrivateKey()), invalidJwtEventId));
+ }
+
@Test
public void validateSignature_shouldReturnEventIdWhenInvalidECSignature()
throws JOSEException, ParseException, NoSuchAlgorithmException {
- final BasicJWKCredential anotherEcCredential = createKeyPairCredential("EC", "ES256", "mockECKey2", 256);
+ final BasicJWKCredential anotherEcCredential = createJWKKeyPairCredential("EC", "ES256", "mockECKey2", 256);
SecurityParametersContext secCtx = initSecurityParamsContext("ES256", ecCredential);
Assert.assertEquals(JWTSignatureValidationUtil.validateSignature(secCtx,
signEC((ECPrivateKey) anotherEcCredential.getPrivateKey()), invalidJwtEventId), invalidJwtEventId);
}
+ @Test
+ public void validateSignature_shouldReturnEventIdWhenInvalidECSignatureEx()
+ throws JOSEException, ParseException, NoSuchAlgorithmException {
+ final BasicJWKCredential anotherEcCredential = createJWKKeyPairCredential("EC", "ES256", "mockECKey2", 256);
+ Assert.assertEquals(JWTSignatureValidationUtil.validateSignatureEx(credentialList,
+ signEC((ECPrivateKey) anotherEcCredential.getPrivateKey()), invalidJwtEventId), invalidJwtEventId);
+ }
+
@Test
public void validateSignature_shouldReturnNullWhenValidMACSignature() throws JOSEException, ParseException {
SecurityParametersContext secCtx = initSecurityParamsContext("HS256", sharedCredential);
@@ -180,7 +219,7 @@ public class JWTSignatureValidationUtilTest {
return SignedJWT.parse(jwsObject.serialize());
}
- protected BasicJWKCredential createKeyPairCredential(final String keyPairAlgorithm, final String jwsAlgorithm,
+ protected BasicJWKCredential createJWKKeyPairCredential(final String keyPairAlgorithm, final String jwsAlgorithm,
final String kid, final int keysize) throws NoSuchAlgorithmException {
final KeyPairGenerator generator = KeyPairGenerator.getInstance(keyPairAlgorithm);
generator.initialize(keysize);
@@ -193,7 +232,15 @@ public class JWTSignatureValidationUtilTest {
return credential;
}
-
+
+ protected BasicCredential createBasicKeyPairCredential(final String keyPairAlgorithm, final int keysize)
+ throws NoSuchAlgorithmException {
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance(keyPairAlgorithm);
+ generator.initialize(keysize);
+ final KeyPair keyPair = generator.generateKeyPair();
+ return new BasicCredential(keyPair.getPublic(), keyPair.getPrivate());
+ }
+
protected BasicJWKCredential createSharedSecretCredential(final String jwsAlgorithm, final String kid) {
final BasicJWKCredential credential = new BasicJWKCredential();
credential.setAlgorithm(JWSAlgorithm.parse(jwsAlgorithm));
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list