From 3dfe6df41069a8e24ea17f78c13a3418fa22eeb2 Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Mon, 2 Apr 2012 13:13:13 -0400 Subject: [PATCH] refactored algorithms out to their own separate Enum --- .../org/mitre/jwt/signer/JwsAlgorithm.java | 64 +++++++++++++++ .../mitre/jwt/signer/impl/EcdsaSigner.java | 70 ++-------------- .../org/mitre/jwt/signer/impl/HmacSigner.java | 82 +++---------------- .../jwt/signer/impl/PlaintextSigner.java | 1 + .../org/mitre/jwt/signer/impl/RsaSigner.java | 75 ++--------------- .../src/test/java/org/mitre/jwt/JwtTest.java | 33 +++----- 6 files changed, 102 insertions(+), 223 deletions(-) create mode 100644 openid-connect-server/src/main/java/org/mitre/jwt/signer/JwsAlgorithm.java diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/JwsAlgorithm.java b/openid-connect-server/src/main/java/org/mitre/jwt/signer/JwsAlgorithm.java new file mode 100644 index 000000000..12dc4183c --- /dev/null +++ b/openid-connect-server/src/main/java/org/mitre/jwt/signer/JwsAlgorithm.java @@ -0,0 +1,64 @@ +package org.mitre.jwt.signer; + +import org.apache.commons.lang.StringUtils; + +/** + * Enum to translate between the JWS defined algorithm names and the JSE algorithm names + * + * @author jricher + * + */ +public enum JwsAlgorithm { + + // HMAC + HS256("HMACSHA256"), + HS384("HMACSHA384"), + HS512("HMACSHA512"), + // RSA + RS256("SHA256withRSA"), + RS384("SHA384withRSA"), + RS512("SHA512withRSA"), + // ECDSA + ES256("SHA256withECDSA"), + ES384("SHA384withECDSA"), + ES512("SHA512withECDSA"); + + + /** + * Returns the Algorithm for the name + * + * @param name + * @return + */ + public static JwsAlgorithm getByName(String name) { + for (JwsAlgorithm correspondingType : JwsAlgorithm.values()) { + if (correspondingType.toString().equals(name)) { + return correspondingType; + } + } + + // corresponding type not found + throw new IllegalArgumentException( + "JwsAlgorithm name " + name + " does not have a corresponding JwsAlgorithm: expected one of [" + StringUtils.join(JwsAlgorithm.values(), ", ") + "]"); + } + + private final String standardName; + + /** + * Constructor of JwsAlgorithm + * + * @param standardName + */ + JwsAlgorithm(String standardName) { + this.standardName = standardName; + } + + /** + * Return the Java standard JwsAlgorithm name + * + * @return + */ + public String getStandardName() { + return standardName; + } +} diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/EcdsaSigner.java b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/EcdsaSigner.java index c177bed19..5230c40ba 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/EcdsaSigner.java +++ b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/EcdsaSigner.java @@ -9,10 +9,10 @@ import java.security.Signature; import java.util.List; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mitre.jwt.signer.AbstractJwtSigner; +import org.mitre.jwt.signer.JwsAlgorithm; import org.mitre.jwt.signer.service.impl.KeyStore; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; @@ -30,60 +30,6 @@ import com.google.common.collect.Lists; */ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean { - /** - * an enum for mapping a JWS name to standard algorithm name - * - * @author nemonik - * - */ - public enum Algorithm { - - // Algorithm constants - ES256("SHA256withECDSA"), ES384("SHA384withECDSA"), ES512( - "SHA512withECDSA"); - - public static final String DEFAULT = Algorithm.ES256.toString(); - public static final String PREPEND = "ES"; - - /** - * Returns the Algorithm for the name - * - * @param name - * @return - */ - public static Algorithm getByName(String name) { - for (Algorithm correspondingType : Algorithm.values()) { - if (correspondingType.toString().equals(name)) { - return correspondingType; - } - } - - // corresponding type not found - throw new IllegalArgumentException( - "Algorithm name " + name + " does not have a corresponding Algorithm: expected one of [" + StringUtils.join(Algorithm.values(), ", ") + "]"); - } - - private final String standardName; - - /** - * Constructor of Algorithm - * - * @param standardName - */ - Algorithm(String standardName) { - this.standardName = standardName; - } - - /** - * Return the Java standard algorithm name - * - * @return - */ - public String getStandardName() { - return standardName; - } - }; - private static Log logger = LogFactory.getLog(EcdsaSigner.class); public static final String KEYPAIR_ALGORITHM = "EC"; @@ -97,11 +43,14 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean { private PublicKey publicKey; private Signature signer; + public static final String DEFAULT_ALGORITHM = JwsAlgorithm.ES256.toString(); + //public static final String PREPEND = "ES"; + /** * Default constructor */ public EcdsaSigner() { - super(Algorithm.DEFAULT); + super(DEFAULT_ALGORITHM); } /** @@ -167,8 +116,7 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean { * @param privateKey * The private key */ - public EcdsaSigner(String algorithmName, PublicKey publicKey, - PrivateKey privateKey) { + public EcdsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) { super(algorithmName); Assert.notNull(publicKey, "A publicKey must be supplied"); @@ -188,11 +136,9 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean { public void afterPropertiesSet() throws Exception { // Can throw a GeneralException - signer = Signature.getInstance(Algorithm.getByName(super.getAlgorithm()) - .getStandardName()); // PROVIDER); + signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); // PROVIDER); - logger.debug(Algorithm.getByName(getAlgorithm()).getStandardName() - + " ECDSA Signer ready for business"); + logger.debug(JwsAlgorithm.getByName(getAlgorithm()).getStandardName() + " ECDSA Signer ready for business"); } /* (non-Javadoc) diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java index b884ff922..91fadf99c 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java +++ b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java @@ -4,16 +4,15 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mitre.jwt.signer.AbstractJwtSigner; +import org.mitre.jwt.signer.JwsAlgorithm; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; @@ -25,65 +24,9 @@ import org.springframework.util.Assert; */ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { - /** - * an enum for mapping a JWS name to standard algorithm name - * - * @author nemonik - * - */ - public enum Algorithm { + public static final String DEFAULT_PASSPHRASE = "changeit"; - // Algorithm constants - HS256("HMACSHA256"), HS384("HMACSHA384"), HS512("HMACSHA512"); - - public static final String DEFAULT = Algorithm.HS256.toString(); - - /** - * Returns the Algorithm for the name - * - * @param name - * @return - */ - public static Algorithm getByName(String name) { - - for (Algorithm correspondingType : Algorithm.values()) { - if (correspondingType.toString().equals(name)) { - return correspondingType; - } - } - - ArrayList longValues = new ArrayList(); - for (Algorithm v : Algorithm.values()) { - longValues.add(v.standardName); - } - - // corresponding type not found - throw new IllegalArgumentException( - "Algorithm name " + name + " does not have a corresponding Algorithm: expected one of [" + StringUtils.join(Algorithm.values(), ", ") + "]"); - } - - private final String standardName; - - /** - * Constructor of Algorithm - * - * @param standardName - */ - Algorithm(String standardName) { - this.standardName = standardName; - } - - /** - * Return the Java standard algorithm name - * - * @return - */ - public String getStandardName() { - return standardName; - } - } - - public static final String DEFAULT_PASSPHRASE = "changeit";; + public static final String DEFAULT_ALGORITHM = JwsAlgorithm.HS256.toString(); private static Log logger = LogFactory.getLog(HmacSigner.class); @@ -95,7 +38,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { * Default constructor */ public HmacSigner() { - super(Algorithm.DEFAULT); + super(DEFAULT_ALGORITHM); } /** @@ -106,8 +49,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { */ public HmacSigner(byte[] passphraseAsRawBytes) throws NoSuchAlgorithmException { - this(Algorithm.DEFAULT, new String(passphraseAsRawBytes, - Charset.forName("UTF-8"))); + this(DEFAULT_ALGORITHM, new String(passphraseAsRawBytes, Charset.forName("UTF-8"))); } /** @@ -117,7 +59,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { * The passphrase as raw bytes */ public HmacSigner(String passphrase) throws NoSuchAlgorithmException { - this(Algorithm.DEFAULT, passphrase); + this(DEFAULT_ALGORITHM, passphrase); } /** @@ -130,8 +72,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { */ public HmacSigner(String algorithmName, byte[] passphraseAsRawBytes) throws NoSuchAlgorithmException { - this(algorithmName, new String(passphraseAsRawBytes, - Charset.forName("UTF-8"))); + this(algorithmName, new String(passphraseAsRawBytes, Charset.forName("UTF-8"))); } /** @@ -160,11 +101,9 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { - mac = Mac.getInstance(Algorithm.getByName(super.getAlgorithm()) - .getStandardName()); + mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); - logger.debug(Algorithm.getByName(getAlgorithm()).getStandardName() - + " ECDSA Signer ready for business"); + logger.debug(JwsAlgorithm.getByName(getAlgorithm()).getStandardName() + " ECDSA Signer ready for business"); } @@ -182,8 +121,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { } try { - mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac - .getAlgorithm())); + mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac.getAlgorithm())); mac.update(signatureBase.getBytes("UTF-8")); } catch (GeneralSecurityException e) { diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java index 4bd4a849d..59b7d02d3 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java +++ b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java @@ -4,6 +4,7 @@ import org.mitre.jwt.signer.AbstractJwtSigner; public class PlaintextSigner extends AbstractJwtSigner { + // Todo: should this be a JwsAlgorithm? public static final String PLAINTEXT = "none"; public PlaintextSigner() { diff --git a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java index 358c1bb23..00ac40c7f 100644 --- a/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java +++ b/openid-connect-server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java @@ -10,10 +10,10 @@ import java.security.interfaces.RSAPrivateKey; import java.util.List; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mitre.jwt.signer.AbstractJwtSigner; +import org.mitre.jwt.signer.JwsAlgorithm; import org.mitre.jwt.signer.service.impl.KeyStore; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; @@ -29,64 +29,13 @@ import com.google.common.collect.Lists; */ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { - /** - * an enum for mapping a JWS name to standard algorithm name - * - * @author nemonik - * - */ - public enum Algorithm { - - // Algorithm constants - RS256("SHA256withRSA"), RS384("SHA384withRSA"), RS512("SHA512withRSA"); - - public static final String DEFAULT = Algorithm.RS256.toString(); - public static final String PREPEND = "RS"; - - /** - * Returns the Algorithm for the name - * - * @param name - * @return - */ - public static Algorithm getByName(String name) { - for (Algorithm correspondingType : Algorithm.values()) { - if (correspondingType.toString().equals(name)) { - return correspondingType; - } - } - - // corresponding type not found - throw new IllegalArgumentException( - "Algorithm name " + name + " does not have a corresponding Algorithm: expected one of [" + StringUtils.join(Algorithm.values(), ", ") + "]"); - } - - private final String standardName; - - /** - * Constructor of Algorithm - * - * @param standardName - */ - Algorithm(String standardName) { - this.standardName = standardName; - } - - /** - * Return the Java standard algorithm name - * - * @return - */ - public String getStandardName() { - return standardName; - } - }; - private static Log logger = LogFactory.getLog(RsaSigner.class); public static final String KEYPAIR_ALGORITHM = "RSA"; public static final String DEFAULT_PASSWORD = "changeit"; + public static final String DEFAULT_ALGORITHM = JwsAlgorithm.RS256.toString(); + private KeyStore keystore; private String alias; private String password = DEFAULT_PASSWORD; @@ -99,7 +48,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { * Default constructor */ public RsaSigner() { - super(Algorithm.DEFAULT); + super(DEFAULT_ALGORITHM); } /** @@ -135,8 +84,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { * The password used to access and retrieve the key pair. * @throws GeneralSecurityException */ - public RsaSigner(String algorithmName, KeyStore keystore, String alias, - String password) throws GeneralSecurityException { + public RsaSigner(String algorithmName, KeyStore keystore, String alias, String password) throws GeneralSecurityException { super(algorithmName); Assert.notNull(keystore, "An keystore must be supplied"); @@ -166,8 +114,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { * @param privateKey * The private key */ - public RsaSigner(String algorithmName, PublicKey publicKey, - PrivateKey privateKey) { + public RsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) { super(algorithmName); Assert.notNull(publicKey, "An publicKey must be supplied"); @@ -187,12 +134,9 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public void afterPropertiesSet() throws Exception { // unsupported algorithm will throw a NoSuchAlgorithmException - signer = Signature.getInstance(Algorithm - .getByName(super.getAlgorithm()).getStandardName()); // , - // PROVIDER); + signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); // ,PROVIDER); - logger.debug(Algorithm.getByName(getAlgorithm()).getStandardName() - + " RSA Signer ready for business"); + logger.debug(JwsAlgorithm.getByName(getAlgorithm()).getStandardName() + " RSA Signer ready for business"); } @@ -214,8 +158,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { byte[] sigBytes = signer.sign(); - sig = (new String(Base64.encodeBase64URLSafe(sigBytes))).replace( - "=", ""); + sig = (new String(Base64.encodeBase64URLSafe(sigBytes))).replace("=", ""); } catch (GeneralSecurityException e) { logger.error(e); } catch (UnsupportedEncodingException e) { diff --git a/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java b/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java index 895fee7fc..165e1ce4d 100644 --- a/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java +++ b/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java @@ -3,12 +3,9 @@ package org.mitre.jwt; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; -import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigInteger; -import java.security.GeneralSecurityException; import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; @@ -20,6 +17,7 @@ import org.bouncycastle.x509.X509V3CertificateGenerator; import org.junit.Test; import org.junit.runner.RunWith; import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.signer.JwsAlgorithm; import org.mitre.jwt.signer.JwtSigner; import org.mitre.jwt.signer.impl.HmacSigner; import org.mitre.jwt.signer.impl.PlaintextSigner; @@ -72,8 +70,7 @@ public class JwtTest { * Expected signature: iGBPJj47S5q_HAhSoQqAdcS6A_1CFj3zrLaImqNbt9E */ String signature = "p-63Jzz7mgi3H4hvW6MFB7lmPRZjhsL666MYkmpX33Y"; - String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ." - + signature; + String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ." + signature; String actual = jwt.toString(); @@ -118,21 +115,17 @@ public class JwtTest { // BC sez X509V3CertificateGenerator is deprecated and the docs say to // use another, but it seemingly isn't included jar... - X509V3CertificateGenerator v3CertGen = KeyStoreTest.createCertificate( - "testGenerateRsaSignature", 30, 30); + X509V3CertificateGenerator v3CertGen = KeyStoreTest.createCertificate("testGenerateRsaSignature", 30, 30); v3CertGen.setPublicKey(publicKey); v3CertGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); // BC docs say to use another, but it seemingly isn't included... - X509Certificate certificate = v3CertGen - .generateX509Certificate(privateKey); + X509Certificate certificate = v3CertGen.generateX509Certificate(privateKey); // if exist, overwrite java.security.KeyStore ks = keystore.getKeystore(); - ks.setKeyEntry("testGenerateRsaSignature", privateKey, - RsaSigner.DEFAULT_PASSWORD.toCharArray(), - new java.security.cert.Certificate[] { certificate }); + ks.setKeyEntry("testGenerateRsaSignature", privateKey, RsaSigner.DEFAULT_PASSWORD.toCharArray(), new java.security.cert.Certificate[] { certificate }); keystore.setKeystore(ks); @@ -143,9 +136,7 @@ public class JwtTest { jwt.getClaims().setIssuer("joe"); jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE); - JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.RS256.toString(), - keystore, "testGenerateRsaSignature", - RsaSigner.DEFAULT_PASSWORD); + JwtSigner signer = new RsaSigner(JwsAlgorithm.RS256.toString(), keystore, "testGenerateRsaSignature", RsaSigner.DEFAULT_PASSWORD); ((RsaSigner) signer).afterPropertiesSet(); /* @@ -182,15 +173,10 @@ public class JwtTest { Jwt jwt = Jwt.parse(source); - assertThat(jwt.getHeader().getAlgorithm(), - equalTo(PlaintextSigner.PLAINTEXT)); + assertThat(jwt.getHeader().getAlgorithm(), equalTo(PlaintextSigner.PLAINTEXT)); assertThat(jwt.getClaims().getIssuer(), equalTo("joe")); - assertThat(jwt.getClaims().getExpiration(), equalTo(new Date( - 1300819380L * 1000L))); - assertThat( - (Boolean) jwt.getClaims() - .getClaim("http://example.com/is_root"), - equalTo(Boolean.TRUE)); + assertThat(jwt.getClaims().getExpiration(), equalTo(new Date(1300819380L * 1000L))); + assertThat((Boolean) jwt.getClaims().getClaim("http://example.com/is_root"), equalTo(Boolean.TRUE)); } @@ -258,4 +244,5 @@ public class JwtTest { e.printStackTrace(); } } + }