refactored previously commented out unit tests, cleaned up code, service now returns only unique publickeys

pull/59/head
nemonik 2012-02-15 17:35:18 -05:00
parent 5e32e9605b
commit 513145f16f
7 changed files with 148 additions and 149 deletions

View File

@ -4,6 +4,7 @@ import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.Signature; import java.security.Signature;
import java.security.SignatureException; import java.security.SignatureException;
@ -83,19 +84,14 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
private static Log logger = LogFactory.getLog(RsaSigner.class); private static Log logger = LogFactory.getLog(RsaSigner.class);
public static final String PROVIDER = "BC";
public static final String DEFAULT_PASSWORD = "changeit"; public static final String DEFAULT_PASSWORD = "changeit";
// static {
// Security.addProvider(new BouncyCastleProvider());
// }
private KeyStore keystore; private KeyStore keystore;
private String alias; private String alias;
private String password; private String password;
private RSAPrivateKey privateKey; private PrivateKey privateKey;
private RSAPublicKey publicKey; private PublicKey publicKey;
private Signature signer; private Signature signer;
/** /**
@ -113,7 +109,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
public RsaSigner(String algorithmName, KeyStore keystore, String alias) { public RsaSigner(String algorithmName, KeyStore keystore, String alias) {
this(algorithmName, keystore, alias, DEFAULT_PASSWORD); this(algorithmName, keystore, alias, DEFAULT_PASSWORD);
} }
/** /**
* @param algorithmName * @param algorithmName
* @param keystore * @param keystore
@ -136,14 +132,23 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
} }
} }
/**
* Default constructor
*/
public RsaSigner(String algorithmName, RSAPublicKey publicKey, RSAPrivateKey privateKey) {
super(algorithmName);
this.publicKey = publicKey;
this.privateKey = privateKey;
}
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
KeyPair keyPair = keystore.getKeyPairForAlias(alias, password); KeyPair keyPair = keystore.getKeyPairForAlias(alias, password);
publicKey = ((RSAPublicKey) keyPair.getPublic()); publicKey = keyPair.getPublic();
privateKey = (RSAPrivateKey) keyPair.getPrivate(); privateKey = keyPair.getPrivate();
logger.debug("RSA Signer ready for business"); logger.debug( Algorithm.getByName(getAlgorithm()).getStandardName() + " RSA Signer ready for business");
} }
@ -152,15 +157,17 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
*/ */
@Override @Override
protected String generateSignature(String signatureBase) { protected String generateSignature(String signatureBase) {
try { try {
signer.initSign(privateKey); signer.initSign(privateKey);
signer.update(signatureBase.getBytes("UTF-8")); signer.update(signatureBase.getBytes("UTF-8"));
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
System.out.println("boooom 1");
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
System.out.println("boooom 2");
e.printStackTrace(); e.printStackTrace();
} }
@ -176,7 +183,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
return sig; return sig;
} }
@ -192,6 +199,10 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
return password; return password;
} }
public PrivateKey getPrivateKey() {
return privateKey;
}
public PublicKey getPublicKey() { public PublicKey getPublicKey() {
return publicKey; return publicKey;
} }
@ -208,6 +219,10 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
this.password = password; this.password = password;
} }
public void setPrivateKey(RSAPrivateKey privateKey) {
this.privateKey = privateKey;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@ -220,6 +235,9 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
+ ", publicKey=" + publicKey + ", signer=" + signer + "]"; + ", publicKey=" + publicKey + ", signer=" + signer + "]";
} }
/* (non-Javadoc)
* @see org.mitre.jwt.signer.AbstractJwtSigner#verify(java.lang.String)
*/
@Override @Override
public boolean verify(String jwtString) { public boolean verify(String jwtString) {
@ -251,12 +269,4 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
return true; return true;
} }
public RSAPrivateKey getPrivateKey() {
return privateKey;
}
public void setPrivateKey(RSAPrivateKey privateKey) {
this.privateKey = privateKey;
}
} }

View File

@ -1,8 +1,11 @@
package org.mitre.jwt.signer.service.impl; package org.mitre.jwt.signer.service.impl;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -23,31 +26,35 @@ public class JwtSigningAndValidationServiceDefault implements
/** /**
* default constructor * default constructor
*/ */
public JwtSigningAndValidationServiceDefault() { public JwtSigningAndValidationServiceDefault() {
} }
/** /**
* Create JwtSigningAndValidationServiceDefault * Create JwtSigningAndValidationServiceDefault
* *
* @param signer List of JwtSigners to associate with this service * @param signer
* List of JwtSigners to associate with this service
*/ */
public JwtSigningAndValidationServiceDefault(List<? extends JwtSigner> signer) { public JwtSigningAndValidationServiceDefault(
List<? extends JwtSigner> signer) {
setSigners(signer); setSigners(signer);
} }
/*
/* (non-Javadoc) * (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() *
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/ */
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
// used for debugging... // used for debugging...
if (!signers.isEmpty()) { if (!signers.isEmpty()) {
logger.info(this.toString()); logger.info(this.toString());
} }
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JwtSigningAndValidationServiceDefault is open for business"); logger.info("JwtSigningAndValidationServiceDefault is open for business");
} }
/* /*
@ -59,30 +66,31 @@ public class JwtSigningAndValidationServiceDefault implements
*/ */
@Override @Override
public List<PublicKey> getAllPublicKeys() { public List<PublicKey> getAllPublicKeys() {
// TODO Iterate through the signers, gather up, and return all the PublicKeys
Map<String, PublicKey> map = new HashMap<String, PublicKey>();
List<PublicKey> publicKeys = new ArrayList<PublicKey>();
PublicKey publicKey; PublicKey publicKey;
for (JwtSigner signer: signers) { for (JwtSigner signer : signers) {
if (signer instanceof RsaSigner) { if (signer instanceof RsaSigner) {
publicKey = ((RsaSigner) signer).getPublicKey(); publicKey = ((RsaSigner) signer).getPublicKey();
if (publicKey != null) if (publicKey != null)
publicKeys.add(((RsaSigner) signer).getPublicKey()); map.put(((RSAPublicKey) publicKey).getModulus()
.toString(16).toUpperCase()
+ ((RSAPublicKey) publicKey).getPublicExponent()
.toString(16).toUpperCase(), publicKey);
} else if (signer instanceof EcdsaSigner) { } else if (signer instanceof EcdsaSigner) {
publicKey = ((EcdsaSigner) signer).getPublicKey(); // TODO
if (publicKey != null)
publicKeys.add(publicKey);
} }
} }
return publicKeys; return new ArrayList<PublicKey>(map.values());
} }
/** /**
@ -106,7 +114,7 @@ public class JwtSigningAndValidationServiceDefault implements
// TODO Auto-generated method stub // TODO Auto-generated method stub
return false; return false;
} }
/** /**
* Set the JwtSigners associated with this service * Set the JwtSigners associated with this service
* *
@ -132,14 +140,14 @@ public class JwtSigningAndValidationServiceDefault implements
*/ */
@Override @Override
public boolean validateIssuedJwt(Jwt jwt) { public boolean validateIssuedJwt(Jwt jwt) {
// TODO Verify this is correct... // TODO Verify this is correct...
for (JwtSigner signer: signers) { for (JwtSigner signer : signers) {
if (signer.verify(jwt.toString())) if (signer.verify(jwt.toString()))
return true; return true;
} }
return false; return false;
} }
@ -153,11 +161,11 @@ public class JwtSigningAndValidationServiceDefault implements
@Override @Override
public boolean validateSignature(String jwtString) { public boolean validateSignature(String jwtString) {
for (JwtSigner signer: signers) { for (JwtSigner signer : signers) {
if (signer.verify(jwtString)) if (signer.verify(jwtString))
return true; return true;
} }
return false; return false;
} }
} }

View File

@ -1,8 +1,5 @@
package org.mitre.jwt.signer.service.impl; package org.mitre.jwt.signer.service.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.Key; import java.security.Key;
@ -10,7 +7,6 @@ import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.Provider; import java.security.Provider;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -107,8 +103,8 @@ public class KeyStore implements InitializingBean {
// Get public key // Get public key
PublicKey publicKey = cert.getPublicKey(); PublicKey publicKey = cert.getPublicKey();
return new KeyPair(publicKey, (RSAPrivateKey) key); return new KeyPair(publicKey, (PrivateKey) key);
} }
return null; return null;

View File

@ -1,6 +1,8 @@
package org.mitre.jwt; package org.mitre.jwt;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -15,7 +17,6 @@ import org.mitre.jwt.signer.impl.PlaintextSigner;
import org.mitre.jwt.signer.impl.RsaSigner; import org.mitre.jwt.signer.impl.RsaSigner;
import org.mitre.jwt.signer.service.impl.KeyStore; import org.mitre.jwt.signer.service.impl.KeyStore;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ -25,35 +26,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class JwtTest { public class JwtTest {
@Autowired @Autowired
@Qualifier("testKeystore")
KeyStore keystore; KeyStore keystore;
@Test
public void testToStringPlaintext() {
Jwt jwt = new Jwt();
jwt.getHeader().setAlgorithm("none");
jwt.getClaims().setExpiration(new Date(1300819380L * 1000L));
jwt.getClaims().setIssuer("joe");
jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE);
// sign it with a blank signature
JwtSigner signer = new PlaintextSigner();
signer.sign(jwt);
/*
* Expected string based on the following structures, serialized exactly as follows and base64 encoded:
*
* header: {"alg":"none"}
* claims: {"exp":1300819380,"iss":"joe","http://example.com/is_root":true}
*/
String expected = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.";
String actual = jwt.toString();
assertThat(actual, equalTo(expected));
}
@Test @Test
public void testGenerateHmacSignature() { public void testGenerateHmacSignature() {
Jwt jwt = new Jwt(); Jwt jwt = new Jwt();
@ -94,40 +68,70 @@ public class JwtTest {
assertThat(jwt.getSignature(), equalTo(signature)); assertThat(jwt.getSignature(), equalTo(signature));
} }
/** /**
* @throws Exception * @throws Exception
*/ */
// @Test /**
// public void testGenerateRsaSignature() throws Exception { * @throws Exception
// */
//// java.security.KeyStore ks = KeyStore.generateRsaKeyPair(keystore @Test
//// .getLocation().getFile().getPath(), "OpenID Connect Server", public void testGenerateRsaSignature() throws Exception {
//// "twentyYears", KeyStore.PASSWORD, KeyStore.PASSWORD, 30, 365*20);
//// Jwt jwt = new Jwt();
//// keystore.setKeystore(ks); jwt.getHeader().setType("JWT");
// jwt.getHeader().setAlgorithm("RS256");
// Jwt jwt = new Jwt(); jwt.getClaims().setExpiration(new Date(1300819380L * 1000L));
// jwt.getHeader().setType("JWT"); jwt.getClaims().setIssuer("joe");
// jwt.getHeader().setAlgorithm("RS256"); jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE);
// jwt.getClaims().setExpiration(new Date(1300819380L * 1000L));
// jwt.getClaims().setIssuer("joe"); JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.RS256.toString(), keystore, "test", "changeit");
// jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE); ((RsaSigner)signer).afterPropertiesSet();
//
// JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.DEFAULT, keystore, "twentyYears"); signer.sign(jwt);
// ((RsaSigner) signer).afterPropertiesSet();
// assertThat(jwt.getSignature(), not(nullValue()));
// signer.sign(jwt); }
//
// String signature = "TW0nOd_vr1rnV7yIS-lIV2-00V_zJMWxzOc3Z7k3gvMO2aIjIGjZ9nByZMI0iL5komMxYXPl_RCkbd9OKiPkk4iK5CDj7Mawbzu95LgEOOqdXO1f7-IqX9dIvJhVXXInLD3RsGvavyheIqNeFEVidLrJo30tBchB_niljEW7VeX8nSZfiCOdbOTW3hu0ycnon7wFpejb-cRP_S0iqGxCgbYXJzqPT192EHmRy_wmFxxIy9Lc84uqNkAZSIn1jVIeAemm22RoWbq0xLVLTRyiZoxJTUzac_VteiSPRNFlUQuOdxqNf0Hxqh_wVfX1mfXUzv0D8vHJVy6aIqTISmn-qg"; @Test
// String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.TW0nOd_vr1rnV7yIS-lIV2-00V_zJMWxzOc3Z7k3gvMO2aIjIGjZ9nByZMI0iL5komMxYXPl_RCkbd9OKiPkk4iK5CDj7Mawbzu95LgEOOqdXO1f7-IqX9dIvJhVXXInLD3RsGvavyheIqNeFEVidLrJo30tBchB_niljEW7VeX8nSZfiCOdbOTW3hu0ycnon7wFpejb-cRP_S0iqGxCgbYXJzqPT192EHmRy_wmFxxIy9Lc84uqNkAZSIn1jVIeAemm22RoWbq0xLVLTRyiZoxJTUzac_VteiSPRNFlUQuOdxqNf0Hxqh_wVfX1mfXUzv0D8vHJVy6aIqTISmn-qg"; public void testParse() {
// String source = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.";
// String actual = jwt.toString();
//
// assertThat(actual, equalTo(expected)); Jwt jwt = Jwt.parse(source);
// assertThat(jwt.getSignature(), equalTo(signature));
// assertThat(jwt.getHeader().getAlgorithm(), equalTo(PlaintextSigner.PLAINTEXT));
// } assertThat(jwt.getClaims().getIssuer(), equalTo("joe"));
assertThat(jwt.getClaims().getExpiration(), equalTo(new Date(1300819380L * 1000L)));
assertThat((Boolean)jwt.getClaims().getClaim("http://example.com/is_root"), equalTo(Boolean.TRUE));
}
@Test
public void testToStringPlaintext() {
Jwt jwt = new Jwt();
jwt.getHeader().setAlgorithm("none");
jwt.getClaims().setExpiration(new Date(1300819380L * 1000L));
jwt.getClaims().setIssuer("joe");
jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE);
// sign it with a blank signature
JwtSigner signer = new PlaintextSigner();
signer.sign(jwt);
/*
* Expected string based on the following structures, serialized exactly as follows and base64 encoded:
*
* header: {"alg":"none"}
* claims: {"exp":1300819380,"iss":"joe","http://example.com/is_root":true}
*/
String expected = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.";
String actual = jwt.toString();
assertThat(actual, equalTo(expected));
}
@Test @Test
public void testValidateHmacSignature() { public void testValidateHmacSignature() {
@ -158,19 +162,5 @@ public class JwtTest {
assertThat(valid, equalTo(Boolean.TRUE)); assertThat(valid, equalTo(Boolean.TRUE));
} }
@Test
public void testParse() {
String source = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.";
Jwt jwt = Jwt.parse(source);
assertThat(jwt.getHeader().getAlgorithm(), equalTo(PlaintextSigner.PLAINTEXT));
assertThat(jwt.getClaims().getIssuer(), equalTo("joe"));
assertThat(jwt.getClaims().getExpiration(), equalTo(new Date(1300819380L * 1000L)));
assertThat((Boolean)jwt.getClaims().getClaim("http://example.com/is_root"), equalTo(Boolean.TRUE));
}
} }

View File

@ -25,7 +25,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SuppressWarnings({ "restriction", "deprecation" }) // I know... @SuppressWarnings("deprecation")
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { @ContextConfiguration(locations = {
"classpath:test-context.xml" }) "classpath:test-context.xml" })
@ -36,7 +36,7 @@ public class KeyStoreTest {
KeyStore keystore; KeyStore keystore;
static { static {
// Need to create the certificate // Needed to create the certificate
Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastleProvider());
} }
@ -48,7 +48,7 @@ public class KeyStoreTest {
* @param daysNotValidAfter * @param daysNotValidAfter
* @return * @return
*/ */
private X509V3CertificateGenerator createCertificate( private static X509V3CertificateGenerator createCertificate(
String commonName, int daysNotValidBefore, int daysNotValidAfter) { String commonName, int daysNotValidBefore, int daysNotValidAfter) {
// BC sez X509V3CertificateGenerator is deprecated and the docs say to // BC sez X509V3CertificateGenerator is deprecated and the docs say to
// use another, but it seemingly isn't included jar... // use another, but it seemingly isn't included jar...
@ -81,7 +81,7 @@ public class KeyStoreTest {
* @throws GeneralSecurityException * @throws GeneralSecurityException
* @throws IOException * @throws IOException
*/ */
public java.security.KeyStore generateRsaKeyPair( public static java.security.KeyStore generateRsaKeyPair(KeyStore keystore,
String domainName, String alias, String aliasPassword, int daysNotValidBefore, int daysNotValidAfter) String domainName, String alias, String aliasPassword, int daysNotValidBefore, int daysNotValidAfter)
throws GeneralSecurityException, IOException { throws GeneralSecurityException, IOException {
@ -117,13 +117,14 @@ public class KeyStoreTest {
return ks; return ks;
} }
@Test @Test
public void storeKeyPair() throws GeneralSecurityException, IOException { public void storeKeyPair() throws GeneralSecurityException, IOException {
java.security.KeyStore ks = null; java.security.KeyStore ks = null;
try { try {
ks = generateRsaKeyPair("OpenID Connect Server", "storeKeyPair", "changeit", 30, 365); ks = KeyStoreTest.generateRsaKeyPair(keystore, "OpenID Connect Server", "storeKeyPair", "changeit", 30, 365);
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
@ -135,19 +136,13 @@ public class KeyStoreTest {
assertThat(ks, not(nullValue())); assertThat(ks, not(nullValue()));
} }
@Test @Test
public void readKey() throws GeneralSecurityException { public void readKey() throws GeneralSecurityException {
Key key = keystore.getKeystore().getKey("storeKeyPair", Key key = keystore.getKeystore().getKey("storeKeyPair",
KeyStore.PASSWORD.toCharArray()); KeyStore.PASSWORD.toCharArray());
System.out.println("-----BEGIN PRIVATE KEY-----");
System.out
.println(new sun.misc.BASE64Encoder().encode(key.getEncoded()));
System.out.println("-----END PRIVATE KEY-----");
assertThat(key, not(nullValue())); assertThat(key, not(nullValue()));
assertThat(true, not(false));
} }
} }