diff --git a/server/src/main/java/org/mitre/jdbc/datasource/util/SqlFileParser.java b/server/src/main/java/org/mitre/jdbc/datasource/util/SqlFileParser.java index 63ad19325..b518ace5a 100644 --- a/server/src/main/java/org/mitre/jdbc/datasource/util/SqlFileParser.java +++ b/server/src/main/java/org/mitre/jdbc/datasource/util/SqlFileParser.java @@ -1,7 +1,5 @@ package org.mitre.jdbc.datasource.util; -import org.springframework.core.io.Resource; - import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -12,6 +10,10 @@ import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.io.Resource; + /** * @author Matt Franklin * @@ -21,6 +23,9 @@ import java.util.regex.Pattern; * */ public class SqlFileParser { + + private static Log logger = LogFactory.getLog(SqlFileParser.class); + private static final Pattern WORD_PATTERN = Pattern .compile("^([a-zA-Z]*)[ ;]"); private static final String CHILD_SCRIPT_INDICATOR = "@@"; @@ -77,9 +82,8 @@ public class SqlFileParser { processFile(resourceFile, sql); stateStack.pop(); - //System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>"); - //System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>> SQL:: " + sql); - //System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>"); + logger.debug(" SQL:: " + sql); + return sql.toString(); } diff --git a/server/src/main/java/org/mitre/jwt/service/impl/DefaultJwtSigningAndValidationService.java b/server/src/main/java/org/mitre/jwt/service/impl/DefaultJwtSigningAndValidationService.java deleted file mode 100644 index 60b6bd71a..000000000 --- a/server/src/main/java/org/mitre/jwt/service/impl/DefaultJwtSigningAndValidationService.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.mitre.jwt.service.impl; - -import java.security.PublicKey; -import java.util.List; - -import org.mitre.jwt.model.Jwt; -import org.mitre.jwt.service.JwtSigningAndValidationService; -import org.springframework.stereotype.Service; - -/** - * THIS IS A STUB - * - * TODO: Implement - * - * @author AANGANES - * - */ -@Service -public class DefaultJwtSigningAndValidationService implements - JwtSigningAndValidationService { - - @Override - public List getAllPublicKeys() { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean validateSignature(String jwtString) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean validateIssuedJwt(Jwt jwt) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean isJwtExpired(Jwt jwt) { - // TODO Auto-generated method stub - return false; - } - -} diff --git a/server/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java b/server/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java index f2bdc735d..478294171 100644 --- a/server/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java +++ b/server/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java @@ -10,12 +10,7 @@ import com.google.common.base.Strings; import com.google.common.collect.Lists; public abstract class AbstractJwtSigner implements JwtSigner { - - public static final String PLAINTEXT = "none"; - public static final String HS256 = "HS256"; - public static final String HS384 = "HS384"; - public static final String HS512 = "HS512"; - + private String algorithm; public AbstractJwtSigner(String algorithm) { @@ -77,6 +72,4 @@ public abstract class AbstractJwtSigner implements JwtSigner { protected abstract String generateSignature(String signatureBase); - - } \ No newline at end of file diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/EcdsaSigner.java b/server/src/main/java/org/mitre/jwt/signer/impl/EcdsaSigner.java new file mode 100644 index 000000000..1a47bc99e --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/impl/EcdsaSigner.java @@ -0,0 +1,164 @@ +package org.mitre.jwt.signer.impl; + +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; + +import org.mitre.jwt.signer.AbstractJwtSigner; +import org.mitre.jwt.signer.service.impl.KeyStore; +import org.springframework.beans.factory.InitializingBean; + +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"); + + private static final String DEFAULT = Algorithm.ES256.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; + } + } + + // corresponding type not found + throw new IllegalArgumentException("Algorithm name does not have a corresponding Algorithm"); + } + + 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 KeyStore keystore; + private String alias; + private String password; + + private PrivateKey privateKey; + private PublicKey publicKey; + private Signature signer; + + public EcdsaSigner() { + this(Algorithm.DEFAULT, null, null, null); + } + + public EcdsaSigner(String algorithmName, KeyStore keystore, String alias, String password) { + super(algorithmName); + + setKeystore(keystore); + setAlias(alias); + setPassword(password); + + try { + signer = Signature.getInstance(Algorithm.getByName(algorithmName).getStandardName()); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + + @Override + public void afterPropertiesSet() throws Exception { + KeyPair keyPair = keystore.getKeyPairForAlias(alias, password); + + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + } + + @Override + protected String generateSignature(String signatureBase) { + + /* + 1) Generate a digital signature of the UTF-8 representation of the JWS Signing Input + using ECDSA P-256 SHA-256 with the desired private key. The output will be the + EC point (R, S), where R and S are unsigned integers. + 2) Turn R and S into byte arrays in big endian order. Each array will be 32 bytes long. + 3) Concatenate the two byte arrays in the order R and then S. + 4) Base64url encode the resulting 64 byte array. + */ + + return null; + } + + public String getAlias() { + return alias; + } + + public KeyStore getKeystore() { + return keystore; + } + + public String getPassword() { + return password; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public void setKeystore(KeyStore keyStore) { + this.keystore = keyStore; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public boolean verify(String jwtString) { + + /* + 1) Take the Encoded JWS Signature and base64url decode it into a byte array. + If decoding fails, the signed content MUST be rejected. + 2) The output of the base64url decoding MUST be a 64 byte array. + 3) Split the 64 byte array into two 32 byte arrays. The first array will be R and + the second S. Remember that the byte arrays are in big endian byte order; + please check the ECDSA validator in use to see what byte order it requires. + 4) Submit the UTF-8 representation of the JWS Signing Input, R, S and the public + key (x, y) to the ECDSA P-256 SHA-256 validator. + 5) If the validation fails, the signed content MUST be rejected. + */ + + return false; + } + +} \ No newline at end of file diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/Es256Signer.java b/server/src/main/java/org/mitre/jwt/signer/impl/Es256Signer.java deleted file mode 100644 index 5046fbb25..000000000 --- a/server/src/main/java/org/mitre/jwt/signer/impl/Es256Signer.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.mitre.jwt.signer.impl; - -import org.mitre.jwt.signer.AbstractJwtSigner; - -public class Es256Signer extends AbstractJwtSigner { - - public Es256Signer() { - this(null); - } - - public Es256Signer(String algorithm) { - super("ES256"); - } - - @Override - protected String generateSignature(String signatureBase) { - - /* - 1) Generate a digital signature of the UTF-8 representation of the JWS Signing Input - using ECDSA P-256 SHA-256 with the desired private key. The output will be the - EC point (R, S), where R and S are unsigned integers. - 2) Turn R and S into byte arrays in big endian order. Each array will be 32 bytes long. - 3) Concatenate the two byte arrays in the order R and then S. - 4) Base64url encode the resulting 64 byte array. - */ - - return null; - } - - @Override - public boolean verify(String jwtString) { - - /* - 1) Take the Encoded JWS Signature and base64url decode it into a byte array. - If decoding fails, the signed content MUST be rejected. - 2) The output of the base64url decoding MUST be a 64 byte array. - 3) Split the 64 byte array into two 32 byte arrays. The first array will be R and - the second S. Remember that the byte arrays are in big endian byte order; - please check the ECDSA validator in use to see what byte order it requires. - 4) Submit the UTF-8 representation of the JWS Signing Input, R, S and the public - key (x, y) to the ECDSA P-256 SHA-256 validator. - 5) If the validation fails, the signed content MUST be rejected. - */ - - return false; - } - -} diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/Hmac256Signer.java b/server/src/main/java/org/mitre/jwt/signer/impl/Hmac256Signer.java deleted file mode 100644 index 49ac533ea..000000000 --- a/server/src/main/java/org/mitre/jwt/signer/impl/Hmac256Signer.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.mitre.jwt.signer.impl; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Base64; -import org.mitre.jwt.signer.AbstractJwtSigner; - -public class Hmac256Signer extends AbstractJwtSigner { - - private Mac mac; - - private byte[] passphrase; - - /** - * Create a signer with no passphrase - */ - public Hmac256Signer() { - this(null); - } - - /** - * Create a signer with the given passphrase - * @param passphrase - */ - public Hmac256Signer(byte[] passphrase) { - super(HS256); - - //TODO: set up a factory for other signature methods - - setPassphrase(passphrase); - - try { - mac = Mac.getInstance("HMACSHA256"); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - - } - - @Override - protected String generateSignature(String signatureBase) { - if (passphrase == null) { - return null; // TODO: probably throw some kind of exception - } - - try { - mac.init(new SecretKeySpec(getPassphrase(), mac.getAlgorithm())); - } catch (InvalidKeyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - try { - mac.update(signatureBase.getBytes("UTF-8")); - } catch (IllegalStateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - byte[] sigBytes = mac.doFinal(); - - String sig = new String(Base64.encodeBase64URLSafe(sigBytes)); - - // strip off any padding - sig = sig.replace("=", ""); - return sig; - } - - /** - * @return the passphrase - */ - public byte[] getPassphrase() { - return passphrase; - } - - /** - * @param passphrase the passphrase to set - */ - public void setPassphrase(byte[] passphrase) { - this.passphrase = passphrase; - } - - - - -} diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java b/server/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java new file mode 100644 index 000000000..bb0a013d8 --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java @@ -0,0 +1,208 @@ +package org.mitre.jwt.signer.impl; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mitre.jwt.signer.AbstractJwtSigner; + +/** + * JWT Signer using either the HMAC SHA-256, SHA-384, SHA-512 hash algorithm + * + * @author AANGANES, nemonik + * + */ +public class HmacSigner extends AbstractJwtSigner { + + /** + * an enum for mapping a JWS name to standard algorithm name + * + * @author nemonik + * + */ + public enum Algorithm { + + // 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; + } + } + + // corresponding type not found + throw new IllegalArgumentException( + "Algorithm name does not have a corresponding Algorithm"); + } + + 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(HmacSigner.class); + + private Mac mac; + + private String passphrase; + + /** + * Create a signer with no passphrase + */ + public HmacSigner() { + super(Algorithm.DEFAULT); + } + + /** + * Create HMAC singer with default algorithm and passphrase as raw bytes + * + * @param passphraseAsRawBytes + */ + public HmacSigner(byte[] passphraseAsRawBytes) { + this(Algorithm.DEFAULT, new String(passphraseAsRawBytes, + Charset.forName("UTF-8"))); + } + + /** + * Create HMAC singer with default algorithm and passphrase + * + * @param passwordAsRawBytes + */ + public HmacSigner(String passphrase) { + this(Algorithm.DEFAULT, passphrase); + } + + /** + * Create HMAC singer with given algorithm and password as raw bytes + * + * @param algorithmName + * the JWS name for the standard name of the requested MAC + * algorithm + * @param passphraseAsRawBytes + */ + public HmacSigner(String algorithmName, byte[] passphraseAsRawBytes) { + this(algorithmName, new String(passphraseAsRawBytes, + Charset.forName("UTF-8"))); + } + + /** + * Create HMAC singer with given algorithm and passwords + * + * @param algorithmName + * the JWS name for the standard name of the requested MAC + * algorithm + * @param passphrase + * the passphrase + */ + public HmacSigner(String algorithmName, String passphrase) { + super(algorithmName); + + setPassphrase(passphrase); + + try { + mac = Mac.getInstance(Algorithm.getByName(algorithmName) + .getStandardName()); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + + /* + * (non-Javadoc) + * + * @see + * org.mitre.jwt.signer.AbstractJwtSigner#generateSignature(java.lang.String + * ) + */ + @Override + protected String generateSignature(String signatureBase) { + if (passphrase == null) { + return null; // TODO: probably throw some kind of exception + } + + try { + mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac + .getAlgorithm())); + } catch (InvalidKeyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + mac.update(signatureBase.getBytes("UTF-8")); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + byte[] sigBytes = mac.doFinal(); + + String sig = new String(Base64.encodeBase64URLSafe(sigBytes)); + + // strip off any padding + sig = sig.replace("=", ""); + return sig; + } + + public String getPassphrase() { + return passphrase; + } + + public void setPassphrase(byte[] rawbytes) { + this.setPassphrase(new String(rawbytes, Charset.forName("UTF-8"))); + } + + public void setPassphrase(String passphrase) { + + if (passphrase.isEmpty()) + throw new IllegalArgumentException("passphrase must be set"); + + this.passphrase = passphrase; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "HmacSigner [mac=" + mac + ", passphrase=" + passphrase + "]"; + } +} diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java b/server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java index bd02338d6..f60f32584 100644 --- a/server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java +++ b/server/src/main/java/org/mitre/jwt/signer/impl/PlaintextSigner.java @@ -4,6 +4,8 @@ import org.mitre.jwt.signer.AbstractJwtSigner; public class PlaintextSigner extends AbstractJwtSigner { + public static final String PLAINTEXT = "none"; + public PlaintextSigner() { super(PLAINTEXT); } diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/Rs256Signer.java b/server/src/main/java/org/mitre/jwt/signer/impl/Rs256Signer.java deleted file mode 100644 index f7bcfed06..000000000 --- a/server/src/main/java/org/mitre/jwt/signer/impl/Rs256Signer.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.mitre.jwt.signer.impl; - -import java.io.UnsupportedEncodingException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.util.List; - -import org.apache.commons.codec.binary.Base64; -import org.mitre.jwt.signer.AbstractJwtSigner; - -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; - -/** - * JWT Signer using RSA SHA-256 algorithm - * @author AANGANES - * - */ -public class Rs256Signer extends AbstractJwtSigner { - - private PrivateKey privateKey; - private PublicKey publicKey; - - private Signature signer; - - public Rs256Signer() { - this(null, null); - } - - public Rs256Signer(PublicKey publicKey, PrivateKey privateKey) { - super("RS256"); - - setPublicKey(publicKey); - setPrivateKey(privateKey); - - try { - signer = Signature.getInstance("SHA256withRSA"); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Override - protected String generateSignature(String signatureBase) { - - try { - signer.initSign(privateKey); - } catch (InvalidKeyException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - try { - signer.update(signatureBase.getBytes("UTF-8")); - } catch (SignatureException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - 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; - } - - @Override - public boolean verify(String jwtString) { - - // split on the dots - List parts = Lists.newArrayList(Splitter.on(".").split(jwtString)); - - 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); - - String signingInput = h64 + "." + c64; - - try { - signer.initVerify(publicKey); - } catch (InvalidKeyException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - return false; - } - - try { - signer.update(signingInput.getBytes("UTF-8")); - } catch (SignatureException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } catch (UnsupportedEncodingException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - try { - signer.verify(s64.getBytes("UTF-8")); - } catch (SignatureException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - - return true; - } - - public PrivateKey getPrivateKey() { - return privateKey; - } - - public void setPrivateKey(PrivateKey privateKey) { - this.privateKey = privateKey; - } - - public PublicKey getPublicKey() { - return publicKey; - } - - public void setPublicKey(PublicKey publicKey) { - this.publicKey = publicKey; - } - -} diff --git a/server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java b/server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java new file mode 100644 index 000000000..589a40cf8 --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java @@ -0,0 +1,265 @@ +package org.mitre.jwt.signer.impl; + +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.util.List; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mitre.jwt.signer.AbstractJwtSigner; +import org.mitre.jwt.signer.service.impl.KeyStore; +import org.springframework.beans.factory.InitializingBean; + +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; + +/** + * JWT Signer using either the RSA SHA-256, SHA-384, SHA-512 hash algorithm + * + * @author AANGANES, nemonik + * + */ +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(); + + /** + * 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 does not have a corresponding Algorithm"); + } + + 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 DEFAULT_PASSWORD = "changeit"; + + private KeyStore keystore; + private String alias; + private String password; + + private PrivateKey privateKey; + private PublicKey publicKey; + private Signature signer; + + /** + * Default constructor + */ + public RsaSigner() { + this(Algorithm.DEFAULT, null, null, DEFAULT_PASSWORD); + } + + /** + * @param algorithmName + * @param keystore + * @param alias + */ + public RsaSigner(String algorithmName, KeyStore keystore, String alias) { + this(algorithmName, keystore, alias, DEFAULT_PASSWORD); + } + + /** + * @param algorithmName + * @param keystore + * @param alias + * @param password + */ + public RsaSigner(String algorithmName, KeyStore keystore, String alias, String password) { + super(algorithmName); + + setKeystore(keystore); + setAlias(alias); + setPassword(password); + + try { + signer = Signature.getInstance(Algorithm.getByName(algorithmName).getStandardName()); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public void afterPropertiesSet() throws Exception { + KeyPair keyPair = keystore.getKeyPairForAlias(alias, password); + + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + + logger.debug("RSA Signer ready for business"); + + } + + @Override + protected String generateSignature(String signatureBase) { + + try { + signer.initSign(privateKey); + } catch (InvalidKeyException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + signer.update(signatureBase.getBytes("UTF-8")); + } catch (SignatureException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + 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; + } + + public String getAlias() { + return alias; + } + + public KeyStore getKeystore() { + return keystore; + } + + public String getPassword() { + return password; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public void setKeystore(KeyStore keyStore) { + this.keystore = keyStore; + } + + public void setPassword(String password) { + this.password = password; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "RsaSigner [keystore=" + keystore + ", alias=" + alias + + ", password=" + password + ", privateKey=" + privateKey + + ", publicKey=" + publicKey + ", signer=" + signer + "]"; + } + + @Override + public boolean verify(String jwtString) { + + // split on the dots + List parts = Lists.newArrayList(Splitter.on(".").split( + jwtString)); + + 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); + + String signingInput = h64 + "." + c64; + + try { + signer.initVerify(publicKey); + } catch (InvalidKeyException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + return false; + } + + try { + signer.update(signingInput.getBytes("UTF-8")); + } catch (SignatureException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (UnsupportedEncodingException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + try { + signer.verify(s64.getBytes("UTF-8")); + } catch (SignatureException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } + + return true; + } +} diff --git a/server/src/main/java/org/mitre/jwt/service/JwtSigningAndValidationService.java b/server/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java similarity index 60% rename from server/src/main/java/org/mitre/jwt/service/JwtSigningAndValidationService.java rename to server/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java index 969cb6831..6060bac53 100644 --- a/server/src/main/java/org/mitre/jwt/service/JwtSigningAndValidationService.java +++ b/server/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java @@ -1,4 +1,4 @@ -package org.mitre.jwt.service; +package org.mitre.jwt.signer.service; import java.security.PublicKey; import java.util.List; @@ -9,29 +9,38 @@ public interface JwtSigningAndValidationService { /** * Returns all public keys this service is configured with. + * * @return */ public List getAllPublicKeys(); - + /** - * Checks the signature of the given JWT against all configured signers, returns true if at least one of the signers validates it. - * @param jwtString the string representation of the JWT as sent on the wire - * @return true if the signature is valid, false if not + * Check to see if this JWT has expired or not + * + * @param jwt + * the JWT to check + * @return true if this JWT has an expiration and it has passed, false if + * the JWT has no expiration or it has an expiration and the + * expiration has not passed */ - public boolean validateSignature(String jwtString); - + public boolean isJwtExpired(Jwt jwt); + /** * Checks to see if this JWT has been issued by us - * @param jwt the JWT to check the issuer of + * + * @param jwt + * the JWT to check the issuer of * @return true if the JWT was issued by this AS, false if not */ public boolean validateIssuedJwt(Jwt jwt); - - + /** - * Check to see if this JWT has expired or not - * @param jwt the JWT to check - * @return true if this JWT has an expiration and it has passed, false if the JWT has no expiration or it has an expiration and the expiration has not passed + * Checks the signature of the given JWT against all configured signers, + * returns true if at least one of the signers validates it. + * + * @param jwtString + * the string representation of the JWT as sent on the wire + * @return true if the signature is valid, false if not */ - public boolean isJwtExpired(Jwt jwt); + public boolean validateSignature(String jwtString); } diff --git a/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSignerNamespaceHandler.java b/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSignerNamespaceHandler.java new file mode 100644 index 000000000..c82a6857a --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSignerNamespaceHandler.java @@ -0,0 +1,22 @@ +package org.mitre.jwt.signer.service.impl; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +/** + * Support class for implementing custom jwt-signer namespace + * + * @author nemonik + * + */ +public class JwtSignerNamespaceHandler extends NamespaceHandlerSupport { + + /* (non-Javadoc) + * @see org.springframework.beans.factory.xml.NamespaceHandler#init() + */ + @Override + public void init() { + registerBeanDefinitionParser("keystore", new KeystoreDefinitionParser()); + registerBeanDefinitionParser("service", new ServiceDefinitionParser()); + } + +} diff --git a/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java b/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java new file mode 100644 index 000000000..bde226dd0 --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java @@ -0,0 +1,161 @@ +package org.mitre.jwt.signer.service.impl; + +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.signer.JwtSigner; +import org.mitre.jwt.signer.impl.EcdsaSigner; +import org.mitre.jwt.signer.impl.RsaSigner; +import org.mitre.jwt.signer.service.JwtSigningAndValidationService; +import org.springframework.beans.factory.InitializingBean; + +public class JwtSigningAndValidationServiceDefault implements + JwtSigningAndValidationService, InitializingBean { + + private List signers = new ArrayList(); + + private static Log logger = LogFactory + .getLog(JwtSigningAndValidationServiceDefault.class); + + /** + * default constructor + */ + public JwtSigningAndValidationServiceDefault() { + } + + /** + * Create JwtSigningAndValidationServiceDefault + * + * @param signer List of JwtSigners to associate with this service + */ + public JwtSigningAndValidationServiceDefault(List signer) { + setSigners(signer); + } + + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception { + // used for debugging... + if (!signers.isEmpty()) { + logger.info(this.toString()); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.mitre.jwt.signer.service.JwtSigningAndValidationService#getAllPublicKeys + * () + */ + @Override + public List getAllPublicKeys() { + // TODO Iterate through the signers, gather up, and return all the PublicKeys + + List publicKeys = new ArrayList(); + PublicKey publicKey; + + for (JwtSigner signer: signers) { + + if (signer instanceof RsaSigner) { + + publicKey = ((RsaSigner) signer).getPublicKey(); + + if (publicKey != null) + publicKeys.add(((RsaSigner) signer).getPublicKey()); + + } else if (signer instanceof EcdsaSigner) { + + publicKey = ((EcdsaSigner) signer).getPublicKey(); + + if (publicKey != null) + publicKeys.add(publicKey); + } + } + + return publicKeys; + } + + /** + * Return the JwtSigners associated with this service + * + * @return + */ + public List getSigners() { + return signers; + } + + /* + * (non-Javadoc) + * + * @see + * org.mitre.jwt.signer.service.JwtSigningAndValidationService#isJwtExpired + * (org.mitre.jwt.model.Jwt) + */ + @Override + public boolean isJwtExpired(Jwt jwt) { + // TODO Auto-generated method stub + return false; + } + + /** + * Set the JwtSigners associated with this service + * + * @param signers + * List of JwtSigners to associate with this service + */ + public void setSigners(List signers) { + this.signers = signers; + } + + @Override + public String toString() { + return "JwtSigningAndValidationServiceDefault [signers=" + signers + + "]"; + } + + /* + * (non-Javadoc) + * + * @see + * org.mitre.jwt.signer.service.JwtSigningAndValidationService#validateIssuedJwt + * (org.mitre.jwt.model.Jwt) + */ + @Override + public boolean validateIssuedJwt(Jwt jwt) { + + // TODO Verify this is correct... + + for (JwtSigner signer: signers) { + if (signer.verify(jwt.toString())) + return true; + } + + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.mitre.jwt.signer.service.JwtSigningAndValidationService#validateSignature + * (java.lang.String) + */ + @Override + public boolean validateSignature(String jwtString) { + + for (JwtSigner signer: signers) { + if (signer.verify(jwtString)) + return true; + } + + return false; + } +} diff --git a/server/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java b/server/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java new file mode 100644 index 000000000..2d354ae9f --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java @@ -0,0 +1,169 @@ +package org.mitre.jwt.signer.service.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.util.StringUtils; + +/** + * Creates and manages a JCE KeyStore + * + * @author nemonik + * + */ +public class KeyStore implements InitializingBean { + + // TODO: Doesn't have a provider attribute, getter/setter. Not sure we need. + + private static Log logger = LogFactory.getLog(KeyStore.class); + + private static final String TYPE = java.security.KeyStore.getDefaultType(); + private static final String PASSWORD = "changeit"; + + private String password; + private Resource location; + private String type; + + private java.security.KeyStore keystore; + + /** + * default constructor + */ + public KeyStore() { + this(PASSWORD, null, TYPE); + } + + /** + * @param password + * @param location + */ + public KeyStore(String password, Resource location) { + this(password, location, TYPE); + } + + /** + * KeyStore constructor + * + * @param password + * the password used to unlock the keystore + * @param location + * the location of the keystore + * @param type + * the type of keystore. See Appendix A in the Java Cryptography + * Architecture API Specification & Reference for information + * about standard keystore types. + */ + public KeyStore(String password, Resource location, String type) { + setPassword(password); + setLocation(location); + setType(type); + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws IOException, + GeneralSecurityException { + + InputStream inputStream = null; + + try { + keystore = java.security.KeyStore.getInstance(type); + inputStream = location.getInputStream(); + keystore.load(inputStream, this.password.toCharArray()); + + logger.info("Loaded keystore from " + location); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } + + /** + * Returns a KeyPair for the alias given the password + * + * @param alias + * the alias name + * @param password + * the password for recovering the key pair + * @return the key pair + * @throws GeneralSecurityException + */ + public KeyPair getKeyPairForAlias(String alias, String password) + throws GeneralSecurityException { + + Key key = keystore.getKey(alias, password.toCharArray()); + + if (key instanceof PrivateKey) { + + // Get certificate of public key + java.security.cert.Certificate cert = keystore + .getCertificate(alias); + + // Get public key + PublicKey publicKey = cert.getPublicKey(); + + return new KeyPair(publicKey, (PrivateKey) key); + } + + return null; + } + + public Resource getLocation() { + return location; + } + + public String getPassword() { + return password; + } + + public String getType() { + return type; + } + + public void setLocation(Resource location) { + if (location != null && location.exists()) { + this.location = location; + } else { + throw new IllegalArgumentException("location must exist"); + } + } + + public void setPassword(String password) { + this.password = password; + } + + public void setType(String type) { + if (StringUtils.hasLength(type)) { + this.type = type; + } else { + throw new IllegalArgumentException("type must not be empty"); + } + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "KeyStore [password=" + password + ", location=" + location + + ", type=" + type + ", keystore=" + keystore + "]"; + } + +} diff --git a/server/src/main/java/org/mitre/jwt/signer/service/impl/KeystoreDefinitionParser.java b/server/src/main/java/org/mitre/jwt/signer/service/impl/KeystoreDefinitionParser.java new file mode 100644 index 000000000..8b202bf04 --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/service/impl/KeystoreDefinitionParser.java @@ -0,0 +1,73 @@ +package org.mitre.jwt.signer.service.impl; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.io.Resource; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * Needed to parse and define just a single BeanDefinition for the KeyStore + * + * @author nemonik + * + */ +public class KeystoreDefinitionParser extends + AbstractSingleBeanDefinitionParser { + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser + * #doParse(org.w3c.dom.Element, + * org.springframework.beans.factory.xml.ParserContext, + * org.springframework.beans.factory.support.BeanDefinitionBuilder) + */ + @Override + protected void doParse(Element element, ParserContext parserContext, + BeanDefinitionBuilder builder) { + + String password = element.getAttribute("password"); + if (StringUtils.hasText(password)) { + builder.addConstructorArgValue(password); + } + + String location = element.getAttribute("location"); + + if (!StringUtils.hasText(location)) { + parserContext.getReaderContext().error( + "A location must be supplied on a keystore element.", + element); + } else { + + Resource resource = parserContext.getReaderContext().getResourceLoader().getResource(location); + + if (!resource.exists()) { + parserContext.getReaderContext().error( + "The location supplied on the keystore element must exist.", + element); + } else { + builder.addConstructorArgValue(resource); + } + } + + String type = element.getAttribute("type"); + if (StringUtils.hasText(type)) { + builder.addConstructorArgValue(type); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser + * #getBeanClass(org.w3c.dom.Element) + */ + @Override + protected Class getBeanClass(Element element) { + return KeyStore.class; + } +} \ No newline at end of file diff --git a/server/src/main/java/org/mitre/jwt/signer/service/impl/ServiceDefinitionParser.java b/server/src/main/java/org/mitre/jwt/signer/service/impl/ServiceDefinitionParser.java new file mode 100644 index 000000000..2a7d53aa7 --- /dev/null +++ b/server/src/main/java/org/mitre/jwt/signer/service/impl/ServiceDefinitionParser.java @@ -0,0 +1,134 @@ +package org.mitre.jwt.signer.service.impl; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mitre.jwt.signer.impl.HmacSigner; +import org.mitre.jwt.signer.impl.RsaSigner; +import org.springframework.beans.BeanMetadataElement; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * Needed to parse and define just a single BeanDefinition for the + * JwtSigningAndValidationServiceDefault + * + * @author nemonik + * + */ +public class ServiceDefinitionParser extends AbstractSingleBeanDefinitionParser { + + private static Log logger = LogFactory.getLog(ServiceDefinitionParser.class); + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser + * #doParse(org.w3c.dom.Element, + * org.springframework.beans.factory.xml.ParserContext, + * org.springframework.beans.factory.support.BeanDefinitionBuilder) + */ + @Override + protected void doParse(Element element, ParserContext parserContext, + BeanDefinitionBuilder builder) { + + ManagedList signers = new ManagedList(); + + List signerElements = DomUtils.getChildElementsByTagName( + element, new String[] { "rsa", "hmac" }); + + for (Element signerElement : signerElements) { + + if (signerElement.getTagName().contains("rsa")) { + + logger.debug("parsing rsa element"); + + BeanDefinitionBuilder signer = BeanDefinitionBuilder + .rootBeanDefinition(RsaSigner.class); + + String bits = signerElement.getAttribute("bits"); + if (StringUtils.hasText(bits)) { + signer.addConstructorArgValue("RS".concat(bits)); + } else { + signer.addConstructorArgValue(RsaSigner.Algorithm.DEFAULT); + } + + String keystoreRef = signerElement.getAttribute("keystore-ref"); + if (!StringUtils.hasText(keystoreRef)) { + parserContext + .getReaderContext() + .error("A keystore-ref must be supplied with the definition of a rsa.", + signerElement); + } else { + signer.addConstructorArgReference(keystoreRef); + } + + String alias = signerElement.getAttribute("key-alias"); + if (!StringUtils.hasText(alias)) { + parserContext + .getReaderContext() + .error("An key-alias must be supplied with the definition of a rsa.", + signerElement); + } else { + signer.addConstructorArgValue(alias); + } + + String password = signerElement.getAttribute("password"); + if (StringUtils.hasText(password)) { + signer.addConstructorArgValue(password); + } else { + signer.addConstructorArgValue(RsaSigner.DEFAULT_PASSWORD); + } + + signers.add(signer.getBeanDefinition()); + + } else if (signerElement.getTagName().contains("hmac")) { + + logger.debug("parsing hmac element"); + + BeanDefinitionBuilder signer = BeanDefinitionBuilder + .rootBeanDefinition(HmacSigner.class); + + String bits = signerElement.getAttribute("bits"); + if (StringUtils.hasText(bits)) { + signer.addConstructorArgValue("HS".concat(bits)); + } else { + signer.addConstructorArgValue(HmacSigner.Algorithm.DEFAULT); + } + + String passphrase = signerElement.getAttribute("passphrase"); + if (!StringUtils.hasText(passphrase)) { + parserContext + .getReaderContext() + .error("A passphrase must be supplied with the definition of a hmac.", + signerElement); + } else { + signer.addConstructorArgValue(passphrase); + } + + signers.add(signer.getBeanDefinition()); + } + } + + builder.addPropertyValue("signers", signers); + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser + * #getBeanClass(org.w3c.dom.Element) + */ + @Override + protected Class getBeanClass(Element element) { + return JwtSigningAndValidationServiceDefault.class; + } +} diff --git a/server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java b/server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java index c5b87ab50..182a62b22 100644 --- a/server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java +++ b/server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java @@ -1,6 +1,6 @@ package org.mitre.openid.connect.web; -import org.mitre.jwt.service.JwtSigningAndValidationService; +import org.mitre.jwt.signer.service.JwtSigningAndValidationService; import org.mitre.openid.connect.exception.ExpiredTokenException; import org.mitre.openid.connect.exception.InvalidJwtIssuerException; import org.mitre.openid.connect.exception.InvalidJwtSignatureException; diff --git a/server/src/main/java/org/mitre/openid/connect/web/JsonWebKeyEndpoint.java b/server/src/main/java/org/mitre/openid/connect/web/JsonWebKeyEndpoint.java index 1595e424a..582b42d29 100644 --- a/server/src/main/java/org/mitre/openid/connect/web/JsonWebKeyEndpoint.java +++ b/server/src/main/java/org/mitre/openid/connect/web/JsonWebKeyEndpoint.java @@ -5,7 +5,7 @@ import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; import java.util.List; -import org.mitre.jwt.service.JwtSigningAndValidationService; +import org.mitre.jwt.signer.service.JwtSigningAndValidationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/server/src/main/resources/META-INF/spring.handlers b/server/src/main/resources/META-INF/spring.handlers new file mode 100644 index 000000000..735a440ab --- /dev/null +++ b/server/src/main/resources/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.mitre.org/schema/openid-connect/jwt-signer=org.mitre.jwt.signer.service.impl.JwtSignerNamespaceHandler \ No newline at end of file diff --git a/server/src/main/resources/META-INF/spring.schemas b/server/src/main/resources/META-INF/spring.schemas new file mode 100644 index 000000000..144fa3f73 --- /dev/null +++ b/server/src/main/resources/META-INF/spring.schemas @@ -0,0 +1 @@ +http\://www.mitre.org/schema/openid-connect/jwt-signer/jwt-signer.xsd=org/mitre/jwt/signer/service/impl/jwt-signer.xsd \ No newline at end of file diff --git a/server/src/main/resources/org/mitre/jwt/signer/service/impl/jwt-signer.xsd b/server/src/main/resources/org/mitre/jwt/signer/service/impl/jwt-signer.xsd new file mode 100644 index 000000000..4f62fe113 --- /dev/null +++ b/server/src/main/resources/org/mitre/jwt/signer/service/impl/jwt-signer.xsd @@ -0,0 +1,94 @@ + + + + + + + + + Describes the JCE KeyStore necessary for certain + signers. + + + + + + + + + + + + + + + + + Configures the signer service with these signers. + + + + + + + + + + Configures an RSA signer. + + + + + + + + The reference to the bean that defines the + KeyStore. + + + + + + + The alias to the KeyPair to use for + signing/verifying. + + + + + + + The password to the KeyPair to use for + signing/verifying. + + + + + + + + + Configures an HMAC signer. + + + + + + + + The passphrase used for signing/verifying. + + + + + + + + + + + \ No newline at end of file diff --git a/server/src/main/webapp/WEB-INF/spring/application-context.xml b/server/src/main/webapp/WEB-INF/spring/application-context.xml index d89f810c2..71ef6804d 100644 --- a/server/src/main/webapp/WEB-INF/spring/application-context.xml +++ b/server/src/main/webapp/WEB-INF/spring/application-context.xml @@ -5,6 +5,7 @@ xmlns:context="http://www.springframework.org/schema/context" xmlns:security="http://www.springframework.org/schema/security" xmlns:task="http://www.springframework.org/schema/task" + xmlns:jwt-signer="http://www.mitre.org/schema/openid-connect/jwt-signer" xmlns:oauth="http://www.springframework.org/schema/security/oauth2" xsi:schemaLocation= "http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd @@ -12,9 +13,11 @@ http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd - http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd + http://www.mitre.org/schema/openid-connect/jwt-signer http://www.mitre.org/schema/openid-connect/jwt-signer/jwt-signer.xsd"> + @@ -70,7 +73,15 @@ + + + + + + + + diff --git a/server/src/main/webapp/WEB-INF/spring/keystore.jks b/server/src/main/webapp/WEB-INF/spring/keystore.jks new file mode 100644 index 000000000..c2f6182ca Binary files /dev/null and b/server/src/main/webapp/WEB-INF/spring/keystore.jks differ diff --git a/server/src/test/java/org/mitre/jwt/JwtTest.java b/server/src/test/java/org/mitre/jwt/JwtTest.java index 36aa60c6c..ba6ababb8 100644 --- a/server/src/test/java/org/mitre/jwt/JwtTest.java +++ b/server/src/test/java/org/mitre/jwt/JwtTest.java @@ -1,19 +1,16 @@ package org.mitre.jwt; -import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; import java.io.UnsupportedEncodingException; import java.util.Date; import org.junit.Test; -import org.junit.runner.RunWith; import org.mitre.jwt.model.Jwt; -import org.mitre.jwt.signer.AbstractJwtSigner; import org.mitre.jwt.signer.JwtSigner; -import org.mitre.jwt.signer.impl.Hmac256Signer; +import org.mitre.jwt.signer.impl.HmacSigner; import org.mitre.jwt.signer.impl.PlaintextSigner; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; public class JwtTest { @@ -60,8 +57,8 @@ public class JwtTest { // TODO Auto-generated catch block e.printStackTrace(); } - - JwtSigner signer = new Hmac256Signer(key); + + JwtSigner signer = new HmacSigner(key); signer.sign(jwt); @@ -95,7 +92,7 @@ public class JwtTest { e.printStackTrace(); } - JwtSigner signer = new Hmac256Signer(key); + JwtSigner signer = new HmacSigner(key); /* * Token string based on the following strucutres, serialized exactly as follows and base64 encoded: @@ -121,7 +118,7 @@ public class JwtTest { Jwt jwt = Jwt.parse(source); - assertThat(jwt.getHeader().getAlgorithm(), equalTo(AbstractJwtSigner.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));