fix for issue 5, code refactoring across signers
parent
4f407a3a11
commit
f215cfc50c
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
|
@ -5,12 +5,6 @@
|
||||||
<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">
|
|
||||||
<dependency-type>uses</dependency-type>
|
|
||||||
</dependent-module>
|
|
||||||
<dependent-module archiveName="openid-connect-common-0.1.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/openid-connect-common/openid-connect-common">
|
|
||||||
<dependency-type>uses</dependency-type>
|
|
||||||
</dependent-module>
|
|
||||||
<property name="java-output-path" value="/openid/target/classes"/>
|
<property name="java-output-path" value="/openid/target/classes"/>
|
||||||
<property name="context-root" value="openid-connect-server"/>
|
<property name="context-root" value="openid-connect-server"/>
|
||||||
</wb-module>
|
</wb-module>
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -38,15 +39,15 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
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
|
* @param name
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@ -58,7 +59,8 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
// corresponding type not found
|
// corresponding type not found
|
||||||
throw new IllegalArgumentException("Algorithm name does not have a corresponding Algorithm");
|
throw new IllegalArgumentException(
|
||||||
|
"Algorithm name does not have a corresponding Algorithm");
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String standardName;
|
private final String standardName;
|
||||||
|
@ -74,6 +76,7 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Java standard algorithm name
|
* Return the Java standard algorithm name
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String getStandardName() {
|
public String getStandardName() {
|
||||||
|
@ -81,8 +84,6 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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";
|
||||||
|
@ -90,7 +91,7 @@ public class EcdsaSigner 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;
|
||||||
|
@ -100,88 +101,123 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
* 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 {
|
|
||||||
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 EcdsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) {
|
|
||||||
super(algorithmName);
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
this.privateKey = privateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
|
||||||
*/
|
|
||||||
@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() + " ECDSA Signer ready for business");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 EcdsaSigner(String algorithmName, PublicKey publicKey,
|
||||||
|
PrivateKey privateKey) {
|
||||||
|
super(algorithmName);
|
||||||
|
|
||||||
|
Assert.notNull(publicKey, "A 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 {
|
||||||
|
|
||||||
|
// Can throw a GeneralException
|
||||||
|
signer = Signature.getInstance(Algorithm.getByName(super.getAlgorithm())
|
||||||
|
.getStandardName()); // PROVIDER);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
String sig = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
signer.initSign(privateKey);
|
signer.initSign(privateKey);
|
||||||
signer.update(signatureBase.getBytes("UTF-8"));
|
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;
|
byte[] sigBytes = signer.sign();
|
||||||
String sig = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
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;
|
||||||
|
@ -215,8 +251,9 @@ public class EcdsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -226,7 +263,9 @@ 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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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,8 +94,10 @@ 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")));
|
||||||
}
|
}
|
||||||
|
@ -100,8 +106,9 @@ public class HmacSigner extends AbstractJwtSigner {
|
||||||
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,11 +116,12 @@ public class HmacSigner extends AbstractJwtSigner {
|
||||||
* 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,23 +130,33 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,14 +203,12 @@ 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
|
||||||
|
|
|
@ -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,91 +98,126 @@ 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");
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* org.mitre.jwt.signer.AbstractJwtSigner#generateSignature(java.lang.String
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String generateSignature(String signatureBase) {
|
protected String generateSignature(String signatureBase) {
|
||||||
|
|
||||||
|
String sig = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
signer.initSign(privateKey);
|
signer.initSign(privateKey);
|
||||||
signer.update(signatureBase.getBytes("UTF-8"));
|
signer.update(signatureBase.getBytes("UTF-8"));
|
||||||
|
|
||||||
|
byte[] sigBytes = signer.sign();
|
||||||
|
|
||||||
|
sig = (new String(Base64.encodeBase64URLSafe(sigBytes))).replace(
|
||||||
|
"=", "");
|
||||||
} 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] sigBytes;
|
|
||||||
String sig = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
sigBytes = signer.sign();
|
|
||||||
sig = new String(Base64.encodeBase64URLSafe(sigBytes));
|
|
||||||
// strip off any padding
|
|
||||||
sig = sig.replace("=", "");
|
|
||||||
} catch (SignatureException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue