From ee28d560311ac23ebaf90a68147459ea1e7cdd7f Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Fri, 1 Jun 2012 10:51:28 -0400 Subject: [PATCH 1/6] initial implementation of x509 and JWK key retrieval --- openid-connect-client/.classpath | 2 + .../org.eclipse.wst.common.component | 1 + .../client/OIDCAuthenticationFilter.java | 16 ++ .../client/OIDCServerConfiguration.java | 98 ++++++++- .../openid/connect/client/UrlValidator.java | 34 +++ .../client/OIDCServerConfigurationTest.java | 104 +++++++++ openid-connect-common/.classpath | 3 + .../org.eclipse.wst.common.component | 1 + .../java/org/mitre/jwk/model/AbstractJwk.java | 66 ++++++ .../src/main/java/org/mitre/jwk/model/EC.java | 96 ++++++++ .../main/java/org/mitre/jwk/model/Jwk.java | 18 ++ .../main/java/org/mitre/jwk/model/Rsa.java | 67 ++++++ .../src/main/java/org/mitre/util/Utility.java | 79 +++++++ .../test/java/org/mitre/util/UtilityTest.java | 206 ++++++++++++++++++ .../src/test/resources/jwk/jwkFail | 15 ++ .../src/test/resources/jwk/jwkSuccess | 15 ++ 16 files changed, 820 insertions(+), 1 deletion(-) create mode 100644 openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java create mode 100644 openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java create mode 100644 openid-connect-common/src/main/java/org/mitre/jwk/model/AbstractJwk.java create mode 100644 openid-connect-common/src/main/java/org/mitre/jwk/model/EC.java create mode 100644 openid-connect-common/src/main/java/org/mitre/jwk/model/Jwk.java create mode 100644 openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java create mode 100644 openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java create mode 100644 openid-connect-common/src/test/resources/jwk/jwkFail create mode 100644 openid-connect-common/src/test/resources/jwk/jwkSuccess diff --git a/openid-connect-client/.classpath b/openid-connect-client/.classpath index 1b28ee5d7..40f68d2dc 100644 --- a/openid-connect-client/.classpath +++ b/openid-connect-client/.classpath @@ -1,6 +1,8 @@ + + diff --git a/openid-connect-client/.settings/org.eclipse.wst.common.component b/openid-connect-client/.settings/org.eclipse.wst.common.component index fc2629825..e70fe2d47 100755 --- a/openid-connect-client/.settings/org.eclipse.wst.common.component +++ b/openid-connect-client/.settings/org.eclipse.wst.common.component @@ -3,5 +3,6 @@ + diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java index c7697048b..4ec398cbd 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java @@ -132,4 +132,20 @@ public class OIDCAuthenticationFilter extends AbstractOIDCAuthenticationFilter { public void setTokenEndpointURI(String tokenEndpointURI) { oidcServerConfig.setTokenEndpointURI(tokenEndpointURI); } + + public void setX509EncryptUrl(String x509EncryptUrl) { + oidcServerConfig.setX509EncryptUrl(x509EncryptUrl); + } + + public void setX509SigningUrl(String x509SigningUrl) { + oidcServerConfig.setX509SigningUrl(x509SigningUrl); + } + + public void setJwkEncryptUrl(String jwkEncryptUrl) { + oidcServerConfig.setJwkEncryptUrl(jwkEncryptUrl); + } + + public void setJwkSigningUrl(String jwkSigningUrl) { + oidcServerConfig.setJwkSigningUrl(jwkSigningUrl); + } } diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java index 333e4505c..2d0d226b2 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java @@ -15,6 +15,15 @@ ******************************************************************************/ package org.mitre.openid.connect.client; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.Key; + +import org.mitre.util.Utility; + +import com.google.gson.JsonObject; + /** * @author nemonik * @@ -30,6 +39,18 @@ public class OIDCServerConfiguration { private String clientSecret; private String clientId; + + private String x509EncryptUrl; + + private String x509SigningUrl; + + private String jwkEncryptUrl; + + private String jwkSigningUrl; + + private Key encryptKey; + + private Key signingKey; public String getAuthorizationEndpointURI() { return authorizationEndpointURI; @@ -70,6 +91,77 @@ public class OIDCServerConfiguration { public void setTokenEndpointURI(String tokenEndpointURI) { this.tokenEndpointURI = tokenEndpointURI; } + + public String getX509EncryptUrl() { + return x509EncryptUrl; + } + + public String getX509SigningUrl() { + return x509SigningUrl; + } + + public String getJwkEncryptUrl() { + return jwkEncryptUrl; + } + + public String getJwkSigningUrl() { + return jwkSigningUrl; + } + + public void setX509EncryptUrl(String x509EncryptUrl) { + this.x509EncryptUrl = x509EncryptUrl; + } + + public void setX509SigningUrl(String x509SigningUrl) { + this.x509SigningUrl = x509SigningUrl; + } + + public void setJwkEncryptUrl(String jwkEncryptUrl) { + this.jwkEncryptUrl = jwkEncryptUrl; + } + + public void setJwkSigningUrl(String jwkSigningUrl) { + this.jwkSigningUrl = jwkSigningUrl; + } + + public Key getSigningKey() throws Exception { + if(signingKey == null){ + if(x509SigningUrl != null){ + File file = new File(x509SigningUrl); + URL url = file.toURI().toURL(); + signingKey = Utility.retrieveX509Key(url); + } + else if (jwkSigningUrl != null){ + File file = new File(jwkSigningUrl); + URL url = file.toURI().toURL(); + signingKey = Utility.retrieveJwkKey(url); + } + } + return signingKey; + } + + public Key getEncryptionKey() throws Exception { + if(encryptKey == null){ + if(x509EncryptUrl != null){ + File file = new File(x509EncryptUrl); + URL url = file.toURI().toURL(); + encryptKey = Utility.retrieveX509Key(url); + } + else if (jwkEncryptUrl != null){ + File file = new File(jwkEncryptUrl); + URL url = file.toURI().toURL(); + encryptKey = Utility.retrieveJwkKey(url); + } + } + return encryptKey; + } + + public void checkKeys() throws Exception { + encryptKey = null; + signingKey = null; + getEncryptionKey(); + getSigningKey(); + } @Override public String toString() { @@ -77,7 +169,11 @@ public class OIDCServerConfiguration { + authorizationEndpointURI + ", tokenEndpointURI=" + tokenEndpointURI + ", checkIDEndpointURI=" + checkIDEndpointURI + ", clientSecret=" + clientSecret - + ", clientId=" + clientId + "]"; + + ", clientId=" + clientId + ", x509EncryptedUrl=" + + x509EncryptUrl + ", jwkEncryptedUrl=" + + jwkEncryptUrl + ", x509SigningUrl=" + + x509SigningUrl + ", jwkSigningUrl=" + + jwkSigningUrl + "]"; } } diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java new file mode 100644 index 000000000..66c723f0a --- /dev/null +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java @@ -0,0 +1,34 @@ +package org.mitre.openid.connect.client; + +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + +public class UrlValidator implements Validator{ + + + + @Override + public boolean supports(Class clzz) { + return OIDCServerConfiguration.class.equals(clzz); + } + + @Override + public void validate(Object obj, Errors e) { + ValidationUtils.rejectIfEmpty(e, "x509EncryptUrl", "x509EncryptUrl.empty"); + + } + + public void validate1(Object obj, Errors e) { + ValidationUtils.rejectIfEmpty(e, "x509SigningUrl", "x509SigningUrl.empty"); + } + + public void validate2(Object obj, Errors e) { + ValidationUtils.rejectIfEmpty(e, "jwkEncryptUrl", "jwkEncryptUrl.empty"); + } + + public void validate3(Object obj, Errors e) { + ValidationUtils.rejectIfEmpty(e, "jwkSigningUrl", "jwkSigningUrl.empty"); + } + +} \ No newline at end of file diff --git a/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java b/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java new file mode 100644 index 000000000..67456b7a1 --- /dev/null +++ b/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java @@ -0,0 +1,104 @@ +package org.mitre.openid.connect.client; + +import java.net.URL; +import java.security.Key; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mitre.util.Utility; + +import junit.framework.TestCase; + +public class OIDCServerConfigurationTest extends TestCase { + + URL jwkUrl = this.getClass().getResource("/jwk/jwk"); + URL x509Url = this.getClass().getResource("/x509/x509"); + URL jwkEncryptedUrl = this.getClass().getResource("/jwk/jwkEncrypted"); + URL x509EncryptedUrl = this.getClass().getResource("/x509/x509Encrypted"); + OIDCServerConfiguration oidc; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + oidc = new OIDCServerConfiguration(); + super.setUp(); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + /** + * Test method for {@link org.mitre.util.Utility#retrieveJwk(java.lang.String)}. + * @throws Exception + */ + @Test + public void testGetSigningKeyBoth() throws Exception { + oidc.setX509SigningUrl(x509Url.getPath()); + oidc.setJwkSigningUrl(jwkUrl.getPath()); + Key key = oidc.getSigningKey(); + assertEquals(key, Utility.retrieveX509Key(x509Url)); + } + + @Test + public void testGetSigningKeyJwk() throws Exception { + oidc.setX509SigningUrl(null); + oidc.setJwkSigningUrl(jwkUrl.getPath()); + Key key1 = oidc.getSigningKey(); + assertEquals(key1, Utility.retrieveJwkKey(jwkUrl)); + } + + @Test + public void testGetSigningKeyX509() throws Exception { + oidc.setX509SigningUrl(x509Url.getPath()); + oidc.setJwkSigningUrl(null); + Key key2 = oidc.getSigningKey(); + assertEquals(key2, Utility.retrieveX509Key(x509Url)); + } + + @Test + public void testGetSigningKeyNone() throws Exception { + oidc.setX509SigningUrl(null); + oidc.setJwkSigningUrl(null); + Key key3 = oidc.getSigningKey(); + assertEquals(key3, null); + } + + @Test + public void testGetEncryptionKeyBoth() throws Exception { + oidc.setX509EncryptUrl(x509EncryptedUrl.getPath()); + oidc.setJwkEncryptUrl(jwkEncryptedUrl.getPath()); + Key key = oidc.getEncryptionKey(); + assertEquals(key, Utility.retrieveX509Key(x509EncryptedUrl)); + } + + @Test + public void testGetEncryptionKeyJwk() throws Exception { + oidc.setX509EncryptUrl(null); + oidc.setJwkEncryptUrl(jwkEncryptedUrl.getPath()); + Key key1 = oidc.getEncryptionKey(); + assertEquals(key1, Utility.retrieveJwkKey(jwkEncryptedUrl)); + } + + @Test + public void testGetEncryptionKeyX509() throws Exception { + oidc.setX509EncryptUrl(x509EncryptedUrl.getPath()); + oidc.setJwkEncryptUrl(null); + Key key2 = oidc.getEncryptionKey(); + assertEquals(key2, Utility.retrieveX509Key(x509EncryptedUrl)); + } + + @Test + public void testGetEncryptionKeyNone() throws Exception { + oidc.setX509EncryptUrl(null); + oidc.setJwkEncryptUrl(null); + Key key3 = oidc.getEncryptionKey(); + assertEquals(key3, null); + } +} diff --git a/openid-connect-common/.classpath b/openid-connect-common/.classpath index 1b28ee5d7..5d8133f83 100644 --- a/openid-connect-common/.classpath +++ b/openid-connect-common/.classpath @@ -1,6 +1,8 @@ + + @@ -9,3 +11,4 @@ + diff --git a/openid-connect-common/.settings/org.eclipse.wst.common.component b/openid-connect-common/.settings/org.eclipse.wst.common.component index 1e24c2b7c..c681a1288 100644 --- a/openid-connect-common/.settings/org.eclipse.wst.common.component +++ b/openid-connect-common/.settings/org.eclipse.wst.common.component @@ -2,5 +2,6 @@ + diff --git a/openid-connect-common/src/main/java/org/mitre/jwk/model/AbstractJwk.java b/openid-connect-common/src/main/java/org/mitre/jwk/model/AbstractJwk.java new file mode 100644 index 000000000..483dbe170 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwk/model/AbstractJwk.java @@ -0,0 +1,66 @@ +package org.mitre.jwk.model; + +import com.google.gson.JsonObject; + +public abstract class AbstractJwk implements Jwk{ + + public static final String ALGORITHM = "alg"; + public static final String USE = "use"; + public static final String KEY_ID = "kid"; + + private String kid; + private String alg; + private String use; + + public AbstractJwk(JsonObject object){ + init(object); + } + + /* (non-Javadoc) + * @see org.mitre.jwk.model.Jwk2#getAlg() + */ + @Override + public String getAlg() { + return alg; + } + + public void setAlg(String alg) { + this.alg = alg; + } + + /* (non-Javadoc) + * @see org.mitre.jwk.model.Jwk2#getKid() + */ + @Override + public String getKid() { + return kid; + } + + public void setKid(String kid) { + this.kid = kid; + } + + /* (non-Javadoc) + * @see org.mitre.jwk.model.Jwk2#getUse() + */ + @Override + public String getUse() { + return use; + } + + public void setUse(String use) { + this.use = use; + } + + protected void init(JsonObject object){ + if(object.get(ALGORITHM) != null){ + setAlg(object.get(ALGORITHM).getAsString()); + } + if(object.get(KEY_ID) != null){ + setKid(object.get(KEY_ID).getAsString()); + } + if(object.get(USE) != null){ + setUse(object.get(USE).getAsString()); + } + } +} \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/jwk/model/EC.java b/openid-connect-common/src/main/java/org/mitre/jwk/model/EC.java new file mode 100644 index 000000000..c24bdd037 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwk/model/EC.java @@ -0,0 +1,96 @@ +package org.mitre.jwk.model; + +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.spec.ECFieldF2m; +import java.security.spec.EllipticCurve; +import java.security.spec.InvalidKeySpecException; + +import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.JCEECPublicKey; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +import com.google.gson.JsonObject; + +public class EC extends AbstractJwk{ + + public static final String CURVE = "crv"; + public static final String X = "x"; + public static final String Y = "y"; + + private String crv; + private String x; + private String y; + + JsonObject object = new JsonObject(); + + public String getCrv() { + return crv; + } + + public void setCrv(String crv) { + this.crv = crv; + } + + public String getX() { + return x; + } + + public void setX(String x) { + this.x = x; + } + + public String getY() { + return y; + } + + public void setY(String y) { + this.y = y; + } + + public EC(JsonObject object) { + super(object); + } + + public void init(JsonObject object){ + super.init(object); + setCrv(object.get(CURVE).getAsString()); + setX(object.get(X).getAsString()); + setY(object.get(Y).getAsString()); + } + + @Override + public PublicKey getKey() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException { + // TODO Auto-generated method stub + + byte[] x_byte = Base64.decodeBase64(x); + BigInteger x_int = new BigInteger(x_byte); + byte[] y_byte = Base64.decodeBase64(y); + BigInteger y_int = new BigInteger(y_byte); + + ECNamedCurveParameterSpec curveSpec = ECNamedCurveTable.getParameterSpec(crv); + BigInteger orderOfGen = curveSpec.getH(); + int cofactor = Math.abs(curveSpec.getN().intValue()); + ECCurve crv = curveSpec.getCurve(); + BigInteger a = crv.getA().toBigInteger(); + BigInteger b = crv.getB().toBigInteger(); + int fieldSize = crv.getFieldSize(); + ECFieldF2m field = new ECFieldF2m(fieldSize); + EllipticCurve curve = new EllipticCurve(field, a, b); + //ECPoint.Fp point = new ECPoint.Fp(curve, arg1, arg2); + return null; + + //ECParameterSpec paramSpec = new ECParameterSpec(curve, point, orderOfGen, cofactor); + //ECPublicKeySpec spec = new ECPublicKeySpec(point, paramSpec); + //PublicKey key = new JCEECPublicKey("ECDCA", spec); + + //return key; + } +} \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/jwk/model/Jwk.java b/openid-connect-common/src/main/java/org/mitre/jwk/model/Jwk.java new file mode 100644 index 000000000..67edc2b15 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwk/model/Jwk.java @@ -0,0 +1,18 @@ +package org.mitre.jwk.model; + +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.spec.InvalidKeySpecException; + +public interface Jwk { + + public abstract String getAlg(); + + public abstract String getKid(); + + public abstract String getUse(); + + public abstract Key getKey() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException; + +} \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java b/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java new file mode 100644 index 000000000..dc1c795f7 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java @@ -0,0 +1,67 @@ +package org.mitre.jwk.model; + +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; + +import org.apache.commons.codec.binary.Base64; + +import com.google.gson.JsonObject; + +public class Rsa extends AbstractJwk{ + + public static final String MODULUS = "mod"; + public static final String EXPONENT = "exp"; + + private String mod; + private String exp; + + JsonObject object = new JsonObject(); + + public String getMod() { + return mod; + } + + public void setMod(String mod) { + this.mod = mod; + } + + public String getExp() { + return exp; + } + + public void setExp(String exp) { + this.exp = exp; + } + + public Rsa(JsonObject object){ + super(object); + } + + public void init(JsonObject object){ + super.init(object); + setMod(object.get(MODULUS).getAsString()); + setExp(object.get(EXPONENT).getAsString()); + } + + @Override + public PublicKey getKey() throws NoSuchAlgorithmException, InvalidKeySpecException { + // TODO Auto-generated method stub + byte[] modulusByte = Base64.decodeBase64(mod); + BigInteger modulus = new BigInteger(modulusByte); + byte[] exponentByte = Base64.decodeBase64(exp); + BigInteger exponent = new BigInteger(exponentByte); + + RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); + KeyFactory factory = KeyFactory.getInstance("RSA"); + PublicKey pub = factory.generatePublic(spec); + + return pub; + } +} \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/util/Utility.java b/openid-connect-common/src/main/java/org/mitre/util/Utility.java index d6655286a..5bc809bd5 100644 --- a/openid-connect-common/src/main/java/org/mitre/util/Utility.java +++ b/openid-connect-common/src/main/java/org/mitre/util/Utility.java @@ -15,8 +15,34 @@ ******************************************************************************/ package org.mitre.util; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigInteger; +import java.net.URL; +import java.security.Key; +import java.security.KeyFactory; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPublicKeySpec; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.List; + import javax.servlet.http.HttpServletRequest; +import org.apache.commons.codec.binary.Base64; +import org.mitre.jwk.model.AbstractJwk; +import org.mitre.jwk.model.EC; +import org.mitre.jwk.model.Jwk; +import org.mitre.jwk.model.Rsa; + +import com.google.gson.JsonArray; +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + /** * A collection of utility methods. * @@ -43,4 +69,57 @@ public class Utility { } return issuer; } + + public static List retrieveJwk(URL path) throws Exception { + List keys = new ArrayList(); + + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(path.openStream()))).getAsJsonObject(); + JsonArray getArray = json.getAsJsonArray("jwk"); + + for(int i = 0; i < getArray.size(); i++){ + + JsonObject object = getArray.get(i).getAsJsonObject(); + String algorithm = object.get("alg").getAsString(); + + if(algorithm.equals("RSA")){ + Rsa rsa = new Rsa(object); + keys.add(rsa); + } + + else{ + EC ec = new EC(object); + keys.add(ec); + } + } + return keys; + } + + public static Key retrieveX509Key(URL url) throws Exception { + + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) factory.generateCertificate(url.openStream()); + Key key = cert.getPublicKey(); + + return key; + } + + public static Key retrieveJwkKey(URL url) throws Exception { + + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + JsonArray getArray = json.getAsJsonArray("jwk"); + JsonObject object = getArray.get(0).getAsJsonObject(); + + byte[] modulusByte = Base64.decodeBase64(object.get("mod").getAsString()); + BigInteger modulus = new BigInteger(modulusByte); + byte[] exponentByte = Base64.decodeBase64(object.get("exp").getAsString()); + BigInteger exponent = new BigInteger(exponentByte); + + RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); + KeyFactory factory = KeyFactory.getInstance("RSA"); + PublicKey pub = factory.generatePublic(spec); + + return pub; + } } diff --git a/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java b/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java new file mode 100644 index 000000000..6404eda77 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java @@ -0,0 +1,206 @@ +/** + * + */ +package org.mitre.util; + +import java.security.Key; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.RSAPublicKeySpec; +import java.util.List; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.math.BigInteger; +import java.net.URL; + +import junit.framework.TestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mitre.jwk.model.Jwk; +import org.mitre.jwk.model.Rsa; +import org.mitre.jwk.model.EC; +import org.mitre.util.Utility; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.apache.commons.codec.binary.*; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.jce.provider.JCEECPublicKey; + +/** + * @author DERRYBERRY + * + */ +public class UtilityTest extends TestCase{ + + URL url = this.getClass().getResource("/jwk/jwkSuccess"); + URL certUrl = this.getClass().getResource("/x509/certTest"); + URL rsaUrl = this.getClass().getResource("/jwk/rsaOnly"); + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + super.setUp(); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + /** + * Test method for {@link org.mitre.util.Utility#retrieveJwk(java.lang.String)}. + * @throws Exception + */ + @Test + public void testRetrieveJwk() throws Exception { + + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + JsonArray getArray = json.getAsJsonArray("jwk"); + + List list = Utility.retrieveJwk(url); + + for(int i = 0; i < list.size(); i++){ + + Jwk jwk = list.get(i); + JsonObject object = getArray.get(i).getAsJsonObject(); + + assertEquals(object.get("alg").getAsString(), jwk.getAlg()); + if(object.get("kid") != null){ + assertEquals(object.get("kid").getAsString(), jwk.getKid()); + } + if(object.get("use") != null){ + assertEquals(object.get("use").getAsString(), jwk.getUse()); + } + + if(jwk instanceof Rsa){ + assertEquals(object.get("mod").getAsString(), ((Rsa) jwk).getMod()); + assertEquals(object.get("exp").getAsString(), ((Rsa) jwk).getExp()); + } + else { + assertEquals(object.get("crv").getAsString(), ((EC) jwk).getCrv()); + assertEquals(object.get("x").getAsString(), ((EC) jwk).getX()); + assertEquals(object.get("y").getAsString(), ((EC) jwk).getY()); + } + } + } + + @Test + public void testMakeRsa() throws Exception{ + + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + JsonArray getArray = json.getAsJsonArray("jwk"); + + List list = Utility.retrieveJwk(url); + + for(int i = 0; i < list.size(); i++){ + Jwk jwk = list.get(i); + JsonObject object = getArray.get(i).getAsJsonObject(); + + if(jwk instanceof Rsa){ + + RSAPublicKey key = ((RSAPublicKey) ((Rsa) jwk).getKey()); + + byte[] mod = Base64.decodeBase64(object.get("mod").getAsString()); + BigInteger modInt = new BigInteger(mod); + assertEquals(modInt, key.getModulus()); + + byte[] exp = Base64.decodeBase64(object.get("exp").getAsString()); + BigInteger expInt = new BigInteger(exp); + assertEquals(expInt, key.getPublicExponent()); + } + } + } + + @Test + public void testRetriveX509Key() throws Exception { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + X509Certificate x509 = (X509Certificate) factory.generateCertificate(certUrl.openStream()); + Key key = Utility.retrieveX509Key(certUrl); + assertEquals(x509.getPublicKey(), key); + assertEquals("RSA", key.getAlgorithm()); + assertEquals("X.509", key.getFormat()); + } + + public void testRetriveJwkKey() throws Exception { + Key key = Utility.retrieveJwkKey(rsaUrl); + + JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(rsaUrl.openStream()))).getAsJsonObject(); + JsonArray getArray = json.getAsJsonArray("jwk"); + JsonObject object = getArray.get(0).getAsJsonObject(); + + byte[] modulusByte = Base64.decodeBase64(object.get("mod").getAsString()); + BigInteger modulus = new BigInteger(modulusByte); + byte[] exponentByte = Base64.decodeBase64(object.get("exp").getAsString()); + BigInteger exponent = new BigInteger(exponentByte); + + RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); + KeyFactory factory = KeyFactory.getInstance("RSA"); + PublicKey pub = factory.generatePublic(spec); + + assertEquals(pub, key); + } + + //@Test + //public void testMakeEC() throws Exception{ + + /*JsonParser parser = new JsonParser(); + JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + JsonArray getArray = json.getAsJsonArray("jwk"); + + List list = Utility.retrieveJwk(url); + + for(int i = 0; i < list.size(); i++){ + Jwk jwk = list.get(i); + JsonObject object = getArray.get(i).getAsJsonObject(); + + if(jwk instanceof EC){ + + ECPublicKey key = ((ECPublicKey) ((EC) jwk).getKey()); + + byte[] xArray = Base64.decodeBase64(object.get("x").getAsString()); + BigInteger xInt = new BigInteger(xArray); + byte[] yArray = Base64.decodeBase64(object.get("y").getAsString()); + BigInteger yInt = new BigInteger(yArray); + + String curveName = object.get("crv").getAsString(); + ECNamedCurveParameterSpec curveSpec = ECNamedCurveTable.getParameterSpec(curveName); + ECCurve crv = curveSpec.getCurve(); + BigInteger a = crv.getA().toBigInteger(); + BigInteger b = crv.getB().toBigInteger(); + int fieldSize = crv.getFieldSize(); + BigInteger orderOfGen = curveSpec.getH(); + int cofactor = Math.abs(curveSpec.getN().intValue()); + + assertEquals(a, key.getParams().getCurve().getA()); + assertEquals(b, key.getParams().getCurve().getB()); + assertEquals(fieldSize, key.getParams().getCurve().getField()); + assertEquals(orderOfGen, key.getParams().getOrder()); + assertEquals(cofactor, key.getParams().getCofactor()); + assertEquals(xInt, key.getW().getAffineX()); + assertEquals(yInt, key.getW().getAffineY()); + } + }*/ + //fail("method not implemented"); + //} + + +} \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwk/jwkFail b/openid-connect-common/src/test/resources/jwk/jwkFail new file mode 100644 index 000000000..4a208df47 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwk/jwkFail @@ -0,0 +1,15 @@ + {"jwk": + [ + {"alg":"never", + "crv":"gonna", + "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", + "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", + "use":"give", + "kid":"1"}, + + {"alg":"you", + "mod": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "exp":"up", + "kid":"rick astley"} + ] + } \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwk/jwkSuccess b/openid-connect-common/src/test/resources/jwk/jwkSuccess new file mode 100644 index 000000000..1ad6f5d5f --- /dev/null +++ b/openid-connect-common/src/test/resources/jwk/jwkSuccess @@ -0,0 +1,15 @@ + {"jwk": + [ + {"alg":"EC", + "crv":"P-256", + "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", + "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", + "use":"enc", + "kid":"1"}, + + {"alg":"RSA", + "mod": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "exp":"AQAB", + "kid":"2011-04-29"} + ] + } \ No newline at end of file From fad6caa968783d768814cc9f93f5530f8aa3ef91 Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Thu, 7 Jun 2012 14:28:09 -0400 Subject: [PATCH 2/6] Added testing for signers for Hmac, Rsa, and Plaintext --- .../main/java/org/mitre/jwt/model/Jwt.java | 2 +- .../java/org/mitre/jwt/model/JwtClaims.java | 1 - .../mitre/jwt/signer/AbstractJwtSigner.java | 8 +- .../java/org/mitre/jwt/signer/JwtSigner.java | 6 +- .../org/mitre/jwt/signer/impl/HmacSigner.java | 17 +- .../org/mitre/jwt/signer/impl/RsaSigner.java | 17 +- .../JwtSigningAndValidationService.java | 7 +- ...bstractJwtSigningAndValidationService.java | 54 +++++++ ...DynamicJwtSigningAndValidationService.java | 146 ++++++++++++++++++ ...JwtSigningAndValidationServiceDefault.java | 109 ++++--------- .../mitre/jwt/signer/impl/HmacSignerTest.java | 73 +++++++++ .../jwt/signer/impl/PlaintextSignerTest.java | 55 +++++++ .../mitre/jwt/signer/impl/RsaSignerTest.java | 99 ++++++++++++ ...micJwtSigningAndValidationServiceTest.java | 64 ++++++++ .../test/java/org/mitre/util/UtilityTest.java | 2 +- .../src/test/resources/jwk/rsaOnly | 8 + .../src/test/resources/jwt/claims | 6 + .../src/test/resources/jwt/hs256 | 2 + .../src/test/resources/jwt/hs384 | 2 + .../src/test/resources/jwt/hs512 | 2 + .../src/test/resources/jwt/plaintext | 2 + .../src/test/resources/jwt/rs256 | 2 + .../src/test/resources/jwt/rs384 | 2 + .../src/test/resources/jwt/rs512 | 2 + .../src/test/resources/x509/HmacJwt | 6 + .../src/test/resources/x509/x509Cert | 15 ++ 26 files changed, 609 insertions(+), 100 deletions(-) create mode 100644 openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java create mode 100644 openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java create mode 100644 openid-connect-common/src/test/resources/jwk/rsaOnly create mode 100644 openid-connect-common/src/test/resources/jwt/claims create mode 100644 openid-connect-common/src/test/resources/jwt/hs256 create mode 100644 openid-connect-common/src/test/resources/jwt/hs384 create mode 100644 openid-connect-common/src/test/resources/jwt/hs512 create mode 100644 openid-connect-common/src/test/resources/jwt/plaintext create mode 100644 openid-connect-common/src/test/resources/jwt/rs256 create mode 100644 openid-connect-common/src/test/resources/jwt/rs384 create mode 100644 openid-connect-common/src/test/resources/jwt/rs512 create mode 100644 openid-connect-common/src/test/resources/x509/HmacJwt create mode 100644 openid-connect-common/src/test/resources/x509/x509Cert diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java index 39d609bf3..ca0474b88 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/Jwt.java @@ -133,7 +133,7 @@ public class Jwt { return h64 + "." + c64; } - + /** * Parse a wire-encoded JWT */ diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java index 0c4807baf..1831edf10 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java @@ -25,7 +25,6 @@ import java.util.Map.Entry; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; public class JwtClaims extends ClaimSet { diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java index 7aeeb4cb3..5b5e427a2 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/AbstractJwtSigner.java @@ -15,6 +15,7 @@ ******************************************************************************/ package org.mitre.jwt.signer; +import java.security.NoSuchAlgorithmException; import java.util.List; import org.mitre.jwt.model.Jwt; @@ -52,9 +53,10 @@ public abstract class AbstractJwtSigner implements JwtSigner { * * @param jwt the jwt to sign * @return the signed jwt + * @throws NoSuchAlgorithmException */ @Override - public Jwt sign(Jwt jwt) { + public Jwt sign(Jwt jwt) throws NoSuchAlgorithmException { if (!Objects.equal(algorithm, jwt.getHeader().getAlgorithm())) { // algorithm type doesn't match // TODO: should this be an error or should we just fix it in the incoming jwt? @@ -73,7 +75,7 @@ public abstract class AbstractJwtSigner implements JwtSigner { * @see org.mitre.jwt.JwtSigner#verify(java.lang.String) */ @Override - public boolean verify(String jwtString) { + public boolean verify(String jwtString) throws NoSuchAlgorithmException { // split on the dots List parts = Lists.newArrayList(Splitter.on(".").split(jwtString)); @@ -92,5 +94,5 @@ public abstract class AbstractJwtSigner implements JwtSigner { } - protected abstract String generateSignature(String signatureBase); + protected abstract String generateSignature(String signatureBase) throws NoSuchAlgorithmException; } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/JwtSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/JwtSigner.java index a43314659..e2ab061b3 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/JwtSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/JwtSigner.java @@ -15,12 +15,14 @@ ******************************************************************************/ package org.mitre.jwt.signer; +import java.security.NoSuchAlgorithmException; + import org.mitre.jwt.model.Jwt; public interface JwtSigner { - public Jwt sign(Jwt jwt); + public Jwt sign(Jwt jwt) throws NoSuchAlgorithmException; - public boolean verify(String jwtString); + public boolean verify(String jwtString) throws NoSuchAlgorithmException; } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java index 974ed43f1..5f93ff13a 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java @@ -134,23 +134,24 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { * ) */ @Override - public String generateSignature(String signatureBase) { + public String generateSignature(String signatureBase) throws NoSuchAlgorithmException { + Mac _mac = getMac(); if (passphrase == null) { throw new IllegalArgumentException("Passphrase cannot be null"); } try { - mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac + _mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac .getAlgorithm())); - mac.update(signatureBase.getBytes("UTF-8")); + _mac.update(signatureBase.getBytes("UTF-8")); } catch (GeneralSecurityException e) { logger.error(e); } catch (UnsupportedEncodingException e) { logger.error(e); } - byte[] sigBytes = mac.doFinal(); + byte[] sigBytes = _mac.doFinal(); String sig = new String(Base64.encodeBase64URLSafe(sigBytes)); @@ -171,6 +172,14 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { public void setPassphrase(String passphrase) { this.passphrase = passphrase; } + + private Mac getMac() throws NoSuchAlgorithmException { + if(mac == null){ + mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()) + .getStandardName()); + } + return mac; + } /* * (non-Javadoc) diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java index d12869259..4b261a15e 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java @@ -18,6 +18,7 @@ package org.mitre.jwt.signer.impl; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; @@ -173,15 +174,16 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { * ) */ @Override - public String generateSignature(String signatureBase) { + public String generateSignature(String signatureBase) throws NoSuchAlgorithmException { String sig = null; + Signature _signer = getSigner(); try { - signer.initSign(privateKey); - signer.update(signatureBase.getBytes("UTF-8")); + _signer.initSign(privateKey); + _signer.update(signatureBase.getBytes("UTF-8")); - byte[] sigBytes = signer.sign(); + byte[] sigBytes = _signer.sign(); sig = (new String(Base64.encodeBase64URLSafe(sigBytes))).replace("=", ""); } catch (GeneralSecurityException e) { @@ -228,6 +230,13 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public void setPrivateKey(RSAPrivateKey privateKey) { this.privateKey = privateKey; } + + private Signature getSigner() throws NoSuchAlgorithmException{ + if(signer == null){ + signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); + } + return signer; + } /* * (non-Javadoc) diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java index 44c956302..4f5ffbde7 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java @@ -15,6 +15,7 @@ ******************************************************************************/ package org.mitre.jwt.signer.service; +import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.util.List; import java.util.Map; @@ -59,8 +60,9 @@ public interface JwtSigningAndValidationService { * @param jwtString * the string representation of the JWT as sent on the wire * @return true if the signature is valid, false if not + * @throws NoSuchAlgorithmException */ - public boolean validateSignature(String jwtString); + public boolean validateSignature(String jwtString) throws NoSuchAlgorithmException; /** * Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm. @@ -68,8 +70,9 @@ public interface JwtSigningAndValidationService { * * @param jwt the jwt to sign * @return the signed jwt + * @throws NoSuchAlgorithmException */ - public void signJwt(Jwt jwt); + public void signJwt(Jwt jwt) throws NoSuchAlgorithmException; /** * Sign a jwt using the selected algorithm. The algorithm is selected using the String parameter values specified diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java new file mode 100644 index 000000000..ed4d99216 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java @@ -0,0 +1,54 @@ +package org.mitre.jwt.signer.service.impl; + +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.Map; + +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.signer.JwtSigner; +import org.mitre.jwt.signer.service.JwtSigningAndValidationService; + +public abstract class AbstractJwtSigningAndValidationService implements JwtSigningAndValidationService{ + + /** + * Return the JwtSigners associated with this service + * + * @return + */ + public abstract Map getSigners(); + + @Override + public boolean isJwtExpired(Jwt jwt) { + + Date expiration = jwt.getClaims().getExpiration(); + + if (expiration != null) + return new Date().after(expiration); + else + return false; + + } + + @Override + public boolean validateIssuedJwt(Jwt jwt, String expectedIssuer) { + + String iss = jwt.getClaims().getIssuer(); + + if (iss.equals(expectedIssuer)) + return true; + + return false; + } + + @Override + public boolean validateSignature(String jwtString) throws NoSuchAlgorithmException { + + for (JwtSigner signer : getSigners().values()) { + if (signer.verify(jwtString)) + return true; + } + + return false; + } + +} \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java new file mode 100644 index 000000000..efcd571ac --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java @@ -0,0 +1,146 @@ +package org.mitre.jwt.signer.service.impl; + +import java.io.File; +import java.net.URL; +import java.security.Key; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.HashMap; +import java.util.Map; + +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtHeader; +import org.mitre.jwt.signer.JwtSigner; +import org.mitre.jwt.signer.impl.HmacSigner; +import org.mitre.jwt.signer.impl.PlaintextSigner; +import org.mitre.jwt.signer.impl.RsaSigner; +import org.mitre.util.Utility; + + +public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAndValidationService{ + + private String x509SigningUrl; + + private String jwkSigningUrl; + + private String clientSecret; + + private Key signingKey; + + private Map map; + + private PublicKey publicKey; + + private Map signers; + + private String signingAlgorithm; + + + public DynamicJwtSigningAndValidationService(String x509SigningUrl, String jwkSigningUrl, String clientSecret) throws Exception { + setX509SigningUrl(x509SigningUrl); + setJwkSigningUrl(jwkSigningUrl); + setClientSecret(clientSecret); + } + + public Key getSigningKey() throws Exception { + if(signingKey == null){ + if(x509SigningUrl != null){ + File file = new File(x509SigningUrl); + URL url = file.toURI().toURL(); + signingKey = Utility.retrieveX509Key(url); + } + else if (jwkSigningUrl != null){ + File file = new File(jwkSigningUrl); + URL url = file.toURI().toURL(); + signingKey = Utility.retrieveJwkKey(url); + } + } + return signingKey; + } + + public String getSigningX509Url() { + return x509SigningUrl; + } + + public void setX509SigningUrl(String x509SigningUrl) { + this.x509SigningUrl = x509SigningUrl; + } + + public String getSigningJwkUrl() { + return jwkSigningUrl; + } + + public void setJwkSigningUrl(String jwkSigningUrl) { + this.jwkSigningUrl = jwkSigningUrl; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + @Override + public Map getAllPublicKeys() { + if(publicKey != null){ + //check to make sure key isn't null, return map + map.put(((RSAPublicKey) publicKey).getModulus() + .toString(16).toUpperCase() + + ((RSAPublicKey) publicKey).getPublicExponent() + .toString(16).toUpperCase(), publicKey); + } + return map; + } + + @Override + public void signJwt(Jwt jwt) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException(); + } + + @Override + public Map getSigners() { + // TODO Auto-generated method stub + signers = new HashMap(); + return signers; + } + + @Override + public boolean validateSignature(String jwtString) { + + try { + JwtSigner signer = getSigner(jwtString); + return signer.verify(jwtString); + } + catch(Exception e) { + return false; + } + + } + + public JwtSigner getSigner(String str) throws Exception { + JwtHeader header = Jwt.parse(str).getHeader(); + String alg = header.getAlgorithm(); + JwtSigner signer = null; + + if(alg.equals("HS256") || alg.equals("HS384") || alg.equals("HS512")){ + signer = new HmacSigner(alg, clientSecret); + } + + else if (alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")){ + signer = new RsaSigner(alg, (PublicKey) getSigningKey(), null); + } + + else if (alg.equals("none")){ + signer = new PlaintextSigner(); + } + + else{ + throw new IllegalArgumentException("Not an existing algorithm type"); + } + + return signer; + } +} diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java index 2237e19ac..595b46347 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java @@ -15,9 +15,9 @@ ******************************************************************************/ package org.mitre.jwt.signer.service.impl; +import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.interfaces.RSAPublicKey; -import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -31,14 +31,13 @@ import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -public class JwtSigningAndValidationServiceDefault implements +public class JwtSigningAndValidationServiceDefault extends AbstractJwtSigningAndValidationService implements JwtSigningAndValidationService, InitializingBean { - @Autowired - private ConfigurationPropertiesBean configBean; + @Autowired ConfigurationPropertiesBean configBean; // map of identifier to signer - private Map signers = new HashMap(); + Map signers = new HashMap(); private static Log logger = LogFactory .getLog(JwtSigningAndValidationServiceDefault.class); @@ -111,34 +110,6 @@ public class JwtSigningAndValidationServiceDefault implements return map; } - /** - * Return the JwtSigners associated with this service - * - * @return - */ - public Map getSigners() { - return signers; - } - - /* - * (non-Javadoc) - * - * @see - * org.mitre.jwt.signer.service.JwtSigningAndValidationService#isJwtExpired - * (org.mitre.jwt.model.Jwt) - */ - @Override - public boolean isJwtExpired(Jwt jwt) { - - Date expiration = jwt.getClaims().getExpiration(); - - if (expiration != null) - return new Date().after(expiration); - else - return false; - - } - /** * Set the JwtSigners associated with this service * @@ -158,55 +129,6 @@ public class JwtSigningAndValidationServiceDefault implements + "]"; } - /* - * (non-Javadoc) - * - * @see - * org.mitre.jwt.signer.service.JwtSigningAndValidationService#validateIssuedJwt - * (org.mitre.jwt.model.Jwt) - */ - @Override - public boolean validateIssuedJwt(Jwt jwt, String expectedIssuer) { - - String iss = jwt.getClaims().getIssuer(); - - if (iss.equals(expectedIssuer)) - 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.values()) { - if (signer.verify(jwtString)) - return true; - } - - return false; - } - - /** - * Sign a jwt in place using the configured default signer. - */ - @Override - public void signJwt(Jwt jwt) { - String signerId = configBean.getDefaultJwtSigner(); - - JwtSigner signer = signers.get(signerId); - - signer.sign(jwt); - - } - /** * @return the configBean */ @@ -220,4 +142,27 @@ public class JwtSigningAndValidationServiceDefault implements public void setConfigBean(ConfigurationPropertiesBean configBean) { this.configBean = configBean; } + + /** + * Sign a jwt in place using the configured default signer. + * @throws NoSuchAlgorithmException + */ + @Override + public void signJwt(Jwt jwt) throws NoSuchAlgorithmException { + String signerId = configBean.getDefaultJwtSigner(); + + JwtSigner signer = getSigners().get(signerId); + + signer.sign(jwt); + + } + + /** + * Return the JwtSigners associated with this service + * + * @return + */ + public Map getSigners() { + return signers; + } } diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java new file mode 100644 index 000000000..ddac6e860 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java @@ -0,0 +1,73 @@ +package org.mitre.jwt.signer.impl; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; + +import junit.framework.TestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class HmacSignerTest extends TestCase { + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL hs256Url = this.getClass().getResource("/jwt/hs256"); + URL hs384Url = this.getClass().getResource("/jwt/hs384"); + URL hs512Url = this.getClass().getResource("/jwt/hs512"); + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp(URL url) throws Exception { + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + @Test + public void testHmacSigner256() throws Exception { + setUp(hs256Url); + HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); + jwt = hmac.sign(jwt); + assertEquals(hmac.verify(jwt.toString()), true); + } + + @Test + public void testHmacSigner384() throws Exception { + setUp(hs384Url); + HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); + jwt = hmac.sign(jwt); + assertEquals(hmac.verify(jwt.toString()), true); + } + + @Test + public void testHmacSigner512() throws Exception { + setUp(hs512Url); + HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); + jwt = hmac.sign(jwt); + assertEquals(hmac.verify(jwt.toString()), true); + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java new file mode 100644 index 000000000..446212872 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java @@ -0,0 +1,55 @@ +package org.mitre.jwt.signer.impl; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import junit.framework.TestCase; + +public class PlaintextSignerTest extends TestCase { + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL plaintextUrl = this.getClass().getResource("/jwt/plaintext"); + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp(URL url) throws Exception { + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + @Test + public void testPlaintextSigner() throws Exception { + setUp(plaintextUrl); + PlaintextSigner plaintext = new PlaintextSigner(); + jwt = plaintext.sign(jwt); + assertEquals(plaintext.verify(jwt.toString()), true); + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java new file mode 100644 index 000000000..cd74c577a --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java @@ -0,0 +1,99 @@ +package org.mitre.jwt.signer.impl; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; + +import junit.framework.TestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; +import org.mitre.jwt.signer.JwsAlgorithm; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class RsaSignerTest extends TestCase { + + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL rs256Url = this.getClass().getResource("/jwt/rs256"); + URL rs384Url = this.getClass().getResource("/jwt/rs384"); + URL rs512Url = this.getClass().getResource("/jwt/rs512"); + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + KeyPairGenerator keyGen; + KeyPair keyPair; + PublicKey publicKey; + PrivateKey privateKey; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp(URL url) throws Exception { + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + @Test + public void testRsaSigner256() throws Exception { + setUp(rs256Url); + keyGen = KeyPairGenerator.getInstance("RSA"); + keyPair = keyGen.generateKeyPair(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS256.toString(), publicKey, privateKey); + jwt = rsa.sign(jwt); + assertEquals(rsa.verify(jwt.toString()), true); + + } + + @Test + public void testRsaSigner384() throws Exception{ + setUp(rs384Url); + keyGen = KeyPairGenerator.getInstance("RSA"); + keyPair = keyGen.generateKeyPair(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS384.toString(), publicKey, privateKey); + jwt = rsa.sign(jwt); + assertEquals(rsa.verify(jwt.toString()), true); + + } + + @Test + public void testRsaSigner512() throws Exception{ + setUp(rs512Url); + keyGen = KeyPairGenerator.getInstance("RSA"); + keyPair = keyGen.generateKeyPair(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS512.toString(), publicKey, privateKey); + jwt = rsa.sign(jwt); + assertEquals(rsa.verify(jwt.toString()), true); + + } + + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java new file mode 100644 index 000000000..95391cea0 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java @@ -0,0 +1,64 @@ +package org.mitre.jwt.signer.service.impl; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.Key; + +import junit.framework.TestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mitre.jwt.signer.JwtSigner; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class DynamicJwtSigningAndValidationServiceTest extends TestCase { + + URL x509Url = this.getClass().getResource("/x509/x509Cert"); + URL jwkUrl = this.getClass().getResource("/jwk/rsaOnly"); + Key jwkKey = null; + Key x509Key = null; + + DynamicJwtSigningAndValidationService jsvs; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + super.setUp(); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + /** + * Test method for {@link org.mitre.util.Utility#retrieveJwk(java.lang.String)}. + * @throws Exception + */ + @Test + public void testGetSigner() throws Exception { + //create key, sign it, for both x509 and jwk. + /* jsvs.setX509SigningUrl(x509Url.getPath()); + x509Key = jsvs.getSigningKey(); + jsvs.setJwkSigningUrl(jwkUrl.getPath()); + jwkKey = jsvs.getSigningKey(); + + JsonParser parser = new JsonParser(); + + String rsaStr = parser.parse(new BufferedReader(new InputStreamReader(jwkUrl.openStream()))).getAsString(); + JwtSigner rsaSigner = jsvs.getSigner(rsaStr); + + String x509Str = parser.parse(new BufferedReader(new InputStreamReader(x509Url.openStream()))).getAsString(); + JwtSigner x509Signer = jsvs.getSigner(x509Str);*/ + assertEquals("yo", "yo"); + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java b/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java index 6404eda77..674e2306a 100644 --- a/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java +++ b/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java @@ -45,7 +45,7 @@ import org.bouncycastle.jce.provider.JCEECPublicKey; public class UtilityTest extends TestCase{ URL url = this.getClass().getResource("/jwk/jwkSuccess"); - URL certUrl = this.getClass().getResource("/x509/certTest"); + URL certUrl = this.getClass().getResource("/x509/x509Cert"); URL rsaUrl = this.getClass().getResource("/jwk/rsaOnly"); /** diff --git a/openid-connect-common/src/test/resources/jwk/rsaOnly b/openid-connect-common/src/test/resources/jwk/rsaOnly new file mode 100644 index 000000000..a5f42177d --- /dev/null +++ b/openid-connect-common/src/test/resources/jwk/rsaOnly @@ -0,0 +1,8 @@ + {"jwk": + [ + {"alg":"RSA", + "mod": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "exp":"AQAB", + "kid":"2011-04-29"} + ] + } \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwt/claims b/openid-connect-common/src/test/resources/jwt/claims new file mode 100644 index 000000000..11f69c7e2 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/claims @@ -0,0 +1,6 @@ +{"iss":"joe", + "user_id":34252452623, + "aud":"yolo", + "exp":35324583457247, + "iat":43215325235, + "nonce":"howdy"} \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwt/hs256 b/openid-connect-common/src/test/resources/jwt/hs256 new file mode 100644 index 000000000..a4cdd0b17 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/hs256 @@ -0,0 +1,2 @@ +{"typ":"JWT", + "alg":"HS256"} diff --git a/openid-connect-common/src/test/resources/jwt/hs384 b/openid-connect-common/src/test/resources/jwt/hs384 new file mode 100644 index 000000000..68f175c1a --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/hs384 @@ -0,0 +1,2 @@ +{"typ":"JWT", + "alg":"HS384"} diff --git a/openid-connect-common/src/test/resources/jwt/hs512 b/openid-connect-common/src/test/resources/jwt/hs512 new file mode 100644 index 000000000..42c727e09 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/hs512 @@ -0,0 +1,2 @@ +{"typ":"JWT", + "alg":"HS512"} diff --git a/openid-connect-common/src/test/resources/jwt/plaintext b/openid-connect-common/src/test/resources/jwt/plaintext new file mode 100644 index 000000000..e16befde3 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/plaintext @@ -0,0 +1,2 @@ +{"typ":"JWT", + "alg":"none"} \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwt/rs256 b/openid-connect-common/src/test/resources/jwt/rs256 new file mode 100644 index 000000000..1d069af3f --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/rs256 @@ -0,0 +1,2 @@ +{"typ":"JWT", + "alg":"RS256"} \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/jwt/rs384 b/openid-connect-common/src/test/resources/jwt/rs384 new file mode 100644 index 000000000..21ceb32e6 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/rs384 @@ -0,0 +1,2 @@ +{"typ":"JWT", + "alg":"RS384"} diff --git a/openid-connect-common/src/test/resources/jwt/rs512 b/openid-connect-common/src/test/resources/jwt/rs512 new file mode 100644 index 000000000..37d614532 --- /dev/null +++ b/openid-connect-common/src/test/resources/jwt/rs512 @@ -0,0 +1,2 @@ +{"typ":"JWT", + "alg":"RS512"} diff --git a/openid-connect-common/src/test/resources/x509/HmacJwt b/openid-connect-common/src/test/resources/x509/HmacJwt new file mode 100644 index 000000000..f076c9dab --- /dev/null +++ b/openid-connect-common/src/test/resources/x509/HmacJwt @@ -0,0 +1,6 @@ +eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9 +. +eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt +cGxlLmNvbS9pc19yb290Ijp0cnVlfQ +. +dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk \ No newline at end of file diff --git a/openid-connect-common/src/test/resources/x509/x509Cert b/openid-connect-common/src/test/resources/x509/x509Cert new file mode 100644 index 000000000..2d60d2c3e --- /dev/null +++ b/openid-connect-common/src/test/resources/x509/x509Cert @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICxDCCAi0CBECcV/wwDQYJKoZIhvcNAQEEBQAwgagxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVU +ZXhhczEPMA0GA1UEBxMGQXVzdGluMSowKAYDVQQKEyFUaGUgVW5pdmVyc2l0eSBvZiBUZXhhcyBh +dCBBdXN0aW4xKDAmBgNVBAsTH0luZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMxIjAgBgNV +BAMTGXhtbGdhdGV3YXkuaXRzLnV0ZXhhcy5lZHUwHhcNMDQwNTA4MDM0NjA0WhcNMDQwODA2MDM0 +NjA0WjCBqDELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRleGFzMQ8wDQYDVQQHEwZBdXN0aW4xKjAo +BgNVBAoTIVRoZSBVbml2ZXJzaXR5IG9mIFRleGFzIGF0IEF1c3RpbjEoMCYGA1UECxMfSW5mb3Jt +YXRpb24gVGVjaG5vbG9neSBTZXJ2aWNlczEiMCAGA1UEAxMZeG1sZ2F0ZXdheS5pdHMudXRleGFz +LmVkdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsmc+6+NjLmanvh+FvBziYdBwTiz+d/DZ +Uy2jyvij6f8Xly6zkhHLSsuBzw08wPzr2K+F359bf9T3uiZMuao//FBGtDrTYpvQwkn4PFZwSeY2 +Ynw4edxp1JEWT2zfOY+QJDfNgpsYQ9hrHDwqnpbMVVqjdBq5RgTKGhFBj9kxEq0CAwEAATANBgkq +hkiG9w0BAQQFAAOBgQCPYGXF6oRbnjti3CPtjfwORoO7ab1QzNS9Z2rLMuPnt6POlm1A3UPEwCS8 +6flTlAqg19Sh47H7+Iq/LuzotKvUE5ugK52QRNMa4c0OSaO5UEM5EfVox1pT9tZV1Z3whYYMhThg +oC4y/On0NUVMN5xfF/GpSACga/bVjoNvd8HWEg== +-----END CERTIFICATE----- \ No newline at end of file From 65dc3daaf8b3b9efcd384182ccfa82983e34c7a2 Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Tue, 12 Jun 2012 16:09:01 -0400 Subject: [PATCH 3/6] smart client --- openid-connect-client/.classpath | 4 +- .../org.eclipse.wst.common.component | 4 +- openid-connect-client/.springBeans | 14 ++ .../AbstractOIDCAuthenticationFilter.java | 159 +++++++----------- .../client/OIDCAuthenticationFilter.java | 11 +- .../OIDCAuthenticationUsingChooserFilter.java | 13 +- .../client/OIDCServerConfiguration.java | 27 ++- .../connect/client/OIDCUserDetailService.java | 39 +++++ .../client/OIDCServerConfigurationTest.java | 10 ++ .../src/test/resources/jwk/jwk | 8 + .../src/test/resources/jwk/jwkEncrypted | 8 + .../src/test/resources/x509/x509 | 15 ++ .../src/test/resources/x509/x509Encrypted | 15 ++ openid-connect-common/.classpath | 5 +- .../org.eclipse.wst.common.component | 1 - .../java/org/mitre/jwt/model/JwtClaims.java | 5 - .../JwtSigningAndValidationService.java | 34 +++- ...bstractJwtSigningAndValidationService.java | 31 ++++ ...DynamicJwtSigningAndValidationService.java | 37 +++- ...JwtSigningAndValidationServiceDefault.java | 33 +++- .../token/ConnectAuthCodeTokenGranter.java | 7 +- .../openid/connect/web/CheckIDEndpoint.java | 4 +- .../src/test/java/org/mitre/jwt/JwtTest.java | 3 +- 23 files changed, 359 insertions(+), 128 deletions(-) create mode 100644 openid-connect-client/.springBeans create mode 100644 openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java create mode 100644 openid-connect-client/src/test/resources/jwk/jwk create mode 100644 openid-connect-client/src/test/resources/jwk/jwkEncrypted create mode 100644 openid-connect-client/src/test/resources/x509/x509 create mode 100644 openid-connect-client/src/test/resources/x509/x509Encrypted diff --git a/openid-connect-client/.classpath b/openid-connect-client/.classpath index 40f68d2dc..57073c1a5 100644 --- a/openid-connect-client/.classpath +++ b/openid-connect-client/.classpath @@ -1,8 +1,8 @@ - - + + diff --git a/openid-connect-client/.settings/org.eclipse.wst.common.component b/openid-connect-client/.settings/org.eclipse.wst.common.component index e70fe2d47..6227d3014 100755 --- a/openid-connect-client/.settings/org.eclipse.wst.common.component +++ b/openid-connect-client/.settings/org.eclipse.wst.common.component @@ -1,8 +1,8 @@ - - + + diff --git a/openid-connect-client/.springBeans b/openid-connect-client/.springBeans new file mode 100644 index 000000000..707e4bb7c --- /dev/null +++ b/openid-connect-client/.springBeans @@ -0,0 +1,14 @@ + + + 1 + + + + + + + spring-servlet.xml + + + + diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java index 49c775859..dca5b1724 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java @@ -28,6 +28,7 @@ import java.security.SecureRandom; import java.security.Signature; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -42,9 +43,16 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.mitre.openid.connect.model.IdToken; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtHeader; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.signer.AbstractJwtSigner; +import org.mitre.jwt.signer.impl.HmacSigner; +import org.mitre.jwt.signer.service.impl.DynamicJwtSigningAndValidationService; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; @@ -60,6 +68,7 @@ import org.springframework.web.util.WebUtils; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.JsonParser; /** @@ -376,11 +385,12 @@ public class AbstractOIDCAuthenticationFilter extends * authentication * @return The authenticated user token, or null if authentication is * incomplete. + * @throws Exception * @throws UnsupportedEncodingException */ protected Authentication handleAuthorizationGrantResponse( String authorizationGrant, HttpServletRequest request, - OIDCServerConfiguration serverConfig) { + OIDCServerConfiguration serverConfig) throws Exception { final boolean debug = logger.isDebugEnabled(); @@ -457,42 +467,45 @@ public class AbstractOIDCAuthenticationFilter extends // Extract the id_token to insert into the // OpenIdConnectAuthenticationToken - + + Cookie nonceSignatureCookie = WebUtils.getCookie(request, + NONCE_SIGNATURE_COOKIE_NAME); + IdToken idToken = null; - + DynamicJwtSigningAndValidationService dynamic = new DynamicJwtSigningAndValidationService(null, null, null); + OIDCServerConfiguration oidc = new OIDCServerConfiguration(); + if (jsonRoot.getAsJsonObject().get("id_token") != null) { - try { - idToken = IdToken.parse(jsonRoot.getAsJsonObject() - .get("id_token").getAsString()); + if(dynamic.validateSignature(jsonRoot.getAsJsonObject().get("id_token").getAsString()) + && + dynamic.validateIssuedJwt(idToken, oidc.getIssuer()) + && + dynamic.validateAudience(idToken, oidc.getClientId()) + && + dynamic.isJwtExpired(idToken) + && + dynamic.validateIssuedAt(idToken) + && + dynamic.validateNonce(idToken, nonceSignatureCookie.getValue())){ + + try { + idToken = IdToken.parse(jsonRoot.getAsJsonObject().get("id_token").getAsString()); + + } catch (Exception e) { - List parts = Lists.newArrayList(Splitter.on(".") - .split(jsonRoot.getAsJsonObject().get("id_token") - .getAsString())); + // I suspect this could happen - if (parts.size() != 3) { - throw new IllegalArgumentException( - "Invalid JWT format."); + logger.error("Problem parsing id_token: " + e); + // e.printStackTrace(); + + throw new AuthenticationServiceException( + "Problem parsing id_token return from Token endpoint: " + + e); } - - String h64 = parts.get(0); - String c64 = parts.get(1); - String s64 = parts.get(2); - - logger.debug("h64 = " + h64); - logger.debug("c64 = " + c64); - logger.debug("s64 = " + s64); - - } catch (Exception e) { - - // I suspect this could happen - - logger.error("Problem parsing id_token: " + e); - // e.printStackTrace(); - - throw new AuthenticationServiceException( - "Problem parsing id_token return from Token endpoint: " - + e); + } + else{ + throw new AuthenticationServiceException("Problem verifying id_token"); } } else { @@ -505,100 +518,58 @@ public class AbstractOIDCAuthenticationFilter extends "Token Endpoint did not return a token_id"); } - // Handle Check ID Endpoint interaction + - httpClient = new DefaultHttpClient(); - httpClient.getParams().setParameter("http.socket.timeout", - new Integer(httpSocketTimeout)); - - factory = new HttpComponentsClientHttpRequestFactory(httpClient); - restTemplate = new RestTemplate(factory); - - form = new LinkedMultiValueMap(); - - form.add("access_token", jsonRoot.getAsJsonObject().get("id_token") - .getAsString()); - - jsonString = null; - - try { - jsonString = restTemplate.postForObject( - serverConfig.getCheckIDEndpointURI(), form, - String.class); - } catch (HttpClientErrorException httpClientErrorException) { - - // Handle error - - logger.error("Check ID Endpoint error response: " - + httpClientErrorException.getStatusText() + " : " - + httpClientErrorException.getMessage()); - - throw new AuthenticationServiceException("Unable check token."); - } - - jsonRoot = new JsonParser().parse(jsonString); // String iss = jsonRoot.getAsJsonObject().get("iss") // .getAsString(); - String userId = jsonRoot.getAsJsonObject().get("user_id") - .getAsString(); + //String userId = jsonRoot.getAsJsonObject().get("user_id") + // .getAsString(); // String aud = jsonRoot.getAsJsonObject().get("aud") // .getAsString(); - String nonce = jsonRoot.getAsJsonObject().get("nonce") - .getAsString(); + //String nonce = jsonRoot.getAsJsonObject().get("nonce") + // .getAsString(); // String exp = jsonRoot.getAsJsonObject().get("exp") // .getAsString(); // Compare returned ID Token to signed session cookie // to detect ID Token replay by third parties. - Cookie nonceSignatureCookie = WebUtils.getCookie(request, - NONCE_SIGNATURE_COOKIE_NAME); - if (nonceSignatureCookie != null) { - String sigText = nonceSignatureCookie.getValue(); + String sigText = nonceSignatureCookie.getValue(); - if (sigText != null && !sigText.isEmpty()) { + if (sigText != null && !sigText.isEmpty()) { - if (!verify(signer, publicKey, nonce, sigText)) { - logger.error("Possible replay attack detected! " - + "The comparison of the nonce in the returned " - + "ID Token to the signed session " - + NONCE_SIGNATURE_COOKIE_NAME + " failed."); - - throw new AuthenticationServiceException( - "Possible replay attack detected! " - + "The comparison of the nonce in the returned " - + "ID Token to the signed session " - + NONCE_SIGNATURE_COOKIE_NAME - + " failed."); - } - - } else { - logger.error(NONCE_SIGNATURE_COOKIE_NAME - + " was found, but was null or empty."); + if (!verify(signer, publicKey, idToken.getClaims().getNonce(), sigText)) { + logger.error("Possible replay attack detected! " + + "The comparison of the nonce in the returned " + + "ID Token to the signed session " + + NONCE_SIGNATURE_COOKIE_NAME + " failed."); throw new AuthenticationServiceException( - NONCE_SIGNATURE_COOKIE_NAME - + " was found, but was null or empty."); + "Possible replay attack detected! " + + "The comparison of the nonce in the returned " + + "ID Token to the signed session " + + NONCE_SIGNATURE_COOKIE_NAME + + " failed."); } } else { - logger.error(NONCE_SIGNATURE_COOKIE_NAME - + " cookie was not found."); + + " was found, but was null or empty."); throw new AuthenticationServiceException( - NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found."); + NONCE_SIGNATURE_COOKIE_NAME + + " was found, but was null or empty."); } // Create an Authentication object for the token, and // return. OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken( - userId, idToken); + idToken.getTokenClaims().getUserId(), idToken); Authentication authentication = this.getAuthenticationManager() .authenticate(token); diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java index 4ec398cbd..2797c7ff1 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java @@ -97,9 +97,14 @@ public class OIDCAuthenticationFilter extends AbstractOIDCAuthenticationFilter { } else if (StringUtils.isNotBlank(request.getParameter("code"))) { - return handleAuthorizationGrantResponse( - request.getParameter("code"), new SanatizedRequest(request, - new String[] { "code" }), oidcServerConfig); + try { + return handleAuthorizationGrantResponse( + request.getParameter("code"), new SanatizedRequest(request, + new String[] { "code" }), oidcServerConfig); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else { diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationUsingChooserFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationUsingChooserFilter.java index 9a420dc65..ccfc6dd93 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationUsingChooserFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationUsingChooserFilter.java @@ -108,10 +108,15 @@ public class OIDCAuthenticationUsingChooserFilter extends Cookie issuerCookie = WebUtils.getCookie(request, ISSUER_COOKIE_NAME); - return handleAuthorizationGrantResponse( - request.getParameter("code"), new SanatizedRequest(request, - new String[] { "code" }), - oidcServerConfigs.get(issuerCookie.getValue())); + try { + return handleAuthorizationGrantResponse( + request.getParameter("code"), new SanatizedRequest(request, + new String[] { "code" }), + oidcServerConfigs.get(issuerCookie.getValue())); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else { diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java index 2d0d226b2..1aeb6a23c 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java @@ -16,19 +16,19 @@ package org.mitre.openid.connect.client; import java.io.File; -import java.net.MalformedURLException; import java.net.URL; import java.security.Key; +import org.mitre.jwt.signer.service.impl.DynamicJwtSigningAndValidationService; import org.mitre.util.Utility; -import com.google.gson.JsonObject; - /** * @author nemonik * */ public class OIDCServerConfiguration { + + DynamicJwtSigningAndValidationService dynamic; private String authorizationEndpointURI; @@ -40,6 +40,8 @@ public class OIDCServerConfiguration { private String clientId; + private String issuer; + private String x509EncryptUrl; private String x509SigningUrl; @@ -63,6 +65,10 @@ public class OIDCServerConfiguration { public String getClientId() { return clientId; } + + public String getIssuer() { + return issuer; + } public String getClientSecret() { return clientSecret; @@ -84,6 +90,10 @@ public class OIDCServerConfiguration { this.clientId = clientId; } + public void setIssuer(String issuer) { + this.issuer = issuer; + } + public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } @@ -169,11 +179,18 @@ public class OIDCServerConfiguration { + authorizationEndpointURI + ", tokenEndpointURI=" + tokenEndpointURI + ", checkIDEndpointURI=" + checkIDEndpointURI + ", clientSecret=" + clientSecret - + ", clientId=" + clientId + ", x509EncryptedUrl=" + + ", clientId=" + clientId + ", issuer=" + issuer + +", x509EncryptedUrl=" + x509EncryptUrl + ", jwkEncryptedUrl=" + jwkEncryptUrl + ", x509SigningUrl=" + x509SigningUrl + ", jwkSigningUrl=" + jwkSigningUrl + "]"; } + + public DynamicJwtSigningAndValidationService getDynamic() throws Exception{ + dynamic = new DynamicJwtSigningAndValidationService(getX509SigningUrl(), getJwkSigningUrl(), getClientSecret()); + return dynamic; + } -} + +} \ No newline at end of file diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java new file mode 100644 index 000000000..64a0980b1 --- /dev/null +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java @@ -0,0 +1,39 @@ +package org.mitre.openid.connect.client; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +import org.mitre.openid.connect.model.IdToken; +import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +public class OIDCUserDetailService implements UserDetailsService, + AuthenticationUserDetailsService { + + public IdToken retrieveToken(URL url) throws IOException{ + String str = new BufferedReader(new InputStreamReader(url.openStream())).toString(); + IdToken idToken = IdToken.parse(str); + return idToken; + } + + + @Override + public UserDetails loadUserDetails(OpenIdConnectAuthenticationToken token) + throws UsernameNotFoundException { + // TODO Auto-generated method stub + + return null; + } + + @Override + public UserDetails loadUserByUsername(String username) + throws UsernameNotFoundException { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java b/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java index 67456b7a1..e3ce69fbe 100644 --- a/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java +++ b/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java @@ -101,4 +101,14 @@ public class OIDCServerConfigurationTest extends TestCase { Key key3 = oidc.getEncryptionKey(); assertEquals(key3, null); } + + @Test + public void testGetDynamic() throws Exception { + oidc.setX509SigningUrl(x509Url.getPath()); + oidc.setJwkSigningUrl(jwkUrl.getPath()); + oidc.setClientSecret("foo"); + assertEquals(oidc.getDynamic().getSigningX509Url(), x509Url.getPath()); + assertEquals(oidc.getDynamic().getSigningJwkUrl(), jwkUrl.getPath()); + assertEquals(oidc.getDynamic().getClientSecret(), "foo"); + } } diff --git a/openid-connect-client/src/test/resources/jwk/jwk b/openid-connect-client/src/test/resources/jwk/jwk new file mode 100644 index 000000000..a5f42177d --- /dev/null +++ b/openid-connect-client/src/test/resources/jwk/jwk @@ -0,0 +1,8 @@ + {"jwk": + [ + {"alg":"RSA", + "mod": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "exp":"AQAB", + "kid":"2011-04-29"} + ] + } \ No newline at end of file diff --git a/openid-connect-client/src/test/resources/jwk/jwkEncrypted b/openid-connect-client/src/test/resources/jwk/jwkEncrypted new file mode 100644 index 000000000..a5f42177d --- /dev/null +++ b/openid-connect-client/src/test/resources/jwk/jwkEncrypted @@ -0,0 +1,8 @@ + {"jwk": + [ + {"alg":"RSA", + "mod": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "exp":"AQAB", + "kid":"2011-04-29"} + ] + } \ No newline at end of file diff --git a/openid-connect-client/src/test/resources/x509/x509 b/openid-connect-client/src/test/resources/x509/x509 new file mode 100644 index 000000000..2d60d2c3e --- /dev/null +++ b/openid-connect-client/src/test/resources/x509/x509 @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICxDCCAi0CBECcV/wwDQYJKoZIhvcNAQEEBQAwgagxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVU +ZXhhczEPMA0GA1UEBxMGQXVzdGluMSowKAYDVQQKEyFUaGUgVW5pdmVyc2l0eSBvZiBUZXhhcyBh +dCBBdXN0aW4xKDAmBgNVBAsTH0luZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMxIjAgBgNV +BAMTGXhtbGdhdGV3YXkuaXRzLnV0ZXhhcy5lZHUwHhcNMDQwNTA4MDM0NjA0WhcNMDQwODA2MDM0 +NjA0WjCBqDELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRleGFzMQ8wDQYDVQQHEwZBdXN0aW4xKjAo +BgNVBAoTIVRoZSBVbml2ZXJzaXR5IG9mIFRleGFzIGF0IEF1c3RpbjEoMCYGA1UECxMfSW5mb3Jt +YXRpb24gVGVjaG5vbG9neSBTZXJ2aWNlczEiMCAGA1UEAxMZeG1sZ2F0ZXdheS5pdHMudXRleGFz +LmVkdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsmc+6+NjLmanvh+FvBziYdBwTiz+d/DZ +Uy2jyvij6f8Xly6zkhHLSsuBzw08wPzr2K+F359bf9T3uiZMuao//FBGtDrTYpvQwkn4PFZwSeY2 +Ynw4edxp1JEWT2zfOY+QJDfNgpsYQ9hrHDwqnpbMVVqjdBq5RgTKGhFBj9kxEq0CAwEAATANBgkq +hkiG9w0BAQQFAAOBgQCPYGXF6oRbnjti3CPtjfwORoO7ab1QzNS9Z2rLMuPnt6POlm1A3UPEwCS8 +6flTlAqg19Sh47H7+Iq/LuzotKvUE5ugK52QRNMa4c0OSaO5UEM5EfVox1pT9tZV1Z3whYYMhThg +oC4y/On0NUVMN5xfF/GpSACga/bVjoNvd8HWEg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/openid-connect-client/src/test/resources/x509/x509Encrypted b/openid-connect-client/src/test/resources/x509/x509Encrypted new file mode 100644 index 000000000..2d60d2c3e --- /dev/null +++ b/openid-connect-client/src/test/resources/x509/x509Encrypted @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICxDCCAi0CBECcV/wwDQYJKoZIhvcNAQEEBQAwgagxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVU +ZXhhczEPMA0GA1UEBxMGQXVzdGluMSowKAYDVQQKEyFUaGUgVW5pdmVyc2l0eSBvZiBUZXhhcyBh +dCBBdXN0aW4xKDAmBgNVBAsTH0luZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMxIjAgBgNV +BAMTGXhtbGdhdGV3YXkuaXRzLnV0ZXhhcy5lZHUwHhcNMDQwNTA4MDM0NjA0WhcNMDQwODA2MDM0 +NjA0WjCBqDELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRleGFzMQ8wDQYDVQQHEwZBdXN0aW4xKjAo +BgNVBAoTIVRoZSBVbml2ZXJzaXR5IG9mIFRleGFzIGF0IEF1c3RpbjEoMCYGA1UECxMfSW5mb3Jt +YXRpb24gVGVjaG5vbG9neSBTZXJ2aWNlczEiMCAGA1UEAxMZeG1sZ2F0ZXdheS5pdHMudXRleGFz +LmVkdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsmc+6+NjLmanvh+FvBziYdBwTiz+d/DZ +Uy2jyvij6f8Xly6zkhHLSsuBzw08wPzr2K+F359bf9T3uiZMuao//FBGtDrTYpvQwkn4PFZwSeY2 +Ynw4edxp1JEWT2zfOY+QJDfNgpsYQ9hrHDwqnpbMVVqjdBq5RgTKGhFBj9kxEq0CAwEAATANBgkq +hkiG9w0BAQQFAAOBgQCPYGXF6oRbnjti3CPtjfwORoO7ab1QzNS9Z2rLMuPnt6POlm1A3UPEwCS8 +6flTlAqg19Sh47H7+Iq/LuzotKvUE5ugK52QRNMa4c0OSaO5UEM5EfVox1pT9tZV1Z3whYYMhThg +oC4y/On0NUVMN5xfF/GpSACga/bVjoNvd8HWEg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/openid-connect-common/.classpath b/openid-connect-common/.classpath index 5d8133f83..191f61b4a 100644 --- a/openid-connect-common/.classpath +++ b/openid-connect-common/.classpath @@ -1,8 +1,8 @@ - - + + @@ -11,4 +11,3 @@ - diff --git a/openid-connect-common/.settings/org.eclipse.wst.common.component b/openid-connect-common/.settings/org.eclipse.wst.common.component index c681a1288..1e24c2b7c 100644 --- a/openid-connect-common/.settings/org.eclipse.wst.common.component +++ b/openid-connect-common/.settings/org.eclipse.wst.common.component @@ -2,6 +2,5 @@ - diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java index 1831edf10..bc6bc9aca 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtClaims.java @@ -15,12 +15,7 @@ ******************************************************************************/ package org.mitre.jwt.model; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Date; -import java.util.HashMap; -import java.util.Map; import java.util.Map.Entry; import com.google.gson.JsonElement; diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java index 4f5ffbde7..0cb60026f 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java @@ -17,7 +17,6 @@ package org.mitre.jwt.signer.service; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; -import java.util.List; import java.util.Map; import org.mitre.jwt.model.Jwt; @@ -72,6 +71,39 @@ public interface JwtSigningAndValidationService { * @return the signed jwt * @throws NoSuchAlgorithmException */ + public boolean validateIssuedAt(Jwt jwt); + + /** + * Checks to see when this JWT was issued + * + * @param jwt + * the JWT to check + * @return true if the issued at is valid, false if not + * @throws NoSuchAlgorithmException + */ + public boolean validateAudience(Jwt jwt, String clientId); + + /** + * Checks the audience that the given JWT against the client_id of the Client + * + * @param jwt + * @param clientId + * the string representation of the client_id + * @return true if the audience matches the clinet_id, false if otherwise + * @throws NoSuchAlgorithmException + */ + public boolean validateNonce(Jwt jwt, String nonce); + + /** + * Checks to see if the nonce parameter sent in the Authorization Request + * is equal to the nonce parameter in the id token + * + * @param jwt + * @param nonce + * the string representation of the Nonce + * @return true if both nonce parameters are equal, false if otherwise + * @throws NoSuchAlgorithmException + */ public void signJwt(Jwt jwt) throws NoSuchAlgorithmException; /** diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java index ed4d99216..8d3a8d437 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java @@ -50,5 +50,36 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni return false; } + + @Override + public boolean validateIssuedAt(Jwt jwt) { + Date issuedAt = jwt.getClaims().getIssuedAt(); + + if (issuedAt != null) + return new Date().before(issuedAt); + else + return false; + } + + @Override + public boolean validateAudience(Jwt jwt, String clientId) { + + if(jwt.getClaims().getAudience().equals(clientId)){ + return true; + } + else{ + return false; + } + } + + @Override + public boolean validateNonce(Jwt jwt, String nonce) { + if(jwt.getClaims().getNonce().equals(nonce)){ + return true; + } + else{ + return false; + } + } } \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java index efcd571ac..cf337051e 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java @@ -5,6 +5,7 @@ import java.net.URL; import java.security.Key; import java.security.PublicKey; import java.security.interfaces.RSAPublicKey; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -33,9 +34,6 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd private Map signers; - private String signingAlgorithm; - - public DynamicJwtSigningAndValidationService(String x509SigningUrl, String jwkSigningUrl, String clientSecret) throws Exception { setX509SigningUrl(x509SigningUrl); setJwkSigningUrl(jwkSigningUrl); @@ -143,4 +141,35 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd return signer; } -} + + @Override + public boolean validateIssuedAt(Jwt jwt) { + Date issuedAt = jwt.getClaims().getIssuedAt(); + + if (issuedAt != null) + return new Date().before(issuedAt); + else + return false; + } + + @Override + public boolean validateAudience(Jwt jwt, String clientId) { + + if(jwt.getClaims().getAudience().equals(clientId)){ + return true; + } + else{ + return false; + } + } + + @Override + public boolean validateNonce(Jwt jwt, String nonce) { + if(jwt.getClaims().getNonce().equals(nonce)){ + return true; + } + else{ + return false; + } + } +} \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java index 8d4ddd162..77eb8cd83 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java @@ -17,7 +17,7 @@ package org.mitre.jwt.signer.service.impl; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; -import java.security.interfaces.RSAPublicKey; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -163,4 +163,35 @@ public class JwtSigningAndValidationServiceDefault extends AbstractJwtSigningAnd public Map getSigners() { return signers; } + + @Override + public boolean validateIssuedAt(Jwt jwt) { + Date issuedAt = jwt.getClaims().getIssuedAt(); + + if (issuedAt != null) + return new Date().before(issuedAt); + else + return false; + } + + @Override + public boolean validateAudience(Jwt jwt, String clientId) { + + if(clientId.equals(jwt.getClaims().getAudience())){ + return true; + } + else{ + return false; + } + } + + @Override + public boolean validateNonce(Jwt jwt, String nonce) { + if(nonce.equals(jwt.getClaims().getNonce())){ + return true; + } + else{ + return false; + } + } } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectAuthCodeTokenGranter.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectAuthCodeTokenGranter.java index f3b56d6bb..3615953ed 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectAuthCodeTokenGranter.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectAuthCodeTokenGranter.java @@ -18,6 +18,7 @@ */ package org.mitre.openid.connect.token; +import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.Map; import java.util.Set; @@ -30,6 +31,7 @@ import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.mitre.openid.connect.model.IdToken; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.exceptions.InvalidClientException; import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; @@ -112,10 +114,13 @@ public class ConnectAuthCodeTokenGranter implements TokenGranter { * @param parameters * @param clientId * @param scope + * @throws NoSuchAlgorithmException + * @throws AuthenticationException + * @throws InvalidGrantException */ @Override public OAuth2AccessToken grant(String grantType, - Map parameters, String clientId, Set scope) { + Map parameters, String clientId, Set scope) throws NoSuchAlgorithmException, InvalidGrantException, AuthenticationException { if (!GRANT_TYPE.equals(grantType)) { return null; diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java index aa859b3cc..a7ef053db 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java @@ -15,6 +15,8 @@ ******************************************************************************/ package org.mitre.openid.connect.web; +import java.security.NoSuchAlgorithmException; + import javax.servlet.http.HttpServletRequest; import org.mitre.jwt.signer.service.JwtSigningAndValidationService; @@ -44,7 +46,7 @@ public class CheckIDEndpoint { @PreAuthorize("hasRole('ROLE_USER')") @RequestMapping("/checkid") - public ModelAndView checkID(@RequestParam("access_token") String tokenString, ModelAndView mav, HttpServletRequest request) { + public ModelAndView checkID(@RequestParam("access_token") String tokenString, ModelAndView mav, HttpServletRequest request) throws NoSuchAlgorithmException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); diff --git a/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java b/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java index f565fbd33..caefa4104 100644 --- a/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java +++ b/openid-connect-server/src/test/java/org/mitre/jwt/JwtTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertThat; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; @@ -198,7 +199,7 @@ public class JwtTest { } @Test - public void testToStringPlaintext() { + public void testToStringPlaintext() throws NoSuchAlgorithmException { Jwt jwt = new Jwt(); jwt.getHeader().setAlgorithm("none"); jwt.getClaims().setExpiration(new Date(1300819380L * 1000L)); From fe3bbfb3d551bebbedda70ef9368a4a678d8174e Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Fri, 15 Jun 2012 17:11:58 -0400 Subject: [PATCH 4/6] Further cleanups. Still missing: - All tests extend TestCase, should use annotations instead - Several elements throw Exception - Key Fetchers should use RESTTemplates and be in a separate utility set --- .../AbstractOIDCAuthenticationFilter.java | 2 +- .../client/OIDCServerConfiguration.java | 6 ++++ .../connect/client/OIDCUserDetailService.java | 4 +++ .../openid/connect/client/UrlValidator.java | 5 ++++ .../org/mitre/jwt/signer/impl/HmacSigner.java | 1 + .../org/mitre/jwt/signer/impl/RsaSigner.java | 5 ++-- .../JwtSigningAndValidationService.java | 10 +++---- ...bstractJwtSigningAndValidationService.java | 28 +++++++++---------- ...DynamicJwtSigningAndValidationService.java | 28 +++++++++++-------- ...JwtSigningAndValidationServiceDefault.java | 5 ++-- .../jwt/signer/service/impl/KeyStore.java | 1 + .../src/main/java/org/mitre/util/Utility.java | 3 ++ .../org/mitre/swd/view/XrdJsonResponse.java | 12 ++++++-- 13 files changed, 72 insertions(+), 38 deletions(-) diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java index cecd8bb9c..2005886ff 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java @@ -388,7 +388,7 @@ public class AbstractOIDCAuthenticationFilter extends */ protected Authentication handleAuthorizationGrantResponse( String authorizationGrant, HttpServletRequest request, - OIDCServerConfiguration serverConfig) throws Exception { + OIDCServerConfiguration serverConfig) { final boolean debug = logger.isDebugEnabled(); diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java index 675f54775..c5f27688f 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java @@ -48,6 +48,8 @@ public class OIDCServerConfiguration { private String jwkSigningUrl; + + // TODO: these keys should be settable through other means beyond discovery private Key encryptKey; private Key signingKey; @@ -124,6 +126,7 @@ public class OIDCServerConfiguration { this.jwkSigningUrl = jwkSigningUrl; } + // FIXME: this should not throw Exception public Key getSigningKey() throws Exception { if(signingKey == null){ if(x509SigningUrl != null){ @@ -140,6 +143,7 @@ public class OIDCServerConfiguration { return signingKey; } + // FIXME: this should not throw Exception public Key getEncryptionKey() throws Exception { if(encryptKey == null){ if(x509EncryptUrl != null){ @@ -156,6 +160,7 @@ public class OIDCServerConfiguration { return encryptKey; } + // FIXME: this should not throw exception public void checkKeys() throws Exception { encryptKey = null; signingKey = null; @@ -176,6 +181,7 @@ public class OIDCServerConfiguration { + jwkSigningUrl + "]"; } + // TODO: what is this function for? nobody uses it, and it seems backwards for construction public DynamicJwtSigningAndValidationService getDynamic() throws Exception{ dynamic = new DynamicJwtSigningAndValidationService(getX509SigningUrl(), getJwkSigningUrl(), getClientSecret()); return dynamic; diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java index 64a0980b1..301c71b4e 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java @@ -11,6 +11,10 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; + +// TODO: what is this class for? + + public class OIDCUserDetailService implements UserDetailsService, AuthenticationUserDetailsService { diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java index 66c723f0a..a89f216e6 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java @@ -4,6 +4,8 @@ import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; +// TODO: is this used anywhere? + public class UrlValidator implements Validator{ @@ -19,14 +21,17 @@ public class UrlValidator implements Validator{ } + // TODO this isn't called anywhere public void validate1(Object obj, Errors e) { ValidationUtils.rejectIfEmpty(e, "x509SigningUrl", "x509SigningUrl.empty"); } + // TODO this isn't called anywhere public void validate2(Object obj, Errors e) { ValidationUtils.rejectIfEmpty(e, "jwkEncryptUrl", "jwkEncryptUrl.empty"); } + // TODO this isn't called anywhere public void validate3(Object obj, Errors e) { ValidationUtils.rejectIfEmpty(e, "jwkSigningUrl", "jwkSigningUrl.empty"); } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java index 5f93ff13a..86a0ce452 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java @@ -173,6 +173,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { this.passphrase = passphrase; } + // TODO: this this indirection to a lazy constructor necessary? private Mac getMac() throws NoSuchAlgorithmException { if(mac == null){ mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()) diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java index 4b261a15e..b394d4153 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java @@ -138,7 +138,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() throws NoSuchAlgorithmException, GeneralSecurityException { // unsupported algorithm will throw a NoSuchAlgorithmException signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); // ,PROVIDER); @@ -230,7 +230,8 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public void setPrivateKey(RSAPrivateKey privateKey) { this.privateKey = privateKey; } - + + // TODO: this this indirection to a lazy constructor really necessary? private Signature getSigner() throws NoSuchAlgorithmException{ if(signer == null){ signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java index 0cb60026f..042d3fc41 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java @@ -71,8 +71,6 @@ public interface JwtSigningAndValidationService { * @return the signed jwt * @throws NoSuchAlgorithmException */ - public boolean validateIssuedAt(Jwt jwt); - /** * Checks to see when this JWT was issued * @@ -81,7 +79,7 @@ public interface JwtSigningAndValidationService { * @return true if the issued at is valid, false if not * @throws NoSuchAlgorithmException */ - public boolean validateAudience(Jwt jwt, String clientId); + public boolean validateIssuedAt(Jwt jwt); /** * Checks the audience that the given JWT against the client_id of the Client @@ -92,7 +90,7 @@ public interface JwtSigningAndValidationService { * @return true if the audience matches the clinet_id, false if otherwise * @throws NoSuchAlgorithmException */ - public boolean validateNonce(Jwt jwt, String nonce); + public boolean validateAudience(Jwt jwt, String clientId); /** * Checks to see if the nonce parameter sent in the Authorization Request @@ -104,7 +102,7 @@ public interface JwtSigningAndValidationService { * @return true if both nonce parameters are equal, false if otherwise * @throws NoSuchAlgorithmException */ - public void signJwt(Jwt jwt) throws NoSuchAlgorithmException; + public boolean validateNonce(Jwt jwt, String nonce); /** * Sign a jwt using the selected algorithm. The algorithm is selected using the String parameter values specified @@ -114,6 +112,8 @@ public interface JwtSigningAndValidationService { * @param alg the name of the algorithm to use, as specified in JWS s.6 * @return the signed jwt */ + public void signJwt(Jwt jwt) throws NoSuchAlgorithmException; + //TODO: implement later; only need signJwt(Jwt jwt) for now //public Jwt signJwt(Jwt jwt, String alg); diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java index 8d3a8d437..e3cc3a833 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java @@ -22,11 +22,11 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni Date expiration = jwt.getClaims().getExpiration(); - if (expiration != null) + if (expiration != null) { return new Date().after(expiration); - else + } else { return false; - + } } @Override @@ -34,8 +34,9 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni String iss = jwt.getClaims().getIssuer(); - if (iss.equals(expectedIssuer)) + if (iss.equals(expectedIssuer)) { return true; + } return false; } @@ -44,10 +45,10 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni public boolean validateSignature(String jwtString) throws NoSuchAlgorithmException { for (JwtSigner signer : getSigners().values()) { - if (signer.verify(jwtString)) + if (signer.verify(jwtString)) { return true; + } } - return false; } @@ -55,19 +56,19 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni public boolean validateIssuedAt(Jwt jwt) { Date issuedAt = jwt.getClaims().getIssuedAt(); - if (issuedAt != null) + if (issuedAt != null) { return new Date().before(issuedAt); - else + } else { return false; + } } @Override - public boolean validateAudience(Jwt jwt, String clientId) { + public boolean validateAudience(Jwt jwt, String expectedAudience) { - if(jwt.getClaims().getAudience().equals(clientId)){ + if(jwt.getClaims().getAudience().equals(expectedAudience)){ return true; - } - else{ + } else { return false; } } @@ -76,8 +77,7 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni public boolean validateNonce(Jwt jwt, String nonce) { if(jwt.getClaims().getNonce().equals(nonce)){ return true; - } - else{ + } else { return false; } } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java index b475bd266..0c327d890 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java @@ -34,12 +34,13 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd private Map signers; - public DynamicJwtSigningAndValidationService(String x509SigningUrl, String jwkSigningUrl, String clientSecret) throws Exception { + public DynamicJwtSigningAndValidationService(String x509SigningUrl, String jwkSigningUrl, String clientSecret) { setX509SigningUrl(x509SigningUrl); setJwkSigningUrl(jwkSigningUrl); setClientSecret(clientSecret); } + // FIXME: this function should not throw Exception public Key getSigningKey() throws Exception { if(signingKey == null){ if(x509SigningUrl != null){ @@ -118,24 +119,27 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd } - public JwtSigner getSigner(String str) throws Exception { + public JwtSigner getSigner(String str) { JwtHeader header = Jwt.parse(str).getHeader(); String alg = header.getAlgorithm(); JwtSigner signer = null; if(alg.equals("HS256") || alg.equals("HS384") || alg.equals("HS512")){ signer = new HmacSigner(alg, clientSecret); // TODO: huh? no, we're not signing with the client secret - } - - else if (alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")){ - signer = new RsaSigner(alg, (PublicKey) getSigningKey(), null); - } - - else if (alg.equals("none")){ + } else if (alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")){ + + PublicKey rsaSigningKey = null; + try { + rsaSigningKey = (PublicKey) getSigningKey(); + } catch (Exception e) { + // FIXME this function call should not throw Exception + e.printStackTrace(); + return null; + } + signer = new RsaSigner(alg, rsaSigningKey, null); + } else if (alg.equals("none")){ signer = new PlaintextSigner(); - } - - else{ + } else { throw new IllegalArgumentException("Not an existing algorithm type"); } diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java index 77eb8cd83..c2a9256e0 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java @@ -34,10 +34,11 @@ import org.springframework.beans.factory.annotation.Autowired; public class JwtSigningAndValidationServiceDefault extends AbstractJwtSigningAndValidationService implements JwtSigningAndValidationService, InitializingBean { - @Autowired ConfigurationPropertiesBean configBean; + @Autowired + private ConfigurationPropertiesBean configBean; // map of identifier to signer - Map signers = new HashMap(); + private Map signers = new HashMap(); private static Log logger = LogFactory .getLog(JwtSigningAndValidationServiceDefault.class); diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java index b3afc9122..2a59fca42 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/KeyStore.java @@ -89,6 +89,7 @@ public class KeyStore implements InitializingBean { } } + // TODO: a more specific exception perhaps? is an empty keystore even an exception? if (keystore.size() == 0) { throw new Exception("Keystore is empty; it has no entries"); } diff --git a/openid-connect-common/src/main/java/org/mitre/util/Utility.java b/openid-connect-common/src/main/java/org/mitre/util/Utility.java index 5bc809bd5..35acac409 100644 --- a/openid-connect-common/src/main/java/org/mitre/util/Utility.java +++ b/openid-connect-common/src/main/java/org/mitre/util/Utility.java @@ -70,6 +70,7 @@ public class Utility { return issuer; } + // FIXME: this should use a rest template and sould not throw Exception public static List retrieveJwk(URL path) throws Exception { List keys = new ArrayList(); @@ -95,6 +96,7 @@ public class Utility { return keys; } + // FIXME: this should use a rest template and sould not throw Exception public static Key retrieveX509Key(URL url) throws Exception { CertificateFactory factory = CertificateFactory.getInstance("X.509"); @@ -104,6 +106,7 @@ public class Utility { return key; } + // FIXME: this should use a rest template and sould not throw Exception public static Key retrieveJwkKey(URL url) throws Exception { JsonParser parser = new JsonParser(); diff --git a/openid-connect-server/src/main/java/org/mitre/swd/view/XrdJsonResponse.java b/openid-connect-server/src/main/java/org/mitre/swd/view/XrdJsonResponse.java index 5f2a69c7b..c77c0a2d9 100644 --- a/openid-connect-server/src/main/java/org/mitre/swd/view/XrdJsonResponse.java +++ b/openid-connect-server/src/main/java/org/mitre/swd/view/XrdJsonResponse.java @@ -18,6 +18,7 @@ */ package org.mitre.swd.view; +import java.io.IOException; import java.io.Writer; import java.util.Map; @@ -44,7 +45,7 @@ public class XrdJsonResponse extends AbstractView { * @see org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel(java.util.Map, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override - protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) { Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() { @Override @@ -67,7 +68,14 @@ public class XrdJsonResponse extends AbstractView { response.setContentType("application/json"); - Writer out = response.getWriter(); + Writer out; + try { + out = response.getWriter(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; // if we can't get the writer, this is pointless + } Map links = (Map) model.get("links"); From b94fbd7439e46aeda768d5397695d79935e87524 Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Wed, 20 Jun 2012 09:36:55 -0400 Subject: [PATCH 5/6] updated -common and -client code by removing throws exception, changing to rest templates, and updating test cases to use annotations --- openid-connect-client/.classpath | 4 + .../.settings/org.eclipse.jdt.core.prefs | 15 ++ .../.settings/org.eclipse.jdt.launching.prefs | 2 + .../AbstractOIDCAuthenticationFilter.java | 32 ++-- .../client/OIDCServerConfiguration.java | 71 +++++---- .../client/OIDCServerConfigurationTest.java | 94 ++++++++---- .../src/test/resources/test-context.xml | 46 ++++++ openid-connect-common/.classpath | 6 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- .../.settings/org.eclipse.jdt.launching.prefs | 2 + .../org/mitre/jwt/signer/impl/HmacSigner.java | 29 ++-- .../org/mitre/jwt/signer/impl/RsaSigner.java | 23 +-- .../JwtSigningAndValidationService.java | 40 ++--- ...bstractJwtSigningAndValidationService.java | 22 --- ...DynamicJwtSigningAndValidationService.java | 48 ++++-- ...JwtSigningAndValidationServiceDefault.java | 13 +- .../java/org/mitre/key/fetch/KeyFetcher.java | 145 ++++++++++++++++++ .../src/main/java/org/mitre/util/Utility.java | 55 ------- .../mitre/jwt/signer/impl/Hmac256Test.java | 68 ++++++++ .../mitre/jwt/signer/impl/Hmac384Test.java | 68 ++++++++ .../mitre/jwt/signer/impl/Hmac512Test.java | 68 ++++++++ .../jwt/signer/impl/PlaintextSignerTest.java | 28 +++- .../org/mitre/jwt/signer/impl/Rsa256Test.java | 82 ++++++++++ .../org/mitre/jwt/signer/impl/Rsa384Test.java | 81 ++++++++++ .../org/mitre/jwt/signer/impl/Rsa512Test.java | 81 ++++++++++ ...micJwtSigningAndValidationServiceTest.java | 10 +- .../org/mitre/key/fetch/KeyFetcherTest.java | 70 +++++++++ .../test/java/org/mitre/util/UtilityTest.java | 19 ++- .../src/test/resources/test-context.xml | 40 +++++ .../.settings/org.eclipse.jdt.core.prefs | 12 +- .../.settings/org.eclipse.jdt.launching.prefs | 2 + .../openid/connect/web/CheckIDEndpoint.java | 6 +- 32 files changed, 1031 insertions(+), 263 deletions(-) create mode 100644 openid-connect-client/.settings/org.eclipse.jdt.launching.prefs create mode 100644 openid-connect-client/src/test/resources/test-context.xml create mode 100644 openid-connect-common/.settings/org.eclipse.jdt.launching.prefs create mode 100644 openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac256Test.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac384Test.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac512Test.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa256Test.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa384Test.java create mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa512Test.java create mode 100644 openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java create mode 100644 openid-connect-common/src/test/resources/test-context.xml create mode 100644 openid-connect-server/.settings/org.eclipse.jdt.launching.prefs diff --git a/openid-connect-client/.classpath b/openid-connect-client/.classpath index bf96ac098..b5b1093d8 100644 --- a/openid-connect-client/.classpath +++ b/openid-connect-client/.classpath @@ -10,5 +10,9 @@ + + + + diff --git a/openid-connect-client/.settings/org.eclipse.jdt.core.prefs b/openid-connect-client/.settings/org.eclipse.jdt.core.prefs index 62a317c86..5738c9c7a 100644 --- a/openid-connect-client/.settings/org.eclipse.jdt.core.prefs +++ b/openid-connect-client/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,23 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=warning +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/openid-connect-client/.settings/org.eclipse.jdt.launching.prefs b/openid-connect-client/.settings/org.eclipse.jdt.launching.prefs new file mode 100644 index 000000000..d211d3263 --- /dev/null +++ b/openid-connect-client/.settings/org.eclipse.jdt.launching.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java index 2005886ff..592a2d041 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java @@ -426,7 +426,7 @@ public class AbstractOIDCAuthenticationFilter extends logger.debug("tokenEndpointURI = " + serverConfig.getTokenEndpointURI()); logger.debug("form = " + form); } - +; String jsonString = null; try { @@ -470,25 +470,27 @@ public class AbstractOIDCAuthenticationFilter extends DynamicJwtSigningAndValidationService jwtValidator = new DynamicJwtSigningAndValidationService(serverConfig.getX509SigningUrl(), serverConfig.getJwkSigningUrl(), serverConfig.getClientSecret()); if (jsonRoot.getAsJsonObject().get("id_token") != null) { + + try { + idToken = IdToken.parse(jsonRoot.getAsJsonObject().get("id_token").getAsString()); + + } catch (AuthenticationServiceException e) { + + // I suspect this could happen + + logger.error("Problem parsing id_token: " + e); + // e.printStackTrace(); + + throw new AuthenticationServiceException("Problem parsing id_token return from Token endpoint: " + e); + } if(jwtValidator.validateSignature(jsonRoot.getAsJsonObject().get("id_token").getAsString()) - && jwtValidator.validateIssuedJwt(idToken, serverConfig.getIssuer()) - && jwtValidator.validateAudience(idToken, serverConfig.getClientId()) + && idToken.getClaims().getIssuer().equals(serverConfig.getIssuer()) + && idToken.getClaims().getIssuer().equals(serverConfig.getClientId()) && jwtValidator.isJwtExpired(idToken) && jwtValidator.validateIssuedAt(idToken)){ - try { - idToken = IdToken.parse(jsonRoot.getAsJsonObject().get("id_token").getAsString()); - - } catch (Exception e) { - - // I suspect this could happen - - logger.error("Problem parsing id_token: " + e); - // e.printStackTrace(); - - throw new AuthenticationServiceException("Problem parsing id_token return from Token endpoint: " + e); - } + } else{ throw new AuthenticationServiceException("Problem verifying id_token"); diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java index c5f27688f..ae4693469 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java @@ -15,20 +15,17 @@ ******************************************************************************/ package org.mitre.openid.connect.client; -import java.io.File; -import java.net.URL; import java.security.Key; - -import org.mitre.jwt.signer.service.impl.DynamicJwtSigningAndValidationService; -import org.mitre.util.Utility; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import org.mitre.key.fetch.KeyFetcher; /** * @author nemonik * */ public class OIDCServerConfiguration { - - private DynamicJwtSigningAndValidationService dynamic; private String authorizationEndpointURI; @@ -126,42 +123,57 @@ public class OIDCServerConfiguration { this.jwkSigningUrl = jwkSigningUrl; } - // FIXME: this should not throw Exception - public Key getSigningKey() throws Exception { + public Key getSigningKey(){ if(signingKey == null){ if(x509SigningUrl != null){ - File file = new File(x509SigningUrl); - URL url = file.toURI().toURL(); - signingKey = Utility.retrieveX509Key(url); + try { + signingKey = KeyFetcher.retrieveX509Key(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else if (jwkSigningUrl != null){ - File file = new File(jwkSigningUrl); - URL url = file.toURI().toURL(); - signingKey = Utility.retrieveJwkKey(url); + try { + signingKey = KeyFetcher.retrieveJwkKey(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } return signingKey; } - // FIXME: this should not throw Exception - public Key getEncryptionKey() throws Exception { + public Key getEncryptionKey(){ if(encryptKey == null){ if(x509EncryptUrl != null){ - File file = new File(x509EncryptUrl); - URL url = file.toURI().toURL(); - encryptKey = Utility.retrieveX509Key(url); + try { + encryptKey = KeyFetcher.retrieveX509Key(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else if (jwkEncryptUrl != null){ - File file = new File(jwkEncryptUrl); - URL url = file.toURI().toURL(); - encryptKey = Utility.retrieveJwkKey(url); + try { + encryptKey = KeyFetcher.retrieveJwkKey(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } return encryptKey; } - - // FIXME: this should not throw exception - public void checkKeys() throws Exception { + + public void checkKeys(){ encryptKey = null; signingKey = null; getEncryptionKey(); @@ -180,12 +192,5 @@ public class OIDCServerConfiguration { + x509SigningUrl + ", jwkSigningUrl=" + jwkSigningUrl + "]"; } - - // TODO: what is this function for? nobody uses it, and it seems backwards for construction - public DynamicJwtSigningAndValidationService getDynamic() throws Exception{ - dynamic = new DynamicJwtSigningAndValidationService(getX509SigningUrl(), getJwkSigningUrl(), getClientSecret()); - return dynamic; - } - } \ No newline at end of file diff --git a/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java b/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java index 48f44358e..ba208afc9 100644 --- a/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java +++ b/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java @@ -1,16 +1,25 @@ package org.mitre.openid.connect.client; +import static org.junit.Assert.assertEquals; + import java.net.URL; import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.key.fetch.KeyFetcher; import org.mitre.util.Utility; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import junit.framework.TestCase; - -public class OIDCServerConfigurationTest extends TestCase { +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class OIDCServerConfigurationTest{ private URL jwkUrl = this.getClass().getResource("/jwk/jwk"); private URL x509Url = this.getClass().getResource("/x509/x509"); @@ -22,16 +31,15 @@ public class OIDCServerConfigurationTest extends TestCase { * @throws java.lang.Exception */ @Before - public void setUp() throws Exception { + public void setUp(){ oidc = new OIDCServerConfiguration(); - super.setUp(); } /** * @throws java.lang.Exception */ @After - public void tearDown() throws Exception { + public void tearDown(){ } /** @@ -39,31 +47,49 @@ public class OIDCServerConfigurationTest extends TestCase { * @throws Exception */ @Test - public void testGetSigningKeyBoth() throws Exception { + public void testGetSigningKeyBoth(){ oidc.setX509SigningUrl(x509Url.getPath()); oidc.setJwkSigningUrl(jwkUrl.getPath()); Key key = oidc.getSigningKey(); - assertEquals(key, Utility.retrieveX509Key(x509Url)); + try { + assertEquals(key, KeyFetcher.retrieveX509Key()); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Test - public void testGetSigningKeyJwk() throws Exception { + public void testGetSigningKeyJwk(){ oidc.setX509SigningUrl(null); oidc.setJwkSigningUrl(jwkUrl.getPath()); Key key1 = oidc.getSigningKey(); - assertEquals(key1, Utility.retrieveJwkKey(jwkUrl)); + try { + assertEquals(key1, KeyFetcher.retrieveJwkKey()); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Test - public void testGetSigningKeyX509() throws Exception { + public void testGetSigningKeyX509(){ oidc.setX509SigningUrl(x509Url.getPath()); oidc.setJwkSigningUrl(null); Key key2 = oidc.getSigningKey(); - assertEquals(key2, Utility.retrieveX509Key(x509Url)); + try { + assertEquals(key2, KeyFetcher.retrieveX509Key()); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Test - public void testGetSigningKeyNone() throws Exception { + public void testGetSigningKeyNone(){ oidc.setX509SigningUrl(null); oidc.setJwkSigningUrl(null); Key key3 = oidc.getSigningKey(); @@ -71,44 +97,52 @@ public class OIDCServerConfigurationTest extends TestCase { } @Test - public void testGetEncryptionKeyBoth() throws Exception { + public void testGetEncryptionKeyBoth(){ oidc.setX509EncryptUrl(x509EncryptedUrl.getPath()); oidc.setJwkEncryptUrl(jwkEncryptedUrl.getPath()); Key key = oidc.getEncryptionKey(); - assertEquals(key, Utility.retrieveX509Key(x509EncryptedUrl)); + try { + assertEquals(key, KeyFetcher.retrieveX509Key()); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Test - public void testGetEncryptionKeyJwk() throws Exception { + public void testGetEncryptionKeyJwk(){ oidc.setX509EncryptUrl(null); oidc.setJwkEncryptUrl(jwkEncryptedUrl.getPath()); Key key1 = oidc.getEncryptionKey(); - assertEquals(key1, Utility.retrieveJwkKey(jwkEncryptedUrl)); + try { + assertEquals(key1, KeyFetcher.retrieveJwkKey()); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Test - public void testGetEncryptionKeyX509() throws Exception { + public void testGetEncryptionKeyX509(){ oidc.setX509EncryptUrl(x509EncryptedUrl.getPath()); oidc.setJwkEncryptUrl(null); Key key2 = oidc.getEncryptionKey(); - assertEquals(key2, Utility.retrieveX509Key(x509EncryptedUrl)); + try { + assertEquals(key2, KeyFetcher.retrieveX509Key()); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } @Test - public void testGetEncryptionKeyNone() throws Exception { + public void testGetEncryptionKeyNone(){ oidc.setX509EncryptUrl(null); oidc.setJwkEncryptUrl(null); Key key3 = oidc.getEncryptionKey(); assertEquals(key3, null); } - - @Test - public void testGetDynamic() throws Exception { - oidc.setX509SigningUrl(x509Url.getPath()); - oidc.setJwkSigningUrl(jwkUrl.getPath()); - oidc.setClientSecret("foo"); - assertEquals(oidc.getDynamic().getSigningX509Url(), x509Url.getPath()); - assertEquals(oidc.getDynamic().getSigningJwkUrl(), jwkUrl.getPath()); - assertEquals(oidc.getDynamic().getClientSecret(), "foo"); - } } diff --git a/openid-connect-client/src/test/resources/test-context.xml b/openid-connect-client/src/test/resources/test-context.xml new file mode 100644 index 000000000..d9a6435a6 --- /dev/null +++ b/openid-connect-client/src/test/resources/test-context.xml @@ -0,0 +1,46 @@ + + + + + + + + + + file:db/tables/accesstoken.sql + file:db/tables/address.sql + file:db/tables/approvedsite.sql + file:db/tables/authorities.sql + file:db/tables/clientdetails.sql + file:db/tables/event.sql + file:db/tables/granttypes.sql + file:db/tables/idtoken.sql + file:db/tables/idtokenclaims.sql + file:db/tables/refreshtoken.sql + file:db/tables/scope.sql + file:db/tables/userinfo.sql + file:db/tables/whitelistedsite.sql + + classpath:test-data.sql + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openid-connect-common/.classpath b/openid-connect-common/.classpath index bf96ac098..6f70891b9 100644 --- a/openid-connect-common/.classpath +++ b/openid-connect-common/.classpath @@ -1,14 +1,18 @@ - + + + + + diff --git a/openid-connect-common/.settings/org.eclipse.jdt.core.prefs b/openid-connect-common/.settings/org.eclipse.jdt.core.prefs index d2a6e1e36..d47a0fc68 100644 --- a/openid-connect-common/.settings/org.eclipse.jdt.core.prefs +++ b/openid-connect-common/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,19 @@ -#Fri Mar 16 16:16:57 EDT 2012 eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=warning +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/openid-connect-common/.settings/org.eclipse.jdt.launching.prefs b/openid-connect-common/.settings/org.eclipse.jdt.launching.prefs new file mode 100644 index 000000000..d211d3263 --- /dev/null +++ b/openid-connect-common/.settings/org.eclipse.jdt.launching.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java index 86a0ce452..b73113120 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/HmacSigner.java @@ -117,10 +117,15 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet(){ - mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()) - .getStandardName()); + try { + mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()) + .getStandardName()); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } logger.debug(JwsAlgorithm.getByName(getAlgorithm()).getStandardName() + " ECDSA Signer ready for business"); @@ -135,23 +140,23 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { */ @Override public String generateSignature(String signatureBase) throws NoSuchAlgorithmException { - Mac _mac = getMac(); + afterPropertiesSet(); if (passphrase == null) { throw new IllegalArgumentException("Passphrase cannot be null"); } try { - _mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac + mac.init(new SecretKeySpec(getPassphrase().getBytes(), mac .getAlgorithm())); - _mac.update(signatureBase.getBytes("UTF-8")); + mac.update(signatureBase.getBytes("UTF-8")); } catch (GeneralSecurityException e) { logger.error(e); } catch (UnsupportedEncodingException e) { logger.error(e); } - byte[] sigBytes = _mac.doFinal(); + byte[] sigBytes = mac.doFinal(); String sig = new String(Base64.encodeBase64URLSafe(sigBytes)); @@ -172,15 +177,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { public void setPassphrase(String passphrase) { this.passphrase = passphrase; } - - // TODO: this this indirection to a lazy constructor necessary? - private Mac getMac() throws NoSuchAlgorithmException { - if(mac == null){ - mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()) - .getStandardName()); - } - return mac; - } + /* * (non-Javadoc) diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java index b394d4153..75a773999 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/impl/RsaSigner.java @@ -177,13 +177,18 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public String generateSignature(String signatureBase) throws NoSuchAlgorithmException { String sig = null; - Signature _signer = getSigner(); + try { + initializeSigner(); + } catch (GeneralSecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } try { - _signer.initSign(privateKey); - _signer.update(signatureBase.getBytes("UTF-8")); + signer.initSign(privateKey); + signer.update(signatureBase.getBytes("UTF-8")); - byte[] sigBytes = _signer.sign(); + byte[] sigBytes = signer.sign(); sig = (new String(Base64.encodeBase64URLSafe(sigBytes))).replace("=", ""); } catch (GeneralSecurityException e) { @@ -230,13 +235,9 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public void setPrivateKey(RSAPrivateKey privateKey) { this.privateKey = privateKey; } - - // TODO: this this indirection to a lazy constructor really necessary? - private Signature getSigner() throws NoSuchAlgorithmException{ - if(signer == null){ - signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); - } - return signer; + + public void initializeSigner() throws NoSuchAlgorithmException{ + signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); } /* diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java index 042d3fc41..708f537f3 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/JwtSigningAndValidationService.java @@ -41,17 +41,6 @@ public interface JwtSigningAndValidationService { */ 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 expectedIssuer - * the expected issuer - * @return true if the JWT was issued by this expected issuer, false if not - */ - public boolean validateIssuedJwt(Jwt jwt, String expectedIssuer); - /** * Checks the signature of the given JWT against all configured signers, * returns true if at least one of the signers validates it. @@ -63,14 +52,7 @@ public interface JwtSigningAndValidationService { */ public boolean validateSignature(String jwtString) throws NoSuchAlgorithmException; - /** - * Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm. - * Use the default algorithm to sign. - * - * @param jwt the jwt to sign - * @return the signed jwt - * @throws NoSuchAlgorithmException - */ + /** * Checks to see when this JWT was issued * @@ -81,17 +63,6 @@ public interface JwtSigningAndValidationService { */ public boolean validateIssuedAt(Jwt jwt); - /** - * Checks the audience that the given JWT against the client_id of the Client - * - * @param jwt - * @param clientId - * the string representation of the client_id - * @return true if the audience matches the clinet_id, false if otherwise - * @throws NoSuchAlgorithmException - */ - public boolean validateAudience(Jwt jwt, String clientId); - /** * Checks to see if the nonce parameter sent in the Authorization Request * is equal to the nonce parameter in the id token @@ -112,6 +83,15 @@ public interface JwtSigningAndValidationService { * @param alg the name of the algorithm to use, as specified in JWS s.6 * @return the signed jwt */ + + /** + * Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm. + * Use the default algorithm to sign. + * + * @param jwt the jwt to sign + * @return the signed jwt + * @throws NoSuchAlgorithmException + */ public void signJwt(Jwt jwt) throws NoSuchAlgorithmException; //TODO: implement later; only need signJwt(Jwt jwt) for now diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java index e3cc3a833..81e7c539a 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java @@ -29,18 +29,6 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni } } - @Override - public boolean validateIssuedJwt(Jwt jwt, String expectedIssuer) { - - String iss = jwt.getClaims().getIssuer(); - - if (iss.equals(expectedIssuer)) { - return true; - } - - return false; - } - @Override public boolean validateSignature(String jwtString) throws NoSuchAlgorithmException { @@ -63,16 +51,6 @@ public abstract class AbstractJwtSigningAndValidationService implements JwtSigni } } - @Override - public boolean validateAudience(Jwt jwt, String expectedAudience) { - - if(jwt.getClaims().getAudience().equals(expectedAudience)){ - return true; - } else { - return false; - } - } - @Override public boolean validateNonce(Jwt jwt, String nonce) { if(jwt.getClaims().getNonce().equals(nonce)){ diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java index 0c327d890..abb8a2a54 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java @@ -1,10 +1,14 @@ package org.mitre.jwt.signer.service.impl; import java.io.File; +import java.net.MalformedURLException; import java.net.URL; import java.security.Key; +import java.security.NoSuchAlgorithmException; import java.security.PublicKey; +import java.security.cert.CertificateException; import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -15,6 +19,7 @@ import org.mitre.jwt.signer.JwtSigner; import org.mitre.jwt.signer.impl.HmacSigner; import org.mitre.jwt.signer.impl.PlaintextSigner; import org.mitre.jwt.signer.impl.RsaSigner; +import org.mitre.key.fetch.KeyFetcher; import org.mitre.util.Utility; @@ -40,18 +45,38 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd setClientSecret(clientSecret); } - // FIXME: this function should not throw Exception - public Key getSigningKey() throws Exception { + public Key getSigningKey() { if(signingKey == null){ if(x509SigningUrl != null){ File file = new File(x509SigningUrl); - URL url = file.toURI().toURL(); - signingKey = Utility.retrieveX509Key(url); + URL url; + try { + url = file.toURI().toURL(); + signingKey = KeyFetcher.retrieveX509Key(); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else if (jwkSigningUrl != null){ File file = new File(jwkSigningUrl); - URL url = file.toURI().toURL(); - signingKey = Utility.retrieveJwkKey(url); + URL url; + try { + url = file.toURI().toURL(); + signingKey = KeyFetcher.retrieveJwkKey(); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } return signingKey; @@ -156,17 +181,6 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd return false; } - @Override - public boolean validateAudience(Jwt jwt, String clientId) { - - if(jwt.getClaims().getAudience().equals(clientId)){ - return true; - } - else{ - return false; - } - } - @Override public boolean validateNonce(Jwt jwt, String nonce) { if(jwt.getClaims().getNonce().equals(nonce)){ diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java index c2a9256e0..f1078ce75 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/JwtSigningAndValidationServiceDefault.java @@ -67,7 +67,7 @@ public class JwtSigningAndValidationServiceDefault extends AbstractJwtSigningAnd * org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet(){ // used for debugging... if (!signers.isEmpty()) { logger.info(this.toString()); @@ -175,17 +175,6 @@ public class JwtSigningAndValidationServiceDefault extends AbstractJwtSigningAnd return false; } - @Override - public boolean validateAudience(Jwt jwt, String clientId) { - - if(clientId.equals(jwt.getClaims().getAudience())){ - return true; - } - else{ - return false; - } - } - @Override public boolean validateNonce(Jwt jwt, String nonce) { if(nonce.equals(jwt.getClaims().getNonce())){ diff --git a/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java b/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java new file mode 100644 index 000000000..bf2eea1ab --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java @@ -0,0 +1,145 @@ +package org.mitre.key.fetch; + +import java.io.InputStream; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.DefaultHttpClient; +import org.mitre.jwk.model.EC; +import org.mitre.jwk.model.Jwk; +import org.mitre.jwk.model.Rsa; +import org.mitre.openid.connect.client.OIDCServerConfiguration; + +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.ResponseExtractor; +import org.springframework.web.client.RestTemplate; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class KeyFetcher { + + public static List retrieveJwk(){ + + OIDCServerConfiguration serverConfig = new OIDCServerConfiguration(); + + List keys = new ArrayList(); + + HttpClient httpClient = new DefaultHttpClient(); + HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + RestTemplate restTemplate = new RestTemplate(httpFactory); + MultiValueMap form = new LinkedMultiValueMap(); + + String jsonString = null; + + try { + jsonString = restTemplate.postForObject( + serverConfig.getTokenEndpointURI(), form, String.class); + } catch (HttpClientErrorException httpClientErrorException) { + + throw new AuthenticationServiceException( + "Unable to obtain Access Token."); + } + + JsonObject json = (JsonObject) new JsonParser().parse(jsonString); + JsonArray getArray = json.getAsJsonArray("jwk"); + + for(int i = 0; i < getArray.size(); i++){ + + JsonObject object = getArray.get(i).getAsJsonObject(); + String algorithm = object.get("alg").getAsString(); + + if(algorithm.equals("RSA")){ + Rsa rsa = new Rsa(object); + keys.add(rsa); + } + + else{ + EC ec = new EC(object); + keys.add(ec); + } + } + return keys; + } + + public static Key retrieveX509Key() throws CertificateException { + + OIDCServerConfiguration serverConfig = new OIDCServerConfiguration(); + + HttpClient httpClient = new DefaultHttpClient(); + HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + RestTemplate restTemplate = new RestTemplate(httpFactory); + MultiValueMap form = new LinkedMultiValueMap(); + + InputStream jsonStream = null; + + try { + jsonStream = restTemplate.postForObject( + serverConfig.getTokenEndpointURI(), form, InputStream.class); + } catch (HttpClientErrorException httpClientErrorException) { + + throw new AuthenticationServiceException( + "Unable to obtain Access Token."); + } + + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) factory.generateCertificate(jsonStream); + Key key = cert.getPublicKey(); + + return key; + } + + public static Key retrieveJwkKey() throws NoSuchAlgorithmException, InvalidKeySpecException{ + + OIDCServerConfiguration serverConfig = new OIDCServerConfiguration(); + + HttpClient httpClient = new DefaultHttpClient(); + HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + RestTemplate restTemplate = new RestTemplate(httpFactory); + MultiValueMap form = new LinkedMultiValueMap(); + + String jsonString = null; + + try { + jsonString = restTemplate.postForObject( + serverConfig.getTokenEndpointURI(), form, String.class); + } catch (HttpClientErrorException httpClientErrorException) { + + throw new AuthenticationServiceException( + "Unable to obtain Access Token."); + } + + JsonObject json = (JsonObject) new JsonParser().parse(jsonString); + JsonArray getArray = json.getAsJsonArray("jwk"); + JsonObject object = getArray.get(0).getAsJsonObject(); + + byte[] modulusByte = Base64.decodeBase64(object.get("mod").getAsString()); + BigInteger modulus = new BigInteger(modulusByte); + byte[] exponentByte = Base64.decodeBase64(object.get("exp").getAsString()); + BigInteger exponent = new BigInteger(exponentByte); + + RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); + KeyFactory factory = KeyFactory.getInstance("RSA"); + PublicKey pub = factory.generatePublic(spec); + + return pub; + } + +} diff --git a/openid-connect-common/src/main/java/org/mitre/util/Utility.java b/openid-connect-common/src/main/java/org/mitre/util/Utility.java index 35acac409..60ed60d08 100644 --- a/openid-connect-common/src/main/java/org/mitre/util/Utility.java +++ b/openid-connect-common/src/main/java/org/mitre/util/Utility.java @@ -69,60 +69,5 @@ public class Utility { } return issuer; } - - // FIXME: this should use a rest template and sould not throw Exception - public static List retrieveJwk(URL path) throws Exception { - List keys = new ArrayList(); - - JsonParser parser = new JsonParser(); - JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(path.openStream()))).getAsJsonObject(); - JsonArray getArray = json.getAsJsonArray("jwk"); - - for(int i = 0; i < getArray.size(); i++){ - - JsonObject object = getArray.get(i).getAsJsonObject(); - String algorithm = object.get("alg").getAsString(); - - if(algorithm.equals("RSA")){ - Rsa rsa = new Rsa(object); - keys.add(rsa); - } - else{ - EC ec = new EC(object); - keys.add(ec); - } - } - return keys; - } - - // FIXME: this should use a rest template and sould not throw Exception - public static Key retrieveX509Key(URL url) throws Exception { - - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) factory.generateCertificate(url.openStream()); - Key key = cert.getPublicKey(); - - return key; - } - - // FIXME: this should use a rest template and sould not throw Exception - public static Key retrieveJwkKey(URL url) throws Exception { - - JsonParser parser = new JsonParser(); - JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); - JsonArray getArray = json.getAsJsonArray("jwk"); - JsonObject object = getArray.get(0).getAsJsonObject(); - - byte[] modulusByte = Base64.decodeBase64(object.get("mod").getAsString()); - BigInteger modulus = new BigInteger(modulusByte); - byte[] exponentByte = Base64.decodeBase64(object.get("exp").getAsString()); - BigInteger exponent = new BigInteger(exponentByte); - - RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); - KeyFactory factory = KeyFactory.getInstance("RSA"); - PublicKey pub = factory.generatePublic(spec); - - return pub; - } } diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac256Test.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac256Test.java new file mode 100644 index 000000000..6ace0a0be --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac256Test.java @@ -0,0 +1,68 @@ +package org.mitre.jwt.signer.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class Hmac256Test{ + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL hs256Url = this.getClass().getResource("/jwt/hs256"); + + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + + /** + * @throws IOException + * @throws JsonSyntaxException + * @throws JsonIOException + * @throws java.lang.Exception + */ + @Before + public void setUp() throws JsonIOException, JsonSyntaxException, IOException{ + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(hs256Url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown(){ + } + + @Test + public void testHmacSigner256() throws Exception { + setUp(); + HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); + jwt = hmac.sign(jwt); + assertEquals(hmac.verify(jwt.toString()), true); + } +} + \ No newline at end of file diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac384Test.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac384Test.java new file mode 100644 index 000000000..efac2ef49 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac384Test.java @@ -0,0 +1,68 @@ +package org.mitre.jwt.signer.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class Hmac384Test { + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL hs384Url = this.getClass().getResource("/jwt/hs384"); + + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + + /** + * @throws IOException + * @throws JsonSyntaxException + * @throws JsonIOException + * @throws java.lang.Exception + */ + @Before + public void setUp() throws JsonIOException, JsonSyntaxException, IOException{ + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(hs384Url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown(){ + } + + @Test + public void testHmacSigner384() throws Exception { + setUp(); + HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); + jwt = hmac.sign(jwt); + assertEquals(hmac.verify(jwt.toString()), true); + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac512Test.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac512Test.java new file mode 100644 index 000000000..d4b06049e --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Hmac512Test.java @@ -0,0 +1,68 @@ +package org.mitre.jwt.signer.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class Hmac512Test { + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL hs512Url = this.getClass().getResource("/jwt/hs512"); + + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + + /** + * @throws IOException + * @throws JsonSyntaxException + * @throws JsonIOException + * @throws java.lang.Exception + */ + @Before + public void setUp() throws JsonIOException, JsonSyntaxException, IOException{ + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(hs512Url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown(){ + } + + @Test + public void testHmacSigner512() throws Exception { + setUp(); + HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); + jwt = hmac.sign(jwt); + assertEquals(hmac.verify(jwt.toString()), true); + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java index 446212872..f67a9e476 100644 --- a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java @@ -1,22 +1,31 @@ package org.mitre.jwt.signer.impl; +import static org.junit.Assert.assertEquals; + import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; +import java.security.NoSuchAlgorithmException; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mitre.jwt.model.Jwt; import org.mitre.jwt.model.JwtClaims; import org.mitre.jwt.model.JwtHeader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import com.google.gson.JsonIOException; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; -import junit.framework.TestCase; - -public class PlaintextSignerTest extends TestCase { +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class PlaintextSignerTest{ URL claimsUrl = this.getClass().getResource("/jwt/claims"); URL plaintextUrl = this.getClass().getResource("/jwt/plaintext"); @@ -25,13 +34,16 @@ public class PlaintextSignerTest extends TestCase { JwtHeader header = null; /** + * @throws IOException + * @throws JsonSyntaxException + * @throws JsonIOException * @throws java.lang.Exception */ @Before - public void setUp(URL url) throws Exception { + public void setUp() throws JsonIOException, JsonSyntaxException, IOException { JsonParser parser = new JsonParser(); JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); - JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(plaintextUrl.openStream()))).getAsJsonObject(); claims = new JwtClaims(claimsObject); header = new JwtHeader(headerObject); jwt = new Jwt(header, claims, null); @@ -41,12 +53,12 @@ public class PlaintextSignerTest extends TestCase { * @throws java.lang.Exception */ @After - public void tearDown() throws Exception { + public void tearDown() { } @Test - public void testPlaintextSigner() throws Exception { - setUp(plaintextUrl); + public void testPlaintextSigner() throws JsonIOException, JsonSyntaxException, IOException, NoSuchAlgorithmException { + setUp(); PlaintextSigner plaintext = new PlaintextSigner(); jwt = plaintext.sign(jwt); assertEquals(plaintext.verify(jwt.toString()), true); diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa256Test.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa256Test.java new file mode 100644 index 000000000..1d9ac0f97 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa256Test.java @@ -0,0 +1,82 @@ +package org.mitre.jwt.signer.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; +import org.mitre.jwt.signer.JwsAlgorithm; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class Rsa256Test{ + + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL rs256Url = this.getClass().getResource("/jwt/rs256"); + + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + KeyPairGenerator keyGen; + KeyPair keyPair; + PublicKey publicKey; + PrivateKey privateKey; + + /** + * @throws IOException + * @throws JsonSyntaxException + * @throws JsonIOException + * @throws java.lang.Exception + */ + @Before + public void setUp() throws JsonIOException, JsonSyntaxException, IOException{ + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(rs256Url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown(){ + } + + @Test + public void testRsaSigner256() throws Exception { + + keyGen = KeyPairGenerator.getInstance("RSA"); + keyPair = keyGen.generateKeyPair(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS256.toString(), publicKey, privateKey); + jwt = rsa.sign(jwt); + assertEquals(rsa.verify(jwt.toString()), true); + + } + +} \ No newline at end of file diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa384Test.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa384Test.java new file mode 100644 index 000000000..c3039ac90 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa384Test.java @@ -0,0 +1,81 @@ +package org.mitre.jwt.signer.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; +import org.mitre.jwt.signer.JwsAlgorithm; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class Rsa384Test { + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL rs384Url = this.getClass().getResource("/jwt/rs384"); + + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + KeyPairGenerator keyGen; + KeyPair keyPair; + PublicKey publicKey; + PrivateKey privateKey; + + /** + * @throws IOException + * @throws JsonSyntaxException + * @throws JsonIOException + * @throws java.lang.Exception + */ + @Before + public void setUp() throws JsonIOException, JsonSyntaxException, IOException{ + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(rs384Url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown(){ + } + + @Test + public void testRsaSigner384() throws Exception{ + setUp(); + keyGen = KeyPairGenerator.getInstance("RSA"); + keyPair = keyGen.generateKeyPair(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS384.toString(), publicKey, privateKey); + jwt = rsa.sign(jwt); + assertEquals(rsa.verify(jwt.toString()), true); + + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa512Test.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa512Test.java new file mode 100644 index 000000000..8da0a4b1f --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/Rsa512Test.java @@ -0,0 +1,81 @@ +package org.mitre.jwt.signer.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwt.model.Jwt; +import org.mitre.jwt.model.JwtClaims; +import org.mitre.jwt.model.JwtHeader; +import org.mitre.jwt.signer.JwsAlgorithm; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class Rsa512Test { + + URL claimsUrl = this.getClass().getResource("/jwt/claims"); + URL rs512Url = this.getClass().getResource("/jwt/rs512"); + + Jwt jwt = null; + JwtClaims claims = null; + JwtHeader header = null; + KeyPairGenerator keyGen; + KeyPair keyPair; + PublicKey publicKey; + PrivateKey privateKey; + + /** + * @throws IOException + * @throws JsonSyntaxException + * @throws JsonIOException + * @throws java.lang.Exception + */ + @Before + public void setUp() throws JsonIOException, JsonSyntaxException, IOException{ + JsonParser parser = new JsonParser(); + JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); + JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(rs512Url.openStream()))).getAsJsonObject(); + claims = new JwtClaims(claimsObject); + header = new JwtHeader(headerObject); + jwt = new Jwt(header, claims, null); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown(){ + } + + @Test + public void testRsaSigner512() throws Exception{ + setUp(); + keyGen = KeyPairGenerator.getInstance("RSA"); + keyPair = keyGen.generateKeyPair(); + publicKey = keyPair.getPublic(); + privateKey = keyPair.getPrivate(); + RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS512.toString(), publicKey, privateKey); + jwt = rsa.sign(jwt); + assertEquals(rsa.verify(jwt.toString()), true); + + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java index 95391cea0..d65298590 100644 --- a/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java @@ -1,5 +1,7 @@ package org.mitre.jwt.signer.service.impl; +import static org.junit.Assert.assertEquals; + import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; @@ -10,12 +12,17 @@ import junit.framework.TestCase; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mitre.jwt.signer.JwtSigner; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -public class DynamicJwtSigningAndValidationServiceTest extends TestCase { +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class DynamicJwtSigningAndValidationServiceTest { URL x509Url = this.getClass().getResource("/x509/x509Cert"); URL jwkUrl = this.getClass().getResource("/jwk/rsaOnly"); @@ -29,7 +36,6 @@ public class DynamicJwtSigningAndValidationServiceTest extends TestCase { */ @Before public void setUp() throws Exception { - super.setUp(); } /** diff --git a/openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java b/openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java new file mode 100644 index 000000000..cf3f87a8e --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java @@ -0,0 +1,70 @@ +package org.mitre.key.fetch; + +import static org.junit.Assert.assertEquals; + + +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.List; + +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.DefaultHttpClient; +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mitre.jwk.model.EC; +import org.mitre.jwk.model.Jwk; +import org.mitre.jwk.model.Rsa; +import org.mitre.openid.connect.client.OIDCServerConfiguration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import static org.easymock.EasyMock.createNiceMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class KeyFetcherTest { + + private KeyFetcher keyFetch; + + @Before + public void setUp(){ + keyFetch = EasyMock.createMock(KeyFetcher.class); + } + + @After + public void tearDown(){ + } + + @Test + public void retrieveJwkTest(){ + //EasyMock.expect(keyFetch.retrieveJwk()).andReturn(Rsa(new JsonObject(object))).once(); + } + + @Test + public void retrieveX509Key(){ + + } + + @Test + public void retriveJwkKey(){ + + } + +} diff --git a/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java b/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java index 674e2306a..66ebc7cd6 100644 --- a/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java +++ b/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java @@ -3,6 +3,8 @@ */ package org.mitre.util; +import static org.junit.Assert.assertEquals; + import java.security.Key; import java.security.KeyFactory; import java.security.PublicKey; @@ -23,10 +25,14 @@ import junit.framework.TestCase; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mitre.jwk.model.Jwk; import org.mitre.jwk.model.Rsa; import org.mitre.jwk.model.EC; +import org.mitre.key.fetch.KeyFetcher; import org.mitre.util.Utility; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -42,7 +48,9 @@ import org.bouncycastle.jce.provider.JCEECPublicKey; * @author DERRYBERRY * */ -public class UtilityTest extends TestCase{ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) +public class UtilityTest { URL url = this.getClass().getResource("/jwk/jwkSuccess"); URL certUrl = this.getClass().getResource("/x509/x509Cert"); @@ -53,7 +61,6 @@ public class UtilityTest extends TestCase{ */ @Before public void setUp() throws Exception { - super.setUp(); } /** @@ -74,7 +81,7 @@ public class UtilityTest extends TestCase{ JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); JsonArray getArray = json.getAsJsonArray("jwk"); - List list = Utility.retrieveJwk(url); + List list = KeyFetcher.retrieveJwk(); for(int i = 0; i < list.size(); i++){ @@ -108,7 +115,7 @@ public class UtilityTest extends TestCase{ JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); JsonArray getArray = json.getAsJsonArray("jwk"); - List list = Utility.retrieveJwk(url); + List list = KeyFetcher.retrieveJwk(); for(int i = 0; i < list.size(); i++){ Jwk jwk = list.get(i); @@ -133,14 +140,14 @@ public class UtilityTest extends TestCase{ public void testRetriveX509Key() throws Exception { CertificateFactory factory = CertificateFactory.getInstance("X.509"); X509Certificate x509 = (X509Certificate) factory.generateCertificate(certUrl.openStream()); - Key key = Utility.retrieveX509Key(certUrl); + Key key = KeyFetcher.retrieveX509Key(); assertEquals(x509.getPublicKey(), key); assertEquals("RSA", key.getAlgorithm()); assertEquals("X.509", key.getFormat()); } public void testRetriveJwkKey() throws Exception { - Key key = Utility.retrieveJwkKey(rsaUrl); + Key key = KeyFetcher.retrieveJwkKey(); JsonParser parser = new JsonParser(); JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(rsaUrl.openStream()))).getAsJsonObject(); diff --git a/openid-connect-common/src/test/resources/test-context.xml b/openid-connect-common/src/test/resources/test-context.xml new file mode 100644 index 000000000..c849de679 --- /dev/null +++ b/openid-connect-common/src/test/resources/test-context.xml @@ -0,0 +1,40 @@ + + + + + + + + + + file:db/tables/accesstoken.sql + file:db/tables/address.sql + file:db/tables/approvedsite.sql + file:db/tables/authorities.sql + file:db/tables/clientdetails.sql + file:db/tables/event.sql + file:db/tables/granttypes.sql + file:db/tables/idtoken.sql + file:db/tables/idtokenclaims.sql + file:db/tables/refreshtoken.sql + file:db/tables/scope.sql + file:db/tables/userinfo.sql + file:db/tables/whitelistedsite.sql + + classpath:test-data.sql + + + + + + + + + + + \ No newline at end of file diff --git a/openid-connect-server/.settings/org.eclipse.jdt.core.prefs b/openid-connect-server/.settings/org.eclipse.jdt.core.prefs index 34653a858..d47a0fc68 100644 --- a/openid-connect-server/.settings/org.eclipse.jdt.core.prefs +++ b/openid-connect-server/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,19 @@ -#Wed Jan 04 13:07:35 EST 2012 eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=warning +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/openid-connect-server/.settings/org.eclipse.jdt.launching.prefs b/openid-connect-server/.settings/org.eclipse.jdt.launching.prefs new file mode 100644 index 000000000..d211d3263 --- /dev/null +++ b/openid-connect-server/.settings/org.eclipse.jdt.launching.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java index 346626ccd..c46694b7e 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/CheckIDEndpoint.java @@ -69,9 +69,9 @@ public class CheckIDEndpoint { } // check the issuer (sanity check) - if (!jwtSignerService.validateIssuedJwt(token, configBean.getIssuer())) { - throw new InvalidJwtIssuerException("The JWT issuer is invalid."); - } + //if (!jwtSignerService.validateIssuedJwt(token, configBean.getIssuer())) { + // throw new InvalidJwtIssuerException("The JWT issuer is invalid."); + //} // pass the claims directly (the view doesn't care about other fields) return new ModelAndView("jsonIdTokenView", "entity", token.getClaims()); From b1fc07bcb8c7cd603bc5c7111e4d2bd8320804c2 Mon Sep 17 00:00:00 2001 From: Mike Derryberry Date: Thu, 21 Jun 2012 14:37:30 -0400 Subject: [PATCH 6/6] updated -common code to get a validation service from a server configuration --- .../AbstractOIDCAuthenticationFilter.java | 89 +++++++- .../client/OIDCServerConfiguration.java | 69 ------ .../connect/client/OIDCUserDetailService.java | 43 ---- .../openid/connect/client/UrlValidator.java | 39 ---- .../client/OIDCServerConfigurationTest.java | 148 ------------ .../src/test/resources/test-context.xml | 6 - .../main/java/org/mitre/jwk/model/Rsa.java | 3 - .../java/org/mitre/jwt/model/JwtHeader.java | 3 - ...DynamicJwtSigningAndValidationService.java | 67 +----- .../java/org/mitre/key/fetch/KeyFetcher.java | 65 ++---- .../service/ClientUserDetailsService.java | 1 - .../src/main/java/org/mitre/util/Utility.java | 26 --- .../mitre/jwt/signer/impl/HmacSignerTest.java | 73 ------ .../mitre/jwt/signer/impl/RsaSignerTest.java | 99 -------- ...micJwtSigningAndValidationServiceTest.java | 14 +- .../org/mitre/key/fetch/KeyFetcherTest.java | 70 ------ .../test/java/org/mitre/util/UtilityTest.java | 213 ------------------ 17 files changed, 122 insertions(+), 906 deletions(-) delete mode 100644 openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java delete mode 100644 openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java delete mode 100644 openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java delete mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java delete mode 100644 openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java delete mode 100644 openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java delete mode 100644 openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java index 592a2d041..c96c7cb83 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/AbstractOIDCAuthenticationFilter.java @@ -20,15 +20,18 @@ import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URLEncoder; import java.security.GeneralSecurityException; +import java.security.Key; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -43,16 +46,20 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.mitre.openid.connect.model.IdToken; +import org.mitre.jwk.model.Jwk; import org.mitre.jwt.model.Jwt; import org.mitre.jwt.model.JwtHeader; -import org.mitre.jwt.model.JwtClaims; import org.mitre.jwt.signer.AbstractJwtSigner; +import org.mitre.jwt.signer.JwtSigner; 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.JwtSigningAndValidationService; import org.mitre.jwt.signer.service.impl.DynamicJwtSigningAndValidationService; +import org.mitre.key.fetch.KeyFetcher; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; @@ -145,6 +152,9 @@ public class AbstractOIDCAuthenticationFilter extends protected final static String FILTER_PROCESSES_URL = "/openid_connect_login"; + + private Map validationServices = new HashMap(); + /** * Builds the redirect_uri that will be sent to the Authorization Endpoint. * By default returns the URL of the current request minus zero or more @@ -658,4 +668,77 @@ public class AbstractOIDCAuthenticationFilter extends public void setScope(String scope) { this.scope = scope; } + + + protected JwtSigningAndValidationService getValidatorForServer(OIDCServerConfiguration serverConfig) throws CertificateException, NoSuchAlgorithmException, InvalidKeySpecException { + + if(getValidationServices().containsKey(serverConfig)){ + return validationServices.get(serverConfig); + } else { + + HttpClient httpClient = new DefaultHttpClient(); + HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + RestTemplate restTemplate = new RestTemplate(httpFactory); + KeyFetcher keyFetch = new KeyFetcher(); + PublicKey signingKey = null; + + String jsonString; + + + if(serverConfig.getX509SigningUrl() != null) { + try { + jsonString = restTemplate.getForObject( + serverConfig.getX509SigningUrl(), String.class); + } catch (HttpClientErrorException httpClientErrorException) { + + throw new AuthenticationServiceException( + "Unable to obtain Access Token."); + } + + signingKey = (PublicKey) keyFetch.retrieveX509Key(serverConfig); + + } else { + try { + jsonString = restTemplate.getForObject(serverConfig.getX509SigningUrl(), String.class); + } catch (HttpClientErrorException httpClientErrorException) { + + throw new AuthenticationServiceException("Unable to obtain Access Token."); + } + + signingKey = (PublicKey) keyFetch.retrieveJwkKey(serverConfig); + } + + DynamicJwtSigningAndValidationService signingAndValidationService = new DynamicJwtSigningAndValidationService(serverConfig.getX509SigningUrl(), serverConfig.getJwkSigningUrl(), serverConfig.getClientSecret()); + + JwtHeader header = Jwt.parse(jsonString).getHeader(); + String alg = header.getAlgorithm(); + JwtSigner signer = null; + + if(alg.equals("HS256") || alg.equals("HS384") || alg.equals("HS512")){ + signer = new HmacSigner(alg, signingKey.toString()); + } else if (alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")){ + signer = new RsaSigner(alg, signingKey, null); + } else if (alg.equals("none")){ + signer = new PlaintextSigner(); + } else { + throw new IllegalArgumentException("Not an existing algorithm type"); + } + + validationServices.put(serverConfig, signingAndValidationService); + return signingAndValidationService; + } + + } + + public Map getValidationServices() { + return validationServices; + } + + public void setValidationServices( + Map validationServices) { + this.validationServices = validationServices; + } + + + } diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java index ae4693469..af0e9c658 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java +++ b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java @@ -15,12 +15,6 @@ ******************************************************************************/ package org.mitre.openid.connect.client; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; -import org.mitre.key.fetch.KeyFetcher; - /** * @author nemonik * @@ -44,12 +38,6 @@ public class OIDCServerConfiguration { private String jwkEncryptUrl; private String jwkSigningUrl; - - - // TODO: these keys should be settable through other means beyond discovery - private Key encryptKey; - - private Key signingKey; public String getAuthorizationEndpointURI() { return authorizationEndpointURI; @@ -122,63 +110,6 @@ public class OIDCServerConfiguration { public void setJwkSigningUrl(String jwkSigningUrl) { this.jwkSigningUrl = jwkSigningUrl; } - - public Key getSigningKey(){ - if(signingKey == null){ - if(x509SigningUrl != null){ - try { - signingKey = KeyFetcher.retrieveX509Key(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - else if (jwkSigningUrl != null){ - try { - signingKey = KeyFetcher.retrieveJwkKey(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - return signingKey; - } - - public Key getEncryptionKey(){ - if(encryptKey == null){ - if(x509EncryptUrl != null){ - try { - encryptKey = KeyFetcher.retrieveX509Key(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - else if (jwkEncryptUrl != null){ - try { - encryptKey = KeyFetcher.retrieveJwkKey(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - return encryptKey; - } - - public void checkKeys(){ - encryptKey = null; - signingKey = null; - getEncryptionKey(); - getSigningKey(); - } @Override public String toString() { diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java deleted file mode 100644 index 301c71b4e..000000000 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCUserDetailService.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.mitre.openid.connect.client; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; - -import org.mitre.openid.connect.model.IdToken; -import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - - -// TODO: what is this class for? - - -public class OIDCUserDetailService implements UserDetailsService, - AuthenticationUserDetailsService { - - public IdToken retrieveToken(URL url) throws IOException{ - String str = new BufferedReader(new InputStreamReader(url.openStream())).toString(); - IdToken idToken = IdToken.parse(str); - return idToken; - } - - - @Override - public UserDetails loadUserDetails(OpenIdConnectAuthenticationToken token) - throws UsernameNotFoundException { - // TODO Auto-generated method stub - - return null; - } - - @Override - public UserDetails loadUserByUsername(String username) - throws UsernameNotFoundException { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java deleted file mode 100644 index a89f216e6..000000000 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/UrlValidator.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.mitre.openid.connect.client; - -import org.springframework.validation.Errors; -import org.springframework.validation.ValidationUtils; -import org.springframework.validation.Validator; - -// TODO: is this used anywhere? - -public class UrlValidator implements Validator{ - - - - @Override - public boolean supports(Class clzz) { - return OIDCServerConfiguration.class.equals(clzz); - } - - @Override - public void validate(Object obj, Errors e) { - ValidationUtils.rejectIfEmpty(e, "x509EncryptUrl", "x509EncryptUrl.empty"); - - } - - // TODO this isn't called anywhere - public void validate1(Object obj, Errors e) { - ValidationUtils.rejectIfEmpty(e, "x509SigningUrl", "x509SigningUrl.empty"); - } - - // TODO this isn't called anywhere - public void validate2(Object obj, Errors e) { - ValidationUtils.rejectIfEmpty(e, "jwkEncryptUrl", "jwkEncryptUrl.empty"); - } - - // TODO this isn't called anywhere - public void validate3(Object obj, Errors e) { - ValidationUtils.rejectIfEmpty(e, "jwkSigningUrl", "jwkSigningUrl.empty"); - } - -} \ No newline at end of file diff --git a/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java b/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java deleted file mode 100644 index ba208afc9..000000000 --- a/openid-connect-client/src/test/java/org/mitre/openid/connect/client/OIDCServerConfigurationTest.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.mitre.openid.connect.client; - -import static org.junit.Assert.assertEquals; - -import java.net.URL; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mitre.key.fetch.KeyFetcher; -import org.mitre.util.Utility; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { "classpath:test-context.xml" }) -public class OIDCServerConfigurationTest{ - - private URL jwkUrl = this.getClass().getResource("/jwk/jwk"); - private URL x509Url = this.getClass().getResource("/x509/x509"); - private URL jwkEncryptedUrl = this.getClass().getResource("/jwk/jwkEncrypted"); - private URL x509EncryptedUrl = this.getClass().getResource("/x509/x509Encrypted"); - private OIDCServerConfiguration oidc; - - /** - * @throws java.lang.Exception - */ - @Before - public void setUp(){ - oidc = new OIDCServerConfiguration(); - } - - /** - * @throws java.lang.Exception - */ - @After - public void tearDown(){ - } - - /** - * Test method for {@link org.mitre.util.Utility#retrieveJwk(java.lang.String)}. - * @throws Exception - */ - @Test - public void testGetSigningKeyBoth(){ - oidc.setX509SigningUrl(x509Url.getPath()); - oidc.setJwkSigningUrl(jwkUrl.getPath()); - Key key = oidc.getSigningKey(); - try { - assertEquals(key, KeyFetcher.retrieveX509Key()); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testGetSigningKeyJwk(){ - oidc.setX509SigningUrl(null); - oidc.setJwkSigningUrl(jwkUrl.getPath()); - Key key1 = oidc.getSigningKey(); - try { - assertEquals(key1, KeyFetcher.retrieveJwkKey()); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testGetSigningKeyX509(){ - oidc.setX509SigningUrl(x509Url.getPath()); - oidc.setJwkSigningUrl(null); - Key key2 = oidc.getSigningKey(); - try { - assertEquals(key2, KeyFetcher.retrieveX509Key()); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testGetSigningKeyNone(){ - oidc.setX509SigningUrl(null); - oidc.setJwkSigningUrl(null); - Key key3 = oidc.getSigningKey(); - assertEquals(key3, null); - } - - @Test - public void testGetEncryptionKeyBoth(){ - oidc.setX509EncryptUrl(x509EncryptedUrl.getPath()); - oidc.setJwkEncryptUrl(jwkEncryptedUrl.getPath()); - Key key = oidc.getEncryptionKey(); - try { - assertEquals(key, KeyFetcher.retrieveX509Key()); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testGetEncryptionKeyJwk(){ - oidc.setX509EncryptUrl(null); - oidc.setJwkEncryptUrl(jwkEncryptedUrl.getPath()); - Key key1 = oidc.getEncryptionKey(); - try { - assertEquals(key1, KeyFetcher.retrieveJwkKey()); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testGetEncryptionKeyX509(){ - oidc.setX509EncryptUrl(x509EncryptedUrl.getPath()); - oidc.setJwkEncryptUrl(null); - Key key2 = oidc.getEncryptionKey(); - try { - assertEquals(key2, KeyFetcher.retrieveX509Key()); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Test - public void testGetEncryptionKeyNone(){ - oidc.setX509EncryptUrl(null); - oidc.setJwkEncryptUrl(null); - Key key3 = oidc.getEncryptionKey(); - assertEquals(key3, null); - } -} diff --git a/openid-connect-client/src/test/resources/test-context.xml b/openid-connect-client/src/test/resources/test-context.xml index d9a6435a6..c849de679 100644 --- a/openid-connect-client/src/test/resources/test-context.xml +++ b/openid-connect-client/src/test/resources/test-context.xml @@ -36,11 +36,5 @@ - - - - - - \ No newline at end of file diff --git a/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java b/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java index dc1c795f7..c09d9c1b4 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java +++ b/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java @@ -1,12 +1,9 @@ package org.mitre.jwk.model; import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.Key; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; -import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPublicKeySpec; diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java index 215537298..37cf16dfd 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/model/JwtHeader.java @@ -15,13 +15,10 @@ ******************************************************************************/ package org.mitre.jwt.model; -import java.util.HashMap; -import java.util.Map; import java.util.Map.Entry; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; public class JwtHeader extends ClaimSet { diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java index abb8a2a54..4e545f63d 100644 --- a/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationService.java @@ -1,14 +1,8 @@ package org.mitre.jwt.signer.service.impl; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; -import java.security.cert.CertificateException; import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -19,8 +13,6 @@ import org.mitre.jwt.signer.JwtSigner; import org.mitre.jwt.signer.impl.HmacSigner; import org.mitre.jwt.signer.impl.PlaintextSigner; import org.mitre.jwt.signer.impl.RsaSigner; -import org.mitre.key.fetch.KeyFetcher; -import org.mitre.util.Utility; public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAndValidationService{ @@ -31,8 +23,6 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd private String clientSecret; - private Key signingKey; - private Map map; private PublicKey publicKey; @@ -44,43 +34,6 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd setJwkSigningUrl(jwkSigningUrl); setClientSecret(clientSecret); } - - public Key getSigningKey() { - if(signingKey == null){ - if(x509SigningUrl != null){ - File file = new File(x509SigningUrl); - URL url; - try { - url = file.toURI().toURL(); - signingKey = KeyFetcher.retrieveX509Key(); - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - else if (jwkSigningUrl != null){ - File file = new File(jwkSigningUrl); - URL url; - try { - url = file.toURI().toURL(); - signingKey = KeyFetcher.retrieveJwkKey(); - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - return signingKey; - } public String getSigningX509Url() { return x509SigningUrl; @@ -105,6 +58,14 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } + + public PublicKey getPublicKey() { + return publicKey; + } + + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + } @Override public Map getAllPublicKeys() { @@ -138,7 +99,7 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd JwtSigner signer = getSigner(jwtString); return signer.verify(jwtString); } - catch(Exception e) { + catch(NoSuchAlgorithmException e) { return false; } @@ -150,17 +111,11 @@ public class DynamicJwtSigningAndValidationService extends AbstractJwtSigningAnd JwtSigner signer = null; if(alg.equals("HS256") || alg.equals("HS384") || alg.equals("HS512")){ - signer = new HmacSigner(alg, clientSecret); // TODO: huh? no, we're not signing with the client secret + signer = new HmacSigner(alg, ""); } else if (alg.equals("RS256") || alg.equals("RS384") || alg.equals("RS512")){ PublicKey rsaSigningKey = null; - try { - rsaSigningKey = (PublicKey) getSigningKey(); - } catch (Exception e) { - // FIXME this function call should not throw Exception - e.printStackTrace(); - return null; - } + rsaSigningKey = (PublicKey) getSigners(); signer = new RsaSigner(alg, rsaSigningKey, null); } else if (alg.equals("none")){ signer = new PlaintextSigner(); diff --git a/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java b/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java index bf2eea1ab..2595f80ed 100644 --- a/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java +++ b/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java @@ -9,6 +9,7 @@ import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPublicKeySpec; import java.util.ArrayList; @@ -24,10 +25,7 @@ import org.mitre.openid.connect.client.OIDCServerConfiguration; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.ResponseExtractor; import org.springframework.web.client.RestTemplate; import com.google.gson.JsonArray; @@ -36,22 +34,19 @@ import com.google.gson.JsonParser; public class KeyFetcher { - public static List retrieveJwk(){ - - OIDCServerConfiguration serverConfig = new OIDCServerConfiguration(); + HttpClient httpClient = new DefaultHttpClient(); + HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + RestTemplate restTemplate = new RestTemplate(httpFactory); + + public List retrieveJwk(OIDCServerConfiguration serverConfig){ List keys = new ArrayList(); - HttpClient httpClient = new DefaultHttpClient(); - HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); - RestTemplate restTemplate = new RestTemplate(httpFactory); - MultiValueMap form = new LinkedMultiValueMap(); - String jsonString = null; try { - jsonString = restTemplate.postForObject( - serverConfig.getTokenEndpointURI(), form, String.class); + jsonString = restTemplate.getForObject( + serverConfig.getTokenEndpointURI(), String.class); } catch (HttpClientErrorException httpClientErrorException) { throw new AuthenticationServiceException( @@ -61,17 +56,15 @@ public class KeyFetcher { JsonObject json = (JsonObject) new JsonParser().parse(jsonString); JsonArray getArray = json.getAsJsonArray("jwk"); - for(int i = 0; i < getArray.size(); i++){ + for (int i = 0; i < getArray.size(); i++){ JsonObject object = getArray.get(i).getAsJsonObject(); String algorithm = object.get("alg").getAsString(); - if(algorithm.equals("RSA")){ + if (algorithm.equals("RSA")){ Rsa rsa = new Rsa(object); keys.add(rsa); - } - - else{ + } else { EC ec = new EC(object); keys.add(ec); } @@ -79,20 +72,13 @@ public class KeyFetcher { return keys; } - public static Key retrieveX509Key() throws CertificateException { + public Key retrieveX509Key(OIDCServerConfiguration serverConfig) throws CertificateException { - OIDCServerConfiguration serverConfig = new OIDCServerConfiguration(); - - HttpClient httpClient = new DefaultHttpClient(); - HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); - RestTemplate restTemplate = new RestTemplate(httpFactory); - MultiValueMap form = new LinkedMultiValueMap(); - - InputStream jsonStream = null; + InputStream x509Stream = null; try { - jsonStream = restTemplate.postForObject( - serverConfig.getTokenEndpointURI(), form, InputStream.class); + x509Stream = restTemplate.getForObject( + serverConfig.getTokenEndpointURI(), InputStream.class); } catch (HttpClientErrorException httpClientErrorException) { throw new AuthenticationServiceException( @@ -100,33 +86,26 @@ public class KeyFetcher { } CertificateFactory factory = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) factory.generateCertificate(jsonStream); + X509Certificate cert = (X509Certificate) factory.generateCertificate(x509Stream); Key key = cert.getPublicKey(); return key; } - public static Key retrieveJwkKey() throws NoSuchAlgorithmException, InvalidKeySpecException{ + public Key retrieveJwkKey(OIDCServerConfiguration serverConfig) throws NoSuchAlgorithmException, InvalidKeySpecException{ - OIDCServerConfiguration serverConfig = new OIDCServerConfiguration(); - - HttpClient httpClient = new DefaultHttpClient(); - HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); - RestTemplate restTemplate = new RestTemplate(httpFactory); - MultiValueMap form = new LinkedMultiValueMap(); - - String jsonString = null; + String jwkString = null; try { - jsonString = restTemplate.postForObject( - serverConfig.getTokenEndpointURI(), form, String.class); + jwkString = restTemplate.getForObject( + serverConfig.getTokenEndpointURI(), String.class); } catch (HttpClientErrorException httpClientErrorException) { throw new AuthenticationServiceException( "Unable to obtain Access Token."); } - JsonObject json = (JsonObject) new JsonParser().parse(jsonString); + JsonObject json = (JsonObject) new JsonParser().parse(jwkString); JsonArray getArray = json.getAsJsonArray("jwk"); JsonObject object = getArray.get(0).getAsJsonObject(); @@ -137,7 +116,7 @@ public class KeyFetcher { RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); KeyFactory factory = KeyFactory.getInstance("RSA"); - PublicKey pub = factory.generatePublic(spec); + RSAPublicKey pub = (RSAPublicKey) factory.generatePublic(spec); return pub; } diff --git a/openid-connect-common/src/main/java/org/mitre/openid/connect/service/ClientUserDetailsService.java b/openid-connect-common/src/main/java/org/mitre/openid/connect/service/ClientUserDetailsService.java index dcb4a9c1f..45b41b549 100644 --- a/openid-connect-common/src/main/java/org/mitre/openid/connect/service/ClientUserDetailsService.java +++ b/openid-connect-common/src/main/java/org/mitre/openid/connect/service/ClientUserDetailsService.java @@ -18,7 +18,6 @@ package org.mitre.openid.connect.service; import java.util.ArrayList; import java.util.List; -import org.mitre.oauth2.model.ClientDetailsEntity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; diff --git a/openid-connect-common/src/main/java/org/mitre/util/Utility.java b/openid-connect-common/src/main/java/org/mitre/util/Utility.java index 60ed60d08..5a020b002 100644 --- a/openid-connect-common/src/main/java/org/mitre/util/Utility.java +++ b/openid-connect-common/src/main/java/org/mitre/util/Utility.java @@ -15,34 +15,8 @@ ******************************************************************************/ package org.mitre.util; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.math.BigInteger; -import java.net.URL; -import java.security.Key; -import java.security.KeyFactory; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.RSAPublicKeySpec; -import java.security.PublicKey; -import java.util.ArrayList; -import java.util.List; - import javax.servlet.http.HttpServletRequest; -import org.apache.commons.codec.binary.Base64; -import org.mitre.jwk.model.AbstractJwk; -import org.mitre.jwk.model.EC; -import org.mitre.jwk.model.Jwk; -import org.mitre.jwk.model.Rsa; - -import com.google.gson.JsonArray; -import com.google.gson.JsonIOException; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; - /** * A collection of utility methods. * diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java deleted file mode 100644 index ddac6e860..000000000 --- a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/HmacSignerTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.mitre.jwt.signer.impl; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; - -import junit.framework.TestCase; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mitre.jwt.model.Jwt; -import org.mitre.jwt.model.JwtClaims; -import org.mitre.jwt.model.JwtHeader; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -public class HmacSignerTest extends TestCase { - - URL claimsUrl = this.getClass().getResource("/jwt/claims"); - URL hs256Url = this.getClass().getResource("/jwt/hs256"); - URL hs384Url = this.getClass().getResource("/jwt/hs384"); - URL hs512Url = this.getClass().getResource("/jwt/hs512"); - Jwt jwt = null; - JwtClaims claims = null; - JwtHeader header = null; - - /** - * @throws java.lang.Exception - */ - @Before - public void setUp(URL url) throws Exception { - JsonParser parser = new JsonParser(); - JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); - JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); - claims = new JwtClaims(claimsObject); - header = new JwtHeader(headerObject); - jwt = new Jwt(header, claims, null); - } - - /** - * @throws java.lang.Exception - */ - @After - public void tearDown() throws Exception { - } - - @Test - public void testHmacSigner256() throws Exception { - setUp(hs256Url); - HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); - jwt = hmac.sign(jwt); - assertEquals(hmac.verify(jwt.toString()), true); - } - - @Test - public void testHmacSigner384() throws Exception { - setUp(hs384Url); - HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); - jwt = hmac.sign(jwt); - assertEquals(hmac.verify(jwt.toString()), true); - } - - @Test - public void testHmacSigner512() throws Exception { - setUp(hs512Url); - HmacSigner hmac = new HmacSigner(header.getAlgorithm(), "secret"); - jwt = hmac.sign(jwt); - assertEquals(hmac.verify(jwt.toString()), true); - } - -} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java deleted file mode 100644 index cd74c577a..000000000 --- a/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/RsaSignerTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.mitre.jwt.signer.impl; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PrivateKey; -import java.security.PublicKey; - -import junit.framework.TestCase; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mitre.jwt.model.Jwt; -import org.mitre.jwt.model.JwtClaims; -import org.mitre.jwt.model.JwtHeader; -import org.mitre.jwt.signer.JwsAlgorithm; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -public class RsaSignerTest extends TestCase { - - - URL claimsUrl = this.getClass().getResource("/jwt/claims"); - URL rs256Url = this.getClass().getResource("/jwt/rs256"); - URL rs384Url = this.getClass().getResource("/jwt/rs384"); - URL rs512Url = this.getClass().getResource("/jwt/rs512"); - Jwt jwt = null; - JwtClaims claims = null; - JwtHeader header = null; - KeyPairGenerator keyGen; - KeyPair keyPair; - PublicKey publicKey; - PrivateKey privateKey; - - /** - * @throws java.lang.Exception - */ - @Before - public void setUp(URL url) throws Exception { - JsonParser parser = new JsonParser(); - JsonObject claimsObject = parser.parse(new BufferedReader(new InputStreamReader(claimsUrl.openStream()))).getAsJsonObject(); - JsonObject headerObject = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); - claims = new JwtClaims(claimsObject); - header = new JwtHeader(headerObject); - jwt = new Jwt(header, claims, null); - } - - /** - * @throws java.lang.Exception - */ - @After - public void tearDown() throws Exception { - } - - @Test - public void testRsaSigner256() throws Exception { - setUp(rs256Url); - keyGen = KeyPairGenerator.getInstance("RSA"); - keyPair = keyGen.generateKeyPair(); - publicKey = keyPair.getPublic(); - privateKey = keyPair.getPrivate(); - RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS256.toString(), publicKey, privateKey); - jwt = rsa.sign(jwt); - assertEquals(rsa.verify(jwt.toString()), true); - - } - - @Test - public void testRsaSigner384() throws Exception{ - setUp(rs384Url); - keyGen = KeyPairGenerator.getInstance("RSA"); - keyPair = keyGen.generateKeyPair(); - publicKey = keyPair.getPublic(); - privateKey = keyPair.getPrivate(); - RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS384.toString(), publicKey, privateKey); - jwt = rsa.sign(jwt); - assertEquals(rsa.verify(jwt.toString()), true); - - } - - @Test - public void testRsaSigner512() throws Exception{ - setUp(rs512Url); - keyGen = KeyPairGenerator.getInstance("RSA"); - keyPair = keyGen.generateKeyPair(); - publicKey = keyPair.getPublic(); - privateKey = keyPair.getPrivate(); - RsaSigner rsa = new RsaSigner(JwsAlgorithm.RS512.toString(), publicKey, privateKey); - jwt = rsa.sign(jwt); - assertEquals(rsa.verify(jwt.toString()), true); - - } - - -} diff --git a/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java b/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java index d65298590..82b8b4fcb 100644 --- a/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/service/impl/DynamicJwtSigningAndValidationServiceTest.java @@ -2,24 +2,16 @@ package org.mitre.jwt.signer.service.impl; import static org.junit.Assert.assertEquals; -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.net.URL; import java.security.Key; -import junit.framework.TestCase; - import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mitre.jwt.signer.JwtSigner; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:test-context.xml" }) public class DynamicJwtSigningAndValidationServiceTest { @@ -35,14 +27,14 @@ public class DynamicJwtSigningAndValidationServiceTest { * @throws java.lang.Exception */ @Before - public void setUp() throws Exception { + public void setUp(){ } /** * @throws java.lang.Exception */ @After - public void tearDown() throws Exception { + public void tearDown(){ } /** @@ -50,7 +42,7 @@ public class DynamicJwtSigningAndValidationServiceTest { * @throws Exception */ @Test - public void testGetSigner() throws Exception { + public void testGetSigner(){ //create key, sign it, for both x509 and jwk. /* jsvs.setX509SigningUrl(x509Url.getPath()); x509Key = jsvs.getSigningKey(); diff --git a/openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java b/openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java deleted file mode 100644 index cf3f87a8e..000000000 --- a/openid-connect-common/src/test/java/org/mitre/key/fetch/KeyFetcherTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.mitre.key.fetch; - -import static org.junit.Assert.assertEquals; - - -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; -import java.util.List; - -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.easymock.EasyMock; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mitre.jwk.model.EC; -import org.mitre.jwk.model.Jwk; -import org.mitre.jwk.model.Rsa; -import org.mitre.openid.connect.client.OIDCServerConfiguration; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import static org.easymock.EasyMock.createNiceMock; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.verify; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { "classpath:test-context.xml" }) -public class KeyFetcherTest { - - private KeyFetcher keyFetch; - - @Before - public void setUp(){ - keyFetch = EasyMock.createMock(KeyFetcher.class); - } - - @After - public void tearDown(){ - } - - @Test - public void retrieveJwkTest(){ - //EasyMock.expect(keyFetch.retrieveJwk()).andReturn(Rsa(new JsonObject(object))).once(); - } - - @Test - public void retrieveX509Key(){ - - } - - @Test - public void retriveJwkKey(){ - - } - -} diff --git a/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java b/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java deleted file mode 100644 index 66ebc7cd6..000000000 --- a/openid-connect-common/src/test/java/org/mitre/util/UtilityTest.java +++ /dev/null @@ -1,213 +0,0 @@ -/** - * - */ -package org.mitre.util; - -import static org.junit.Assert.assertEquals; - -import java.security.Key; -import java.security.KeyFactory; -import java.security.PublicKey; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.interfaces.ECKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.RSAPublicKeySpec; -import java.util.List; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.math.BigInteger; -import java.net.URL; - -import junit.framework.TestCase; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mitre.jwk.model.Jwk; -import org.mitre.jwk.model.Rsa; -import org.mitre.jwk.model.EC; -import org.mitre.key.fetch.KeyFetcher; -import org.mitre.util.Utility; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import org.apache.commons.codec.binary.*; -import org.bouncycastle.jce.ECNamedCurveTable; -import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.jce.provider.JCEECPublicKey; - -/** - * @author DERRYBERRY - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { "classpath:test-context.xml" }) -public class UtilityTest { - - URL url = this.getClass().getResource("/jwk/jwkSuccess"); - URL certUrl = this.getClass().getResource("/x509/x509Cert"); - URL rsaUrl = this.getClass().getResource("/jwk/rsaOnly"); - - /** - * @throws java.lang.Exception - */ - @Before - public void setUp() throws Exception { - } - - /** - * @throws java.lang.Exception - */ - @After - public void tearDown() throws Exception { - } - - /** - * Test method for {@link org.mitre.util.Utility#retrieveJwk(java.lang.String)}. - * @throws Exception - */ - @Test - public void testRetrieveJwk() throws Exception { - - JsonParser parser = new JsonParser(); - JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); - JsonArray getArray = json.getAsJsonArray("jwk"); - - List list = KeyFetcher.retrieveJwk(); - - for(int i = 0; i < list.size(); i++){ - - Jwk jwk = list.get(i); - JsonObject object = getArray.get(i).getAsJsonObject(); - - assertEquals(object.get("alg").getAsString(), jwk.getAlg()); - if(object.get("kid") != null){ - assertEquals(object.get("kid").getAsString(), jwk.getKid()); - } - if(object.get("use") != null){ - assertEquals(object.get("use").getAsString(), jwk.getUse()); - } - - if(jwk instanceof Rsa){ - assertEquals(object.get("mod").getAsString(), ((Rsa) jwk).getMod()); - assertEquals(object.get("exp").getAsString(), ((Rsa) jwk).getExp()); - } - else { - assertEquals(object.get("crv").getAsString(), ((EC) jwk).getCrv()); - assertEquals(object.get("x").getAsString(), ((EC) jwk).getX()); - assertEquals(object.get("y").getAsString(), ((EC) jwk).getY()); - } - } - } - - @Test - public void testMakeRsa() throws Exception{ - - JsonParser parser = new JsonParser(); - JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); - JsonArray getArray = json.getAsJsonArray("jwk"); - - List list = KeyFetcher.retrieveJwk(); - - for(int i = 0; i < list.size(); i++){ - Jwk jwk = list.get(i); - JsonObject object = getArray.get(i).getAsJsonObject(); - - if(jwk instanceof Rsa){ - - RSAPublicKey key = ((RSAPublicKey) ((Rsa) jwk).getKey()); - - byte[] mod = Base64.decodeBase64(object.get("mod").getAsString()); - BigInteger modInt = new BigInteger(mod); - assertEquals(modInt, key.getModulus()); - - byte[] exp = Base64.decodeBase64(object.get("exp").getAsString()); - BigInteger expInt = new BigInteger(exp); - assertEquals(expInt, key.getPublicExponent()); - } - } - } - - @Test - public void testRetriveX509Key() throws Exception { - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - X509Certificate x509 = (X509Certificate) factory.generateCertificate(certUrl.openStream()); - Key key = KeyFetcher.retrieveX509Key(); - assertEquals(x509.getPublicKey(), key); - assertEquals("RSA", key.getAlgorithm()); - assertEquals("X.509", key.getFormat()); - } - - public void testRetriveJwkKey() throws Exception { - Key key = KeyFetcher.retrieveJwkKey(); - - JsonParser parser = new JsonParser(); - JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(rsaUrl.openStream()))).getAsJsonObject(); - JsonArray getArray = json.getAsJsonArray("jwk"); - JsonObject object = getArray.get(0).getAsJsonObject(); - - byte[] modulusByte = Base64.decodeBase64(object.get("mod").getAsString()); - BigInteger modulus = new BigInteger(modulusByte); - byte[] exponentByte = Base64.decodeBase64(object.get("exp").getAsString()); - BigInteger exponent = new BigInteger(exponentByte); - - RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); - KeyFactory factory = KeyFactory.getInstance("RSA"); - PublicKey pub = factory.generatePublic(spec); - - assertEquals(pub, key); - } - - //@Test - //public void testMakeEC() throws Exception{ - - /*JsonParser parser = new JsonParser(); - JsonObject json = parser.parse(new BufferedReader(new InputStreamReader(url.openStream()))).getAsJsonObject(); - JsonArray getArray = json.getAsJsonArray("jwk"); - - List list = Utility.retrieveJwk(url); - - for(int i = 0; i < list.size(); i++){ - Jwk jwk = list.get(i); - JsonObject object = getArray.get(i).getAsJsonObject(); - - if(jwk instanceof EC){ - - ECPublicKey key = ((ECPublicKey) ((EC) jwk).getKey()); - - byte[] xArray = Base64.decodeBase64(object.get("x").getAsString()); - BigInteger xInt = new BigInteger(xArray); - byte[] yArray = Base64.decodeBase64(object.get("y").getAsString()); - BigInteger yInt = new BigInteger(yArray); - - String curveName = object.get("crv").getAsString(); - ECNamedCurveParameterSpec curveSpec = ECNamedCurveTable.getParameterSpec(curveName); - ECCurve crv = curveSpec.getCurve(); - BigInteger a = crv.getA().toBigInteger(); - BigInteger b = crv.getB().toBigInteger(); - int fieldSize = crv.getFieldSize(); - BigInteger orderOfGen = curveSpec.getH(); - int cofactor = Math.abs(curveSpec.getN().intValue()); - - assertEquals(a, key.getParams().getCurve().getA()); - assertEquals(b, key.getParams().getCurve().getB()); - assertEquals(fieldSize, key.getParams().getCurve().getField()); - assertEquals(orderOfGen, key.getParams().getOrder()); - assertEquals(cofactor, key.getParams().getCofactor()); - assertEquals(xInt, key.getW().getAffineX()); - assertEquals(yInt, key.getW().getAffineY()); - } - }*/ - //fail("method not implemented"); - //} - - -} \ No newline at end of file