refactored algorithms out to their own separate Enum

pull/59/head
Justin Richer 2012-04-02 13:13:13 -04:00
parent fec6a3a876
commit 3dfe6df410
6 changed files with 102 additions and 223 deletions

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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<String> longValues = new ArrayList<String>();
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) {

View File

@ -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() {

View File

@ -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) {

View File

@ -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();
}
}
}