Merge branch 'master' of github.com:jricher/OpenID-Connect-Java-Spring-Server

pull/59/head
Michael Jett 2012-02-14 12:39:52 -05:00
commit be132dc5bd
42 changed files with 2057 additions and 332 deletions

BIN
docs/OAuth2.0_Diagrams.pdf Normal file

Binary file not shown.

Binary file not shown.

19
docs/readme.txt Normal file
View File

@ -0,0 +1,19 @@
Changelog
Updated on 2/7/2012
OAuth2:
* Removed refresh_token from the Access Token response on the Client Credentials flow.
Ref: http://tools.ietf.org/html/draft-ietf-oauth-v2-23#section-4.4.3
"A refresh token SHOULD NOT be included."
* Changed "Consumer" to "Client".
Connect:
* Changed "Consumer" to "Client".
* Clarified required/optional wording. Parameters are REQUIRED unless otherwise stated.
* Implicit Flow: changed wording on redirect_uri requirement in the Authorization Request. Now reads "required IFF the client has pre-configured more than one value with the service provider".
* Diagram 3 was renamed to "Optional Steps" (from "Additional Steps"), as these steps may or may not be taken and may be done in any order. Added "openid" to the schema parameter in the UserInfo Request.

View File

@ -269,6 +269,16 @@
<artifactId>maven-replacer-plugin</artifactId>
<version>1.3.8</version>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-security</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework-version}</version>
</dependency>
</dependencies>
<repositories>
<!-- For testing against latest Spring snapshots -->

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 + "]";
}
}

View File

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

View File

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

View File

@ -0,0 +1,265 @@
package org.mitre.jwt.signer.impl;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
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.bouncycastle.jce.provider.BouncyCastleProvider;
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";
static {
Security.addProvider(new BouncyCastleProvider());
}
private KeyStore keystore;
private String alias;
private String password;
private RSAPrivateKey privateKey;
private RSAPublicKey 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(), "BC");
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void afterPropertiesSet() throws Exception {
KeyPair keyPair = keystore.getKeyPairForAlias(alias, password);
publicKey = ((RSAPublicKey) keyPair.getPublic());
privateKey = (RSAPrivateKey) keyPair.getPrivate();
logger.debug("RSA Signer ready for business");
}
/* (non-Javadoc)
* @see org.mitre.jwt.signer.AbstractJwtSigner#generateSignature(java.lang.String)
*/
@Override
protected String generateSignature(String signatureBase) {
try {
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 {
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<String> 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);
signer.update(signingInput.getBytes("UTF-8"));
signer.verify(s64.getBytes("UTF-8"));
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
public RSAPrivateKey getPrivateKey() {
return privateKey;
}
public void setPrivateKey(RSAPrivateKey privateKey) {
this.privateKey = privateKey;
}
}

View File

@ -0,0 +1,46 @@
package org.mitre.jwt.signer.service;
import java.security.PublicKey;
import java.util.List;
import org.mitre.jwt.model.Jwt;
public interface JwtSigningAndValidationService {
/**
* Returns all public keys this service is configured with.
*
* @return
*/
public List<PublicKey> getAllPublicKeys();
/**
* 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 isJwtExpired(Jwt jwt);
/**
* Checks to see if this JWT has been issued by us
*
* @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);
/**
* 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 validateSignature(String jwtString);
}

View File

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

View File

@ -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<? extends JwtSigner> signers = new ArrayList<JwtSigner>();
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<? extends JwtSigner> 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<PublicKey> getAllPublicKeys() {
// TODO Iterate through the signers, gather up, and return all the PublicKeys
List<PublicKey> publicKeys = new ArrayList<PublicKey>();
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<? extends JwtSigner> 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<? extends JwtSigner> 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;
}
}

View File

@ -0,0 +1,324 @@
package org.mitre.jwt.signer.service.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
/**
* Creates and manages a JCE KeyStore
*
* @author nemonik
*
*/
@SuppressWarnings("deprecation")
public class KeyStore implements InitializingBean {
private static Log logger = LogFactory.getLog(KeyStore.class);
public static final String TYPE = "BKS";
public static final String PASSWORD = "changeit";
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* Creates a certificate.
*
* @param commonName
* @param daysNotValidBefore
* @param daysNotValidAfter
* @return
*/
private static X509V3CertificateGenerator createCertificate(
String commonName, int daysNotValidBefore, int daysNotValidAfter) {
// BC docs say to use another, but it seemingly isn't included...
X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
v3CertGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
v3CertGen.setIssuerDN(new X509Principal("CN=" + commonName
+ ", OU=None, O=None L=None, C=None"));
v3CertGen.setNotBefore(new Date(System.currentTimeMillis()
- (1000L * 60 * 60 * 24 * daysNotValidBefore)));
v3CertGen.setNotAfter(new Date(System.currentTimeMillis()
+ (1000L * 60 * 60 * 24 * daysNotValidAfter)));
v3CertGen.setSubjectDN(new X509Principal("CN=" + commonName
+ ", OU=None, O=None L=None, C=None"));
return v3CertGen;
}
/**
* Create an RSA KeyPair and insert into specified KeyStore
*
* @param location
* @param domainName
* @param alias
* @param keystorePassword
* @param aliasPassword
* @param daysNotValidBefore
* @param daysNotValidAfter
* @return
* @throws GeneralSecurityException
* @throws IOException
*/
public static java.security.KeyStore generateRsaKeyPair(String location,
String domainName, String alias, String keystorePassword,
String aliasPassword, int daysNotValidBefore, int daysNotValidAfter)
throws GeneralSecurityException, IOException {
java.security.KeyStore ks = loadJceKeyStore(location, keystorePassword);
KeyPairGenerator rsaKeyPairGenerator = KeyPairGenerator
.getInstance("RSA", "BC");
rsaKeyPairGenerator.initialize(2048);
KeyPair rsaKeyPair = rsaKeyPairGenerator.generateKeyPair();
X509V3CertificateGenerator v3CertGen = createCertificate(domainName,
daysNotValidBefore, daysNotValidAfter);
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) rsaKeyPair.getPrivate();
v3CertGen.setPublicKey(rsaKeyPair.getPublic());
v3CertGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); // "MD5WithRSAEncryption");
// BC docs say to use another, but it seemingly isn't included...
X509Certificate certificate = v3CertGen
.generateX509Certificate(rsaPrivateKey);
// if exist, overwrite
ks.setKeyEntry(alias, rsaPrivateKey, aliasPassword.toCharArray(),
new java.security.cert.Certificate[] { certificate });
storeJceKeyStore(location, keystorePassword, ks);
return ks;
}
/**
* Creates or loads a JCE KeyStore
* @param location
* @param keystorePassword
* @return
* @throws GeneralSecurityException
* @throws IOException
*/
private static java.security.KeyStore loadJceKeyStore(String location, String keystorePassword) throws GeneralSecurityException, IOException {
java.security.KeyStore ks = java.security.KeyStore.getInstance(TYPE);
File keystoreFile = new File(location);
if (!keystoreFile.exists()) {
ks.load(null, null);
} else {
InputStream ios = new FileInputStream(keystoreFile);
try {
ks.load(ios, keystorePassword.toCharArray());
logger.info("Loaded keystore from " + location);
} finally {
ios.close();
}
}
return ks;
}
public static void main(String[] args) {
//TODO create a cmd-line to create the KeyStore?
try {
KeyStore.generateRsaKeyPair("/tmp/keystore.jks",
"OpenID Connect Server", "test", KeyStore.PASSWORD,
KeyStore.PASSWORD, 30, 365);
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Store the JCE KeyStore
*
* @param location
* @param keystorePassword
* @param ks
* @throws FileNotFoundException
* @throws KeyStoreException
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws CertificateException
*/
private static void storeJceKeyStore(String location,
String keystorePassword, java.security.KeyStore ks)
throws FileNotFoundException, KeyStoreException, IOException,
NoSuchAlgorithmException, CertificateException {
File keystoreFile = new File(location);
FileOutputStream fos = new FileOutputStream(keystoreFile);
try {
ks.store(fos, keystorePassword.toCharArray());
} finally {
fos.close();
}
logger.info("Keystore created here: " + keystoreFile.getAbsolutePath());
}
private String password;
private Resource location;
private java.security.KeyStore keystore;
/**
* default constructor
*/
public KeyStore() {
this(PASSWORD, null);
}
/**
* KeyStore constructor
*
* @param password
* the password used to unlock the keystore
* @param location
* the location of the keystore
*/
public KeyStore(String password, Resource location) {
setPassword(password);
setLocation(location);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
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();
}
}
if (keystore.size() == 0) {
throw new Exception("Keystore is empty; it has no entries");
}
}
/**
* 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, (RSAPrivateKey) key);
}
return null;
}
public java.security.KeyStore getKeystore() {
return keystore;
}
public Resource getLocation() {
return location;
}
public String getPassword() {
return password;
}
public Provider getProvider() {
return keystore.getProvider();
}
public void setKeystore(java.security.KeyStore keystore) {
this.keystore = keystore;
}
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;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "KeyStore [password=" + password + ", location=" + location
+ ", keystore=" + keystore + "]";
}
}

View File

@ -0,0 +1,68 @@
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);
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
* #getBeanClass(org.w3c.dom.Element)
*/
@Override
protected Class<?> getBeanClass(Element element) {
return KeyStore.class;
}
}

View File

@ -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<BeanMetadataElement> signers = new ManagedList<BeanMetadataElement>();
List<Element> 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;
}
}

View File

@ -1,4 +1,4 @@
package org.mitre.oauth2.model.serializer;
package org.mitre.oauth2.view;
import java.io.Writer;
import java.lang.reflect.Type;

View File

@ -1,4 +1,4 @@
package org.mitre.oauth2.model.serializer;
package org.mitre.oauth2.view;
import java.io.Writer;
import java.lang.reflect.Type;

View File

@ -0,0 +1,5 @@
package org.mitre.openid.connect.exception;
public class ExpiredTokenException extends RuntimeException {
}

View File

@ -0,0 +1,5 @@
package org.mitre.openid.connect.exception;
public class InvalidJwtIssuerException extends RuntimeException {
}

View File

@ -0,0 +1,5 @@
package org.mitre.openid.connect.exception;
public class InvalidJwtSignatureException extends RuntimeException {
}

View File

@ -0,0 +1,195 @@
/**
*
*/
package org.mitre.openid.connect.token;
import java.util.Map;
import java.util.Set;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.service.impl.DefaultOAuth2ProviderTokenService;
import org.mitre.openid.connect.model.IdToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientCredentialsChecker;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.code.AuthorizationRequestHolder;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.stereotype.Component;
/**
* AccessToken granter for Authorization Code flow.
*
* Note: does this need to be able to grant straight OAuth2.0 Access Tokens as
* well as Connect Access Tokens?
*
*
* @author AANGANES
*
*/
@Component
public class ConnectAuthCodeTokenGranter implements TokenGranter {
private static final String GRANT_TYPE = "authorization_code";
@Autowired
private JdbcAuthorizationCodeServices authorizationCodeServices;
@Autowired
private ClientCredentialsChecker clientCredentialsChecker;
//TODO: Do we need to modify/update this?
@Autowired
private DefaultOAuth2ProviderTokenService tokenServices;
/**
* Default empty constructor
*/
public ConnectAuthCodeTokenGranter() {
}
/**
* Constructor for unit tests
*
* @param tokenServices
* @param authorizationCodeServices
* @param clientDetailsService
*/
public ConnectAuthCodeTokenGranter(
DefaultOAuth2ProviderTokenService tokenServices,
JdbcAuthorizationCodeServices authorizationCodeServices,
ClientDetailsService clientDetailsService) {
setTokenServices(tokenServices);
setAuthorizationCodeServices(authorizationCodeServices);
setClientCredentialsChecker(new ClientCredentialsChecker(clientDetailsService));
}
/**
* Grant an OpenID Connect Access Token
*
* @param grantType
* @param parameters
* @param clientId
* @param scope
*/
@Override
public OAuth2AccessToken grant(String grantType,
Map<String, String> parameters, String clientId, Set<String> scope) {
if (!GRANT_TYPE.equals(grantType)) {
return null;
}
String authorizationCode = parameters.get("code");
String redirectUri = parameters.get("redirect_uri");
if (authorizationCode == null) {
throw new OAuth2Exception("An authorization code must be supplied.");
}
AuthorizationRequestHolder storedAuth = authorizationCodeServices.consumeAuthorizationCode(authorizationCode);
if (storedAuth == null) {
throw new InvalidGrantException("Invalid authorization code: " + authorizationCode);
}
AuthorizationRequest unconfirmedAuthorizationRequest = storedAuth.getAuthenticationRequest();
if (unconfirmedAuthorizationRequest.getRequestedRedirect() != null
&& !unconfirmedAuthorizationRequest.getRequestedRedirect().equals(redirectUri)) {
throw new RedirectMismatchException("Redirect URI mismatch.");
}
if (clientId != null && !clientId.equals(unconfirmedAuthorizationRequest.getClientId())) {
// just a sanity check.
throw new InvalidClientException("Client ID mismatch");
}
// From SECOAUTH: Secret is not required in the authorization request, so it won't be available
// in the unconfirmedAuthorizationCodeAuth. We do want to check that a secret is provided
// in the new request, but that happens elsewhere.
//Validate credentials
AuthorizationRequest authorizationRequest = clientCredentialsChecker.validateCredentials(grantType, clientId,
unconfirmedAuthorizationRequest.getScope());
if (authorizationRequest == null) {
return null;
}
Authentication userAuth = storedAuth.getUserAuthentication();
OAuth2AccessTokenEntity token = tokenServices.createAccessToken(new OAuth2Authentication(authorizationRequest, userAuth));
/**
* Authorization request scope MUST include "openid", but access token request
* may or may not include the scope parameter. As long as the AuthorizationRequest
* has the proper scope, we can consider this a valid OpenID Connect request.
*/
if (authorizationRequest.getScope().contains("openid")) {
IdToken idToken = new IdToken();
//TODO: build IdToken
//Where does the data for the IdToken come from?
//TODO: insert IdToken into OAuth2AccessTokenEntity
}
return token;
}
/**
* @return the authorizationCodeServices
*/
public JdbcAuthorizationCodeServices getAuthorizationCodeServices() {
return authorizationCodeServices;
}
/**
* @param authorizationCodeServices the authorizationCodeServices to set
*/
public void setAuthorizationCodeServices(JdbcAuthorizationCodeServices authorizationCodeServices) {
this.authorizationCodeServices = authorizationCodeServices;
}
/**
* @return the clientCredentialsChecker
*/
public ClientCredentialsChecker getClientCredentialsChecker() {
return clientCredentialsChecker;
}
/**
* @param clientCredentialsChecker the clientCredentialsChecker to set
*/
public void setClientCredentialsChecker(ClientCredentialsChecker clientCredentialsChecker) {
this.clientCredentialsChecker = clientCredentialsChecker;
}
/**
* @return the tokenServices
*/
public DefaultOAuth2ProviderTokenService getTokenServices() {
return tokenServices;
}
/**
* @param tokenServices the tokenServices to set
*/
public void setTokenServices(DefaultOAuth2ProviderTokenService tokenServices) {
this.tokenServices = tokenServices;
}
}

View File

@ -1,4 +1,4 @@
package org.mitre.openid.connect.model.serializer;
package org.mitre.openid.connect.view;
import java.io.Writer;
import java.util.Map;

View File

@ -1,4 +1,4 @@
package org.mitre.openid.connect.model.serializer;
package org.mitre.openid.connect.view;
import java.io.Writer;
import java.util.Map;

View File

@ -0,0 +1,83 @@
/**
*
*/
package org.mitre.openid.connect.view;
import java.io.Writer;
import java.lang.reflect.Type;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.servlet.view.AbstractView;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* @author jricher
*
*/
public class JwkKeyListView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
public boolean shouldSkipField(FieldAttributes f) {
return false;
}
public boolean shouldSkipClass(Class<?> clazz) {
// skip the JPA binding wrapper
if (clazz.equals(BeanPropertyBindingResult.class)) {
return true;
}
return false;
}
})
.registerTypeAdapter(RSAPublicKey.class, new JsonSerializer<RSAPublicKey>() {
@Override
public JsonElement serialize(RSAPublicKey src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject o = new JsonObject();
o.addProperty("mod", src.getModulus().toString());
return o;
}
})
.create();
response.setContentType("application/json");
Writer out = response.getWriter();
Object obj = model.get("entity");
if (obj == null) {
obj = model;
}
gson.toJson(obj, out);
}
}

View File

@ -1,7 +1,12 @@
package org.mitre.openid.connect.web;
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;
import org.mitre.openid.connect.model.IdToken;
import org.mitre.openid.connect.model.IdTokenClaims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -10,17 +15,33 @@ import org.springframework.web.servlet.ModelAndView;
@Controller
public class CheckIDEndpoint {
@Autowired
JwtSigningAndValidationService jwtSignerService;
@RequestMapping("/checkid")
public ModelAndView checkID(@RequestParam("id_token") String tokenString, ModelAndView mav) {
if (!jwtSignerService.validateSignature(tokenString)) {
// can't validate
throw new InvalidJwtSignatureException(); // TODO: attach a view to this exception
}
// it's a valid signature, parse the token
IdToken token = IdToken.parse(tokenString);
// check the expiration
if (jwtSignerService.isJwtExpired(token)) {
// token has expired
throw new ExpiredTokenException(); // TODO create a view for this exception
}
// check the issuer (sanity check)
if (!jwtSignerService.validateIssuedJwt(token)) {
throw new InvalidJwtIssuerException(); // TODO: create a view for this exception
}
return new ModelAndView("jsonIdTokenView", "checkId", token);
return new ModelAndView("jsonIdTokenView", "checkId", token); // TODO: create a view for this
}
}

View File

@ -0,0 +1,30 @@
package org.mitre.openid.connect.web;
import java.security.PublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.List;
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;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class JsonWebKeyEndpoint {
@Autowired
JwtSigningAndValidationService jwtService;
@RequestMapping("/jwk")
public ModelAndView getJwk() {
List<PublicKey> keys = jwtService.getAllPublicKeys();
// TODO: check if keys are empty, return a 404 here?
return new ModelAndView("jwkKeyList", "keys", keys); // TODO: make a view
}
}

View File

@ -0,0 +1 @@
http\://www.mitre.org/schema/openid-connect/jwt-signer=org.mitre.jwt.signer.service.impl.JwtSignerNamespaceHandler

View File

@ -0,0 +1 @@
http\://www.mitre.org/schema/openid-connect/jwt-signer/jwt-signer.xsd=org/mitre/jwt/signer/service/impl/jwt-signer.xsd

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns="http://www.mitre.org/schema/openid-connect/jwt-signer"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.mitre.org/schema/openid-connect/jwt-signer"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"/>
<xs:element name="keystore">
<xs:annotation>
<xs:documentation>
Describes the JCE KeyStore necessary for certain
signers.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:complexContent>
<xs:extension base="beans:identifiedType">
<xs:attribute name="location" type="xs:string" use="required" />
<xs:attribute name="password" type="xs:string" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="service">
<xs:annotation>
<xs:documentation>
Configures the signer service with these signers.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:complexContent>
<xs:extension base="beans:identifiedType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="rsa">
<xs:annotation>
<xs:documentation>
Configures an RSA signer.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="bits" type="xs:string" />
<xs:attribute name="keystore-ref" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The reference to the bean that defines the
KeyStore.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="key-alias" type="xs:string"
use="required">
<xs:annotation>
<xs:documentation>
The alias to the KeyPair to use for
signing/verifying.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string">
<xs:annotation>
<xs:documentation>
The password to the KeyPair to use for
signing/verifying.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="hmac">
<xs:annotation>
<xs:documentation>
Configures an HMAC signer.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="bits" type="xs:integer" />
<xs:attribute name="passphrase" type="xs:string">
<xs:annotation>
<xs:documentation>
The passphrase used for signing/verifying.
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -3,7 +3,9 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
@ -12,6 +14,8 @@
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<security:global-method-security pre-post-annotations="enabled" proxy-target-class="true"/>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
@ -30,8 +34,8 @@
<!-- JSON views for each type of model object -->
<beans:bean id="jsonOpenIdConfigurationView" class="org.mitre.swd.view.JsonOpenIdConfigurationView" />
<beans:bean id="jsonSwdResponseView" class="org.mitre.swd.view.SwdResponse" />
<!-- <beans:bean id="jsonUserInfoView" class="org.mitre.openid.connect.model.serializer.JSONUserInfoView"/> -->
<!-- <beans:bean id="jsonIdTokenView" class="org.mitre.openid.connect.model.serializer.JSONIdTokenView"/> -->
<!-- <beans:bean id="jsonUserInfoView" class="org.mitre.openid.connect.view.JSONUserInfoView"/> -->
<!-- <beans:bean id="jsonIdTokenView" class="org.mitre.openid.connect.view.JSONIdTokenView"/> -->
<beans:import resource="controllers.xml" />

View File

@ -5,13 +5,18 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
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
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
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/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.mitre.org/schema/openid-connect/jwt-signer classpath:/org/mitre/jwt/signer/service/impl/jwt-signer.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<import resource="data-context.xml" />
<import resource="data-context.xml" />
<import resource="security-context.xml" />
<tx:annotation-driven transaction-manager="transactionManager" />
@ -22,6 +27,26 @@
<property name="showSql" value="true" />
</bean>
<!-- Authorization Code Service, used by TokenGranter -->
<bean id="jdbcAuthCodeServices" class="org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices">
<constructor-arg>
<bean class="org.apache.commons.dbcp.BasicDataSource"/>
</constructor-arg>
</bean>
<bean id="clientCredentialsChecker" class="org.springframework.security.oauth2.provider.ClientCredentialsChecker">
<constructor-arg>
<bean class="org.mitre.oauth2.service.impl.DefaultOAuth2ClientDetailsEntityService"/>
</constructor-arg>
</bean>
<!-- SECOAUTH Authorization Server, with our custom token granter plugged in -->
<oauth:authorization-server client-details-service-ref="defaultOAuth2ClientDetailsEntityService"
token-services-ref="defaultOAuth2ProviderTokenService" token-granter-ref="connectAuthCodeTokenGranter"
authorization-endpoint-url="/openidconnect/auth*">
<!-- <oauth:authorization-code disabled="true"/> -->
</oauth:authorization-server>
<!-- Map our custom exception classes to named views -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
@ -47,12 +72,19 @@
</map>
</property>
</bean>
<jwt-signer:keystore id="defaultKeystore" location="file:src/main/webapp/WEB-INF/spring/keystore.jks" password="changeit" />
<jwt-signer:service id="defaultSignerService">
<jwt-signer:rsa bits="256" keystore-ref="defaultKeystore" key-alias="test" password="changeit" />
<jwt-signer:hmac bits="256" passphrase="changeit" />
</jwt-signer:service>
<!-- scheduled tasks -->
<task:scheduler id="taskScheduler" pool-size="10" />
<task:executor id="taskExecutor" pool-size="5" />
<task:annotation-driven scheduler="taskScheduler" executor="taskExecutor" />
<context:component-scan annotation-config="true" base-package="org.mitre.openid" />
<context:component-scan annotation-config="true" base-package="org.mitre" />
</beans>

Binary file not shown.

View File

@ -14,6 +14,17 @@
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- filter through Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
@ -30,4 +41,11 @@
<url-pattern>/</url-pattern>
</servlet-mapping>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
</web-app>

View File

@ -1,7 +1,7 @@
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;
@ -9,14 +9,26 @@ 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.mitre.jwt.signer.impl.RsaSigner;
import org.mitre.jwt.signer.service.impl.KeyStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"file:src/main/webapp/WEB-INF/spring/application-context.xml",
"classpath:test-context.xml" })
public class JwtTest {
@Autowired
@Qualifier("testKeystore")
KeyStore keystore;
@Test
public void testToStringPlaintext() {
Jwt jwt = new Jwt();
@ -60,13 +72,13 @@ public class JwtTest {
// TODO Auto-generated catch block
e.printStackTrace();
}
JwtSigner signer = new Hmac256Signer(key);
JwtSigner signer = new HmacSigner(key);
signer.sign(jwt);
/*
* Expected string based on the following strucutres, serialized exactly as follows and base64 encoded:
* Expected string based on the following structures, serialized exactly as follows and base64 encoded:
*
* header: {"typ":"JWT","alg":"HS256"}
* claims: {"exp":1300819380,"iss":"joe","http://example.com/is_root":true}
@ -84,6 +96,40 @@ public class JwtTest {
}
/**
* @throws Exception
*/
@Test
public void testGenerateRsaSignature() throws Exception {
// java.security.KeyStore ks = KeyStore.generateRsaKeyPair(keystore
// .getLocation().getFile().getPath(), "OpenID Connect Server",
// "twentyYears", KeyStore.PASSWORD, KeyStore.PASSWORD, 30, 365*20);
//
// keystore.setKeystore(ks);
Jwt jwt = new Jwt();
jwt.getHeader().setType("JWT");
jwt.getHeader().setAlgorithm("RS256");
jwt.getClaims().setExpiration(new Date(1300819380L * 1000L));
jwt.getClaims().setIssuer("joe");
jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE);
JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.DEFAULT, keystore, "twentyYears");
((RsaSigner) signer).afterPropertiesSet();
signer.sign(jwt);
String signature = "TW0nOd_vr1rnV7yIS-lIV2-00V_zJMWxzOc3Z7k3gvMO2aIjIGjZ9nByZMI0iL5komMxYXPl_RCkbd9OKiPkk4iK5CDj7Mawbzu95LgEOOqdXO1f7-IqX9dIvJhVXXInLD3RsGvavyheIqNeFEVidLrJo30tBchB_niljEW7VeX8nSZfiCOdbOTW3hu0ycnon7wFpejb-cRP_S0iqGxCgbYXJzqPT192EHmRy_wmFxxIy9Lc84uqNkAZSIn1jVIeAemm22RoWbq0xLVLTRyiZoxJTUzac_VteiSPRNFlUQuOdxqNf0Hxqh_wVfX1mfXUzv0D8vHJVy6aIqTISmn-qg";
String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.TW0nOd_vr1rnV7yIS-lIV2-00V_zJMWxzOc3Z7k3gvMO2aIjIGjZ9nByZMI0iL5komMxYXPl_RCkbd9OKiPkk4iK5CDj7Mawbzu95LgEOOqdXO1f7-IqX9dIvJhVXXInLD3RsGvavyheIqNeFEVidLrJo30tBchB_niljEW7VeX8nSZfiCOdbOTW3hu0ycnon7wFpejb-cRP_S0iqGxCgbYXJzqPT192EHmRy_wmFxxIy9Lc84uqNkAZSIn1jVIeAemm22RoWbq0xLVLTRyiZoxJTUzac_VteiSPRNFlUQuOdxqNf0Hxqh_wVfX1mfXUzv0D8vHJVy6aIqTISmn-qg";
String actual = jwt.toString();
assertThat(actual, equalTo(expected));
assertThat(jwt.getSignature(), equalTo(signature));
}
@Test
public void testValidateHmacSignature() {
// sign it
@ -95,7 +141,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 +167,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));

View File

@ -0,0 +1,54 @@
package org.mitre.jwt.signer.service.impl;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.Key;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SuppressWarnings("restriction") // I know...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"file:src/main/webapp/WEB-INF/spring/application-context.xml",
"classpath:test-context.xml" })
public class KeyStoreTest {
@Autowired
@Qualifier("testKeystore")
KeyStore keystore;
@Test
public void storeKeyPair() throws GeneralSecurityException, IOException {
java.security.KeyStore ks = KeyStore.generateRsaKeyPair(keystore
.getLocation().getFile().getPath(), "OpenID Connect Server",
"test", KeyStore.PASSWORD, KeyStore.PASSWORD, 30, 30);
keystore.setKeystore(ks);
assertThat(ks, not(nullValue()));
}
@Test
public void readKey() throws GeneralSecurityException {
Key key = keystore.getKeystore().getKey("test",
KeyStore.PASSWORD.toCharArray());
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out
.println(new sun.misc.BASE64Encoder().encode(key.getEncoded()));
System.out.println("-----END PRIVATE KEY-----");
assertThat(key, not(nullValue()));
}
}

Binary file not shown.

View File

@ -1,7 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" >
xmlns:jwt-signer="http://www.mitre.org/schema/openid-connect/jwt-signer"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.mitre.org/schema/openid-connect/jwt-signer http://www.mitre.org/schema/openid-connect/jwt-signer/jwt-signer.xsd" >
<!-- Creates an in-memory database populated with test jdbc -->
<bean id="dataSource" class="org.mitre.jdbc.datasource.H2DataSourceFactory">
@ -33,4 +36,7 @@
</map>
</property>
</bean>
<jwt-signer:keystore id="testKeystore" location="file:src/test/resources/keystore.jks" password="changeit" />
</beans>