fix for issue 5, code refactoring across signers

pull/59/head
nemonik 2012-03-29 12:34:51 -04:00
parent 4f407a3a11
commit f215cfc50c
5 changed files with 316 additions and 220 deletions

View File

@ -38,6 +38,8 @@ import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
@ -324,7 +326,7 @@ public class OpenIdConnectAuthenticationFilter extends
public Authentication attemptAuthentication(HttpServletRequest request, public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException, HttpServletResponse response) throws AuthenticationException,
IOException, ServletException { IOException, ServletException {
if (request.getParameter("error") != null) { if (request.getParameter("error") != null) {
handleError(request, response); handleError(request, response);
@ -443,6 +445,25 @@ public class OpenIdConnectAuthenticationFilter extends
try { try {
idToken = IdToken.parse(jsonRoot.getAsJsonObject() idToken = IdToken.parse(jsonRoot.getAsJsonObject()
.get("id_token").getAsString()); .get("id_token").getAsString());
List<String> parts = Lists.newArrayList(Splitter.on(".")
.split(jsonRoot.getAsJsonObject().get("id_token")
.getAsString()));
if (parts.size() != 3) {
throw new IllegalArgumentException(
"Invalid JWT format.");
}
String h64 = parts.get(0);
String c64 = parts.get(1);
String s64 = parts.get(2);
logger.debug("h64 = " + h64);
logger.debug("c64 = " + c64);
logger.debug("s64 = " + s64);
} catch (Exception e) { } catch (Exception e) {
// I suspect this could happen // I suspect this could happen

View File

@ -1,17 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0"> <project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="openid"> <wb-module deploy-name="openid">
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/> <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/> <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/> <wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/> <wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<dependent-module archiveName="spring-security-oauth2-1.0.0.BUILD-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/spring-security-oauth2/spring-security-oauth2"> <property name="java-output-path" value="/openid/target/classes"/>
<dependency-type>uses</dependency-type> <property name="context-root" value="openid-connect-server"/>
</dependent-module> </wb-module>
<dependent-module archiveName="openid-connect-common-0.1.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/openid-connect-common/openid-connect-common"> </project-modules>
<dependency-type>uses</dependency-type>
</dependent-module>
<property name="java-output-path" value="/openid/target/classes"/>
<property name="context-root" value="openid-connect-server"/>
</wb-module>
</project-modules>

View File

@ -3,10 +3,10 @@ package org.mitre.jwt.signer.impl;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.Signature; import java.security.Signature;
import java.security.SignatureException;
import java.util.List; import java.util.List;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
@ -15,6 +15,7 @@ import org.apache.commons.logging.LogFactory;
import org.mitre.jwt.signer.AbstractJwtSigner; import org.mitre.jwt.signer.AbstractJwtSigner;
import org.mitre.jwt.signer.service.impl.KeyStore; import org.mitre.jwt.signer.service.impl.KeyStore;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -24,8 +25,8 @@ import com.google.common.collect.Lists;
* *
* @author AANGANES, nemonik * @author AANGANES, nemonik
* *
* Requires static install of BC * Requires static install of BC
* *
*/ */
public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean { public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
@ -33,37 +34,38 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
* an enum for mapping a JWS name to standard algorithm name * an enum for mapping a JWS name to standard algorithm name
* *
* @author nemonik * @author nemonik
* *
*/ */
public enum Algorithm { public enum Algorithm {
//Algorithm constants // Algorithm constants
ES256("SHA256withECDSA"), ES256("SHA256withECDSA"), ES384("SHA384withECDSA"), ES512(
ES384("SHA384withECDSA"), "SHA512withECDSA");
ES512("SHA512withECDSA");
public static final String DEFAULT = Algorithm.ES256.toString(); public static final String DEFAULT = Algorithm.ES256.toString();
public static final String PREPEND = "ES"; public static final String PREPEND = "ES";
/** /**
* Returns the Algorithm for the name * Returns the Algorithm for the name
* @param name *
* @return * @param name
*/ * @return
public static Algorithm getByName(String name) { */
for (Algorithm correspondingType : Algorithm.values()) { public static Algorithm getByName(String name) {
if (correspondingType.toString().equals(name)) { for (Algorithm correspondingType : Algorithm.values()) {
return correspondingType; if (correspondingType.toString().equals(name)) {
} return correspondingType;
} }
}
// corresponding type not found
throw new IllegalArgumentException("Algorithm name does not have a corresponding Algorithm"); // corresponding type not found
} throw new IllegalArgumentException(
"Algorithm name does not have a corresponding Algorithm");
}
private final String standardName; private final String standardName;
/** /**
* Constructor of Algorithm * Constructor of Algorithm
* *
* @param standardName * @param standardName
@ -71,122 +73,156 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
Algorithm(String standardName) { Algorithm(String standardName) {
this.standardName = standardName; this.standardName = standardName;
} }
/** /**
* Return the Java standard algorithm name * Return the Java standard algorithm name
* @return *
*/ * @return
public String getStandardName() { */
return standardName; public String getStandardName() {
} return standardName;
}; }
};
static final String PROVIDER = "BC";
private static Log logger = LogFactory.getLog(EcdsaSigner.class); private static Log logger = LogFactory.getLog(EcdsaSigner.class);
public static final String KEYPAIR_ALGORITHM = "EC"; public static final String KEYPAIR_ALGORITHM = "EC";
public static final String DEFAULT_PASSWORD = "changeit"; public static final String DEFAULT_PASSWORD = "changeit";
private KeyStore keystore; private KeyStore keystore;
private String alias; private String alias;
private String password; private String password = DEFAULT_PASSWORD;
private PrivateKey privateKey; private PrivateKey privateKey;
private PublicKey publicKey; private PublicKey publicKey;
private Signature signer; private Signature signer;
/** /**
* Default constructor * Default constructor
*/ */
public EcdsaSigner() { public EcdsaSigner() {
this(Algorithm.DEFAULT, null, null, DEFAULT_PASSWORD); super(Algorithm.DEFAULT);
} }
/** /**
* Creates an EcdsaSigner from an algorithm name, a Java Keystore, an alias
* for the key pair, and the default password to access. Key pairs created
* with larger bit sizes obviously create larger signatures.
*
* @param algorithmName * @param algorithmName
* The algorithm name
* @param keystore * @param keystore
* A Java Keystore containing the key pair
* @param alias * @param alias
* The alias for the key pair
* @throws GeneralSecurityException
*/ */
public EcdsaSigner(String algorithmName, KeyStore keystore, String alias) { public EcdsaSigner(String algorithmName, KeyStore keystore, String alias)
throws GeneralSecurityException {
this(algorithmName, keystore, alias, DEFAULT_PASSWORD); this(algorithmName, keystore, alias, DEFAULT_PASSWORD);
} }
/** /**
* Creates an EcdsaSigner from an algorithm name, a Java Keystore, an alias
* for the key pair, and the password to access. Key pairs created with
* larger bit sizes obviously create larger signatures.
*
* @param algorithmName * @param algorithmName
* The algorithm name
* @param keystore * @param keystore
* A Java Keystore containing the key pair
* @param alias * @param alias
* The alias for the key pair
* @param password * @param password
* The password used to access and retrieve the key pair.
* @throws GeneralSecurityException
*/ */
public EcdsaSigner(String algorithmName, KeyStore keystore, String alias, String password) { public EcdsaSigner(String algorithmName, KeyStore keystore, String alias,
String password) throws GeneralSecurityException {
super(algorithmName); super(algorithmName);
Assert.notNull(keystore, "A keystore must be supplied");
Assert.notNull(alias, "A alias must be supplied");
Assert.notNull(password, "A password must be supplied");
setKeystore(keystore); setKeystore(keystore);
setAlias(alias); setAlias(alias);
setPassword(password); setPassword(password);
try { KeyPair keyPair = keystore.getKeyPairForAlias(alias, password);
signer = Signature.getInstance(Algorithm.getByName(algorithmName).getStandardName(), PROVIDER);
} catch (GeneralSecurityException e) { publicKey = keyPair.getPublic();
// TODO Auto-generated catch block privateKey = keyPair.getPrivate();
e.printStackTrace();
} }
}
/** /**
* Creates an RsaSigner from an algorithm name, and key pair. Key pairs
* created with larger bit sizes obviously create larger signatures.
*
* @param algorithmName * @param algorithmName
* The algorithm name
* @param publicKey * @param publicKey
* The public key
* @param privateKey * @param privateKey
* The private key
*/ */
public EcdsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) { public EcdsaSigner(String algorithmName, PublicKey publicKey,
PrivateKey privateKey) {
super(algorithmName); super(algorithmName);
Assert.notNull(publicKey, "A publicKey must be supplied");
Assert.notNull(privateKey, "A privateKey must be supplied");
this.publicKey = publicKey; this.publicKey = publicKey;
this.privateKey = privateKey; this.privateKey = privateKey;
} }
/* (non-Javadoc) /*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() * (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/ */
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
KeyPair keyPair = keystore.getKeyPairForAlias(alias, password);
publicKey = keyPair.getPublic(); // Can throw a GeneralException
privateKey = keyPair.getPrivate(); signer = Signature.getInstance(Algorithm.getByName(super.getAlgorithm())
.getStandardName()); // PROVIDER);
logger.debug( Algorithm.getByName(getAlgorithm()).getStandardName() + " ECDSA Signer ready for business"); logger.debug(Algorithm.getByName(getAlgorithm()).getStandardName()
+ " ECDSA Signer ready for business");
} }
/* (non-Javadoc)
* @see org.mitre.jwt.signer.AbstractJwtSigner#generateSignature(java.lang.String)
*/
@Override @Override
protected String generateSignature(String signatureBase) { protected String generateSignature(String signatureBase) {
try { String sig = null;
signer.initSign(privateKey);
signer.update(signatureBase.getBytes("UTF-8"));
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] sigBytes;
String sig = "";
try { try {
sigBytes = signer.sign();
signer.initSign(privateKey);
signer.update(signatureBase.getBytes("UTF-8"));
byte[] sigBytes = signer.sign();
sig = new String(Base64.encodeBase64URLSafe(sigBytes)); sig = new String(Base64.encodeBase64URLSafe(sigBytes));
// strip off any padding // strip off any padding
sig = sig.replace("=", ""); sig = sig.replace("=", "");
} catch (SignatureException e) {
// TODO Auto-generated catch block } catch (GeneralSecurityException e) {
e.printStackTrace(); logger.error(e);
} catch (UnsupportedEncodingException e) {
logger.error(e);
} }
return sig; return sig;
} }
public String getAlias() { public String getAlias() {
return alias; return alias;
} }
@ -214,9 +250,10 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
public void setPassword(String password) { public void setPassword(String password) {
this.password = password; this.password = password;
} }
/* (non-Javadoc) /*
* (non-Javadoc)
*
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
@Override @Override
@ -226,12 +263,14 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
+ ", publicKey=" + publicKey + ", signer=" + signer + "]"; + ", publicKey=" + publicKey + ", signer=" + signer + "]";
} }
/* (non-Javadoc) /*
* (non-Javadoc)
*
* @see org.mitre.jwt.signer.AbstractJwtSigner#verify(java.lang.String) * @see org.mitre.jwt.signer.AbstractJwtSigner#verify(java.lang.String)
*/ */
@Override @Override
public boolean verify(String jwtString) { public boolean verify(String jwtString) {
// split on the dots // split on the dots
List<String> parts = Lists.newArrayList(Splitter.on(".").split( List<String> parts = Lists.newArrayList(Splitter.on(".").split(
jwtString)); jwtString));
@ -251,14 +290,11 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
signer.update(signingInput.getBytes("UTF-8")); signer.update(signingInput.getBytes("UTF-8"));
signer.verify(s64.getBytes("UTF-8")); signer.verify(s64.getBytes("UTF-8"));
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
// TODO Auto-generated catch block logger.error(e);
e.printStackTrace();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block logger.error(e);
e.printStackTrace();
} }
return true; return true;
} }
} }

View File

@ -2,7 +2,7 @@ package org.mitre.jwt.signer.impl;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.InvalidKeyException; import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac; import javax.crypto.Mac;
@ -12,6 +12,8 @@ import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.mitre.jwt.signer.AbstractJwtSigner; import org.mitre.jwt.signer.AbstractJwtSigner;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/** /**
* JWT Signer using either the HMAC SHA-256, SHA-384, SHA-512 hash algorithm * JWT Signer using either the HMAC SHA-256, SHA-384, SHA-512 hash algorithm
@ -19,7 +21,7 @@ import org.mitre.jwt.signer.AbstractJwtSigner;
* @author AANGANES, nemonik * @author AANGANES, nemonik
* *
*/ */
public class HmacSigner extends AbstractJwtSigner { public class HmacSigner extends AbstractJwtSigner implements InitializingBean {
/** /**
* an enum for mapping a JWS name to standard algorithm name * an enum for mapping a JWS name to standard algorithm name
@ -71,16 +73,18 @@ public class HmacSigner extends AbstractJwtSigner {
public String getStandardName() { public String getStandardName() {
return standardName; return standardName;
} }
}; }
public static final String DEFAULT_PASSPHRASE = "changeit";;
private static Log logger = LogFactory.getLog(HmacSigner.class);
private static Log logger = LogFactory.getLog(HmacSigner.class);
private Mac mac; private Mac mac;
private String passphrase; private String passphrase = DEFAULT_PASSPHRASE;
/** /**
* Create a signer with no passphrase * Default constructor
*/ */
public HmacSigner() { public HmacSigner() {
super(Algorithm.DEFAULT); super(Algorithm.DEFAULT);
@ -90,30 +94,34 @@ public class HmacSigner extends AbstractJwtSigner {
* Create HMAC singer with default algorithm and passphrase as raw bytes * Create HMAC singer with default algorithm and passphrase as raw bytes
* *
* @param passphraseAsRawBytes * @param passphraseAsRawBytes
* The passphrase as raw bytes
*/ */
public HmacSigner(byte[] passphraseAsRawBytes) { public HmacSigner(byte[] passphraseAsRawBytes)
throws NoSuchAlgorithmException {
this(Algorithm.DEFAULT, new String(passphraseAsRawBytes, this(Algorithm.DEFAULT, new String(passphraseAsRawBytes,
Charset.forName("UTF-8"))); Charset.forName("UTF-8")));
} }
/** /**
* Create HMAC singer with default algorithm and passphrase * Create HMAC singer with default algorithm and passphrase
* *
* @param passwordAsRawBytes * @param passwordAsRawBytes
* The passphrase as raw bytes
*/ */
public HmacSigner(String passphrase) { public HmacSigner(String passphrase) throws NoSuchAlgorithmException {
this(Algorithm.DEFAULT, passphrase); this(Algorithm.DEFAULT, passphrase);
} }
/** /**
* Create HMAC singer with given algorithm and password as raw bytes * Create HMAC singer with given algorithm and password as raw bytes
* *
* @param algorithmName * @param algorithmName
* the JWS name for the standard name of the requested MAC * The Java standard name of the requested MAC algorithm
* algorithm
* @param passphraseAsRawBytes * @param passphraseAsRawBytes
* The passphrase as raw bytes
*/ */
public HmacSigner(String algorithmName, byte[] passphraseAsRawBytes) { public HmacSigner(String algorithmName, byte[] passphraseAsRawBytes)
throws NoSuchAlgorithmException {
this(algorithmName, new String(passphraseAsRawBytes, this(algorithmName, new String(passphraseAsRawBytes,
Charset.forName("UTF-8"))); Charset.forName("UTF-8")));
} }
@ -122,26 +130,36 @@ public class HmacSigner extends AbstractJwtSigner {
* Create HMAC singer with given algorithm and passwords * Create HMAC singer with given algorithm and passwords
* *
* @param algorithmName * @param algorithmName
* the JWS name for the standard name of the requested MAC * The Java standard name of the requested MAC algorithm
* algorithm
* @param passphrase * @param passphrase
* the passphrase * the passphrase
*/ */
public HmacSigner(String algorithmName, String passphrase) { public HmacSigner(String algorithmName, String passphrase) {
super(algorithmName); super(algorithmName);
Assert.notNull(passphrase, "A passphrase must be supplied");
setPassphrase(passphrase); setPassphrase(passphrase);
try {
mac = Mac.getInstance(Algorithm.getByName(algorithmName)
.getStandardName());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
mac = Mac.getInstance(Algorithm.getByName(super.getAlgorithm())
.getStandardName());
logger.debug(Algorithm.getByName(getAlgorithm()).getStandardName()
+ " ECDSA Signer ready for business");
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@ -152,25 +170,18 @@ public class HmacSigner extends AbstractJwtSigner {
@Override @Override
protected String generateSignature(String signatureBase) { protected String generateSignature(String signatureBase) {
if (passphrase == null) { if (passphrase == null) {
return null; // TODO: probably throw some kind of exception throw new IllegalArgumentException("Passphrase cannot be null");
} }
try { try {
mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac
.getAlgorithm())); .getAlgorithm()));
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
mac.update(signatureBase.getBytes("UTF-8")); mac.update(signatureBase.getBytes("UTF-8"));
} catch (IllegalStateException e) { } catch (GeneralSecurityException e) {
// TODO Auto-generated catch block logger.error(e);
e.printStackTrace();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block logger.error(e);
e.printStackTrace();
} }
byte[] sigBytes = mac.doFinal(); byte[] sigBytes = mac.doFinal();
@ -179,6 +190,7 @@ public class HmacSigner extends AbstractJwtSigner {
// strip off any padding // strip off any padding
sig = sig.replace("=", ""); sig = sig.replace("=", "");
return sig; return sig;
} }
@ -191,18 +203,16 @@ public class HmacSigner extends AbstractJwtSigner {
} }
public void setPassphrase(String passphrase) { public void setPassphrase(String passphrase) {
if (passphrase.isEmpty())
throw new IllegalArgumentException("passphrase must be set");
this.passphrase = passphrase; this.passphrase = passphrase;
} }
/* (non-Javadoc) /*
* (non-Javadoc)
*
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
@Override @Override
public String toString() { public String toString() {
return "HmacSigner [mac=" + mac + ", passphrase=" + passphrase + "]"; return "HmacSigner [mac=" + mac + ", passphrase=" + passphrase + "]";
} }
} }

View File

@ -6,7 +6,6 @@ import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.Signature; import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.util.List; import java.util.List;
@ -16,6 +15,7 @@ import org.apache.commons.logging.LogFactory;
import org.mitre.jwt.signer.AbstractJwtSigner; import org.mitre.jwt.signer.AbstractJwtSigner;
import org.mitre.jwt.signer.service.impl.KeyStore; import org.mitre.jwt.signer.service.impl.KeyStore;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -42,7 +42,6 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
public static final String DEFAULT = Algorithm.RS256.toString(); public static final String DEFAULT = Algorithm.RS256.toString();
public static final String PREPEND = "RS"; public static final String PREPEND = "RS";
/** /**
* Returns the Algorithm for the name * Returns the Algorithm for the name
* *
@ -89,7 +88,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
private KeyStore keystore; private KeyStore keystore;
private String alias; private String alias;
private String password; private String password = DEFAULT_PASSWORD;
private PrivateKey privateKey; private PrivateKey privateKey;
private PublicKey publicKey; private PublicKey publicKey;
@ -99,93 +98,128 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
* Default constructor * Default constructor
*/ */
public RsaSigner() { public RsaSigner() {
this(Algorithm.DEFAULT, null, null, DEFAULT_PASSWORD); super(Algorithm.DEFAULT);
} }
/** /**
* Creates an RsaSigner from an algorithm name, a Java Keystore, an alias
* for the key pair, and the default password to access. Key pairs created
* with larger bit sizes obviously create larger signatures.
*
* @param algorithmName * @param algorithmName
* The algorithm name
* @param keystore * @param keystore
* A Java Keystore containing the key pair
* @param alias * @param alias
* The alias for the key pair
* @throws GeneralSecurityException
*/ */
public RsaSigner(String algorithmName, KeyStore keystore, String alias) { public RsaSigner(String algorithmName, KeyStore keystore, String alias)
throws GeneralSecurityException {
this(algorithmName, keystore, alias, DEFAULT_PASSWORD); this(algorithmName, keystore, alias, DEFAULT_PASSWORD);
} }
/** /**
* Creates an RsaSigner from an algorithm name, a Java Keystore, an alias
* for the key pair, and the password to access. Key pairs created with
* larger bit sizes obviously create larger signatures.
*
* @param algorithmName * @param algorithmName
* The algorithm name
* @param keystore * @param keystore
* A Java Keystore containing the key pair
* @param alias * @param alias
* The alias for the key pair
* @param password * @param password
* The password used to access and retrieve the key pair.
* @throws GeneralSecurityException
*/ */
public RsaSigner(String algorithmName, KeyStore keystore, String alias, public RsaSigner(String algorithmName, KeyStore keystore, String alias,
String password) { String password) throws GeneralSecurityException {
super(algorithmName); super(algorithmName);
Assert.notNull(keystore, "An keystore must be supplied");
Assert.notNull(alias, "A alias must be supplied");
Assert.notNull(password, "A password must be supplied");
setKeystore(keystore); setKeystore(keystore);
setAlias(alias); setAlias(alias);
setPassword(password); setPassword(password);
try {
signer = Signature.getInstance(Algorithm.getByName(algorithmName).getStandardName()); //, PROVIDER);
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param algorithmName
* @param publicKey
* @param privateKey
*/
public RsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) {
super(algorithmName);
this.publicKey = publicKey;
this.privateKey = privateKey;
}
@Override
public void afterPropertiesSet() throws Exception {
KeyPair keyPair = keystore.getKeyPairForAlias(alias, password); KeyPair keyPair = keystore.getKeyPairForAlias(alias, password);
publicKey = keyPair.getPublic(); publicKey = keyPair.getPublic();
privateKey = keyPair.getPrivate(); privateKey = keyPair.getPrivate();
logger.debug( Algorithm.getByName(getAlgorithm()).getStandardName() + " RSA Signer ready for business");
} }
/* (non-Javadoc) /**
* @see org.mitre.jwt.signer.AbstractJwtSigner#generateSignature(java.lang.String) * Creates an RsaSigner from an algorithm name, and key pair. Key pairs
* created with larger bit sizes obviously create larger signatures.
*
* @param algorithmName
* The algorithm name
* @param publicKey
* The public key
* @param privateKey
* The private key
*/
public RsaSigner(String algorithmName, PublicKey publicKey,
PrivateKey privateKey) {
super(algorithmName);
Assert.notNull(publicKey, "An publicKey must be supplied");
Assert.notNull(privateKey, "A privateKey must be supplied");
this.publicKey = publicKey;
this.privateKey = privateKey;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
// unsupported algorithm will throw a NoSuchAlgorithmException
signer = Signature.getInstance(Algorithm
.getByName(super.getAlgorithm()).getStandardName()); // ,
// PROVIDER);
logger.debug(Algorithm.getByName(getAlgorithm()).getStandardName()
+ " RSA Signer ready for business");
}
/*
* (non-Javadoc)
*
* @see
* org.mitre.jwt.signer.AbstractJwtSigner#generateSignature(java.lang.String
* )
*/ */
@Override @Override
protected String generateSignature(String signatureBase) { protected String generateSignature(String signatureBase) {
try { String sig = null;
signer.initSign(privateKey);
signer.update(signatureBase.getBytes("UTF-8"));
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] sigBytes;
String sig = "";
try { try {
sigBytes = signer.sign(); signer.initSign(privateKey);
sig = new String(Base64.encodeBase64URLSafe(sigBytes)); signer.update(signatureBase.getBytes("UTF-8"));
// strip off any padding
sig = sig.replace("=", ""); byte[] sigBytes = signer.sign();
} catch (SignatureException e) {
// TODO Auto-generated catch block sig = (new String(Base64.encodeBase64URLSafe(sigBytes))).replace(
e.printStackTrace(); "=", "");
} catch (GeneralSecurityException e) {
logger.error(e);
} catch (UnsupportedEncodingException e) {
logger.error(e);
} }
return sig; return sig;
} }
@ -237,15 +271,16 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
+ ", publicKey=" + publicKey + ", signer=" + signer + "]"; + ", publicKey=" + publicKey + ", signer=" + signer + "]";
} }
/* (non-Javadoc) /*
* @see org.mitre.jwt.signer.AbstractJwtSigner#verify(java.lang.String) * (non-Javadoc)
*/ *
/* (non-Javadoc)
* @see org.mitre.jwt.signer.AbstractJwtSigner#verify(java.lang.String) * @see org.mitre.jwt.signer.AbstractJwtSigner#verify(java.lang.String)
*/ */
@Override @Override
public boolean verify(String jwtString) { public boolean verify(String jwtString) {
boolean value = false;
// split on the dots // split on the dots
List<String> parts = Lists.newArrayList(Splitter.on(".").split( List<String> parts = Lists.newArrayList(Splitter.on(".").split(
jwtString)); jwtString));
@ -263,15 +298,15 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
try { try {
signer.initVerify(publicKey); signer.initVerify(publicKey);
signer.update(signingInput.getBytes("UTF-8")); signer.update(signingInput.getBytes("UTF-8"));
signer.verify(s64.getBytes("UTF-8")); value = signer.verify(s64.getBytes("UTF-8"));
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
// TODO Auto-generated catch block logger.error(e);
e.printStackTrace(); return false;
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block logger.error(e);
e.printStackTrace(); return false;
} }
return true; return value;
} }
} }