From 812658d3d32181ab245e41a097bb283761caaf69 Mon Sep 17 00:00:00 2001 From: nemonik Date: Tue, 21 Feb 2012 20:36:00 -0500 Subject: [PATCH] modified testGenerateRsaSignature to be more meaningful, and added testValidateRsaSignature unit test to org.mitre.jwt.JwtTest --- .../main/java/org/mitre/jwt/model/Jwt.java | 4 - .../src/test/java/org/mitre/jwt/JwtTest.java | 240 +++++++++++++----- .../jwt/signer/service/impl/KeyStoreTest.java | 2 +- 3 files changed, 175 insertions(+), 71 deletions(-) diff --git a/server/src/main/java/org/mitre/jwt/model/Jwt.java b/server/src/main/java/org/mitre/jwt/model/Jwt.java index 7d59ca7bd..1db7b3b43 100644 --- a/server/src/main/java/org/mitre/jwt/model/Jwt.java +++ b/server/src/main/java/org/mitre/jwt/model/Jwt.java @@ -1,7 +1,5 @@ package org.mitre.jwt.model; -import java.io.ByteArrayInputStream; -import java.io.InputStreamReader; import java.util.List; import org.apache.commons.codec.binary.Base64; @@ -9,9 +7,7 @@ import org.apache.commons.codec.binary.Base64; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Lists; -import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; public class Jwt { diff --git a/server/src/test/java/org/mitre/jwt/JwtTest.java b/server/src/test/java/org/mitre/jwt/JwtTest.java index c869627b0..ecffcba74 100644 --- a/server/src/test/java/org/mitre/jwt/JwtTest.java +++ b/server/src/test/java/org/mitre/jwt/JwtTest.java @@ -1,13 +1,19 @@ package org.mitre.jwt; 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 java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; import java.util.Date; +import org.bouncycastle.x509.X509V3CertificateGenerator; import org.junit.Test; import org.junit.runner.RunWith; import org.mitre.jwt.model.Jwt; @@ -21,14 +27,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +@SuppressWarnings("deprecation") +// BC sez X509V3CertificateGenerator is deprecated and the docs say to use +// another, but it seemingly isn't included jar... @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { - "classpath:test-context.xml" }) +@ContextConfiguration(locations = { "classpath:test-context.xml" }) public class JwtTest { - + @Autowired KeyStore keystore; - + @Test public void testGenerateHmacSignature() { Jwt jwt = new Jwt(); @@ -40,45 +48,85 @@ public class JwtTest { // sign it byte[] key = null; - try { - key = "secret".getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - JwtSigner signer = new HmacSigner(key); + try { + key = "secret".getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + JwtSigner signer = new HmacSigner(key); signer.sign(jwt); /* - * Expected string based on the following structures, serialized exactly as follows and base64 encoded: + * Expected string based on the following structures, serialized exactly + * as follows and base64 encoded: * - * header: {"typ":"JWT","alg":"HS256"} - * claims: {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} + * header: {"typ":"JWT","alg":"HS256"} claims: + * {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} * * Expected signature: iGBPJj47S5q_HAhSoQqAdcS6A_1CFj3zrLaImqNbt9E - * */ String signature = "p-63Jzz7mgi3H4hvW6MFB7lmPRZjhsL666MYkmpX33Y"; - String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ." + signature; - + String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ." + + signature; + String actual = jwt.toString(); assertThat(actual, equalTo(expected)); assertThat(jwt.getSignature(), equalTo(signature)); - + } - /** - * @throws Exception - */ /** * @throws Exception */ @Test public void testGenerateRsaSignature() throws Exception { + // Hard code the private/public key so as not to depend on it being in + // the keystore... + + RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec( + new BigInteger( + "AD6E684550542947AD95EF9BACDC0AC2C9168C6EB3212D378C23E5539266111DB2E5B4D42B1E47EB4F7A65DB63D9782C72BC365492FD1E5C7B4CD2174C611668C29013FEDE22619B3F58DA3531BB6C02B3266768B7895CBDAFB3F9AC7A7B2F3DB17EF4DCF03BD2575604BDE0A01BB1FB7B0E733AD63E464DB4D7D89626297A214D7CECCD0C50421A322A01E9DCEA23443F6A9339576B31DFA504A133076394562CB57F3FDEDB26F9A82BED2F6D52D6F6BF8286E2497EF0B5C8456F32B4668F5A9F5FCD3781345DDDB749792C37238A53D18FD976C0C9D1F1E211F1A4A9AAE679C45B92D1741EF0D3C3F373232CE7FB93E9BC461E1C508A20B74E7E3361B3C527", + 16), + new BigInteger( + "627CDD67E75B33EA0990A8F64DEED389942A62EB867C23B274B9F9C440D2078C47089D6D136369D21E5B52B688F8797F3C54D7C1A58B6A8F7851C2C90A4DE42CEFB864328B31191ED19582AD4CA5B38BC0F2E12C9D75BB1DD946AA55A1648D0A4ADEDEED0CDBDBF24EDDF87A345225FBBB0114BCE7E78B831B5CAC197068837AB0B3F07157952A05F67A72B9852972C704B6B32A70C3BB3DEB186936B0F7D6ABE012DEB89BC2DBE1F88AE7A28C06C53D1FB2459E58D8ED266E3BFC28266981D2A5F624D36555DD64F410461ADA5D53F448BA5EEBBD4BCEC3AF53285FB394650D7B3BFB06712E081AAD160EED6E83A3EA2D092712C07A6331209F62D27184BFC9", + 16)); + + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + + PrivateKey privateKey = keyFactory.generatePrivate(privateSpec); + + RSAPublicKeySpec publicSpec = new RSAPublicKeySpec( + new BigInteger( + "AD6E684550542947AD95EF9BACDC0AC2C9168C6EB3212D378C23E5539266111DB2E5B4D42B1E47EB4F7A65DB63D9782C72BC365492FD1E5C7B4CD2174C611668C29013FEDE22619B3F58DA3531BB6C02B3266768B7895CBDAFB3F9AC7A7B2F3DB17EF4DCF03BD2575604BDE0A01BB1FB7B0E733AD63E464DB4D7D89626297A214D7CECCD0C50421A322A01E9DCEA23443F6A9339576B31DFA504A133076394562CB57F3FDEDB26F9A82BED2F6D52D6F6BF8286E2497EF0B5C8456F32B4668F5A9F5FCD3781345DDDB749792C37238A53D18FD976C0C9D1F1E211F1A4A9AAE679C45B92D1741EF0D3C3F373232CE7FB93E9BC461E1C508A20B74E7E3361B3C527", + 16), new BigInteger("10001", 16)); + + PublicKey publicKey = keyFactory.generatePublic(publicSpec); + + // BC sez X509V3CertificateGenerator is deprecated and the docs say to + // use another, but it seemingly isn't included jar... + X509V3CertificateGenerator v3CertGen = KeyStoreTest.createCertificate( + "testGenerateRsaSignature", 30, 30); + + v3CertGen.setPublicKey(publicKey); + v3CertGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); + + // BC docs say to use another, but it seemingly isn't included... + X509Certificate certificate = v3CertGen + .generateX509Certificate(privateKey); + + // if exist, overwrite + java.security.KeyStore ks = keystore.getKeystore(); + ks.setKeyEntry("testGenerateRsaSignature", privateKey, + RsaSigner.DEFAULT_PASSWORD.toCharArray(), + new java.security.cert.Certificate[] { certificate }); + + keystore.setKeystore(ks); + Jwt jwt = new Jwt(); jwt.getHeader().setType("JWT"); jwt.getHeader().setAlgorithm("RS256"); @@ -86,33 +134,57 @@ public class JwtTest { jwt.getClaims().setIssuer("joe"); jwt.getClaims().setClaim("http://example.com/is_root", Boolean.TRUE); - KeyStoreTest.generateKeyPair(keystore, - RsaSigner.KEYPAIR_ALGORITHM, 2048, - "SHA256WithRSAEncryption", "OpenID Connect Server", - "rsa", RsaSigner.DEFAULT_PASSWORD, 30, 365); - - JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.RS256.toString(), keystore, "rsa", RsaSigner.DEFAULT_PASSWORD); - ((RsaSigner)signer).afterPropertiesSet(); - + JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.RS256.toString(), + keystore, "testGenerateRsaSignature", + RsaSigner.DEFAULT_PASSWORD); + ((RsaSigner) signer).afterPropertiesSet(); + + /* + * Expected string based on the following structures, serialized exactly + * as follows and base64 encoded: + * + * header: {"typ":"JWT","alg":"HS256"} claims: + * {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} + * + * Expected signature: dSRvtD-ExzGN- + * fRXd1wRZOPo1JFPuqgwvaIKp8jgcyMXJegy6IUjssfUfUcICN5yvh0ggOMWMeWkwQ7 + * -PlXMJWymdhXVI3BOpNt7ZOB2vMFYSOOHNBJUunQoe1lmNxuHQdhxqoHahn3u1cLDXz + * -xx- + * JELduuMmaDWqnTFPodVPl45WBKHaQhlOiFWj3ZClUV2k5p2yBT8TmxekL8gWwgVbQk5yPnYOs + * -PcMjzODc9MZX4yI10ZSCSDciwf- + * rgkQLT7wW4uZCoqTZ7187sCodHd6nw3nghqbtqN05fQ3Yq7ykwaR8pdQBFb2L9l7DhLLuXIREDKIFUHBSUs8OnvXFMg + */ + + String signature = "dSRvtD-ExzGN-fRXd1wRZOPo1JFPuqgwvaIKp8jgcyMXJegy6IUjssfUfUcICN5yvh0ggOMWMeWkwQ7-PlXMJWymdhXVI3BOpNt7ZOB2vMFYSOOHNBJUunQoe1lmNxuHQdhxqoHahn3u1cLDXz-xx-JELduuMmaDWqnTFPodVPl45WBKHaQhlOiFWj3ZClUV2k5p2yBT8TmxekL8gWwgVbQk5yPnYOs-PcMjzODc9MZX4yI10ZSCSDciwf-rgkQLT7wW4uZCoqTZ7187sCodHd6nw3nghqbtqN05fQ3Yq7ykwaR8pdQBFb2L9l7DhLLuXIREDKIFUHBSUs8OnvXFMg"; + String expected = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ" + + "." + signature; + signer.sign(jwt); - - assertThat(jwt.getSignature(), not(nullValue())); + + String actual = jwt.toString(); + + assertThat(actual, equalTo(expected)); + assertThat(jwt.getSignature(), equalTo(signature)); } - + @Test public void testParse() { String source = "eyJhbGciOiJub25lIn0.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."; - - + Jwt jwt = Jwt.parse(source); - - assertThat(jwt.getHeader().getAlgorithm(), equalTo(PlaintextSigner.PLAINTEXT)); + + assertThat(jwt.getHeader().getAlgorithm(), + equalTo(PlaintextSigner.PLAINTEXT)); assertThat(jwt.getClaims().getIssuer(), equalTo("joe")); - assertThat(jwt.getClaims().getExpiration(), equalTo(new Date(1300819380L * 1000L))); - assertThat((Boolean)jwt.getClaims().getClaim("http://example.com/is_root"), equalTo(Boolean.TRUE)); - - } - + 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(); @@ -124,48 +196,84 @@ public class JwtTest { // 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: + * 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} + * 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 public void testValidateHmacSignature() { // sign it byte[] key = null; - try { - key = "secret".getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - + try { + key = "secret".getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + JwtSigner signer = new HmacSigner(key); /* - * Token string based on the following strucutres, serialized exactly as follows and base64 encoded: + * Token string based on the following strucutres, serialized exactly as + * follows and base64 encoded: * - * header: {"typ":"JWT","alg":"HS256"} - * claims: {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} + * header: {"typ":"JWT","alg":"HS256"} claims: + * {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} * * Expected signature: iGBPJj47S5q_HAhSoQqAdcS6A_1CFj3zrLaImqNbt9E - * */ String jwtString = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.iGBPJj47S5q_HAhSoQqAdcS6A_1CFj3zrLaImqNbt9E"; - + boolean valid = signer.verify(jwtString); - + assertThat(valid, equalTo(Boolean.TRUE)); - + + } + + @Test + public void testValidateRsaSignature() throws Exception { + + /* + * Expected string based on the following structures, serialized exactly + * as follows and base64 encoded: + * + * header: {"typ":"JWT","alg":"HS256"} claims: + * {"exp":1300819380,"iss":"joe","http://example.com/is_root":true} + * + * Expected signature: dSRvtD-ExzGN- + * fRXd1wRZOPo1JFPuqgwvaIKp8jgcyMXJegy6IUjssfUfUcICN5yvh0ggOMWMeWkwQ7 + * -PlXMJWymdhXVI3BOpNt7ZOB2vMFYSOOHNBJUunQoe1lmNxuHQdhxqoHahn3u1cLDXz + * -xx- + * JELduuMmaDWqnTFPodVPl45WBKHaQhlOiFWj3ZClUV2k5p2yBT8TmxekL8gWwgVbQk5yPnYOs + * -PcMjzODc9MZX4yI10ZSCSDciwf- + * rgkQLT7wW4uZCoqTZ7187sCodHd6nw3nghqbtqN05fQ3Yq7ykwaR8pdQBFb2L9l7DhLLuXIREDKIFUHBSUs8OnvXFMg + */ + + // uses the "testGenerateRsaSignature" alias added just previously in + // the testGenerateRsaSignature unit test + + JwtSigner signer = new RsaSigner(RsaSigner.Algorithm.RS256.toString(), + keystore, "testGenerateRsaSignature", + RsaSigner.DEFAULT_PASSWORD); + ((RsaSigner) signer).afterPropertiesSet(); + + String jwtString = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjEzMDA4MTkzODAsImlzcyI6ImpvZSIsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dSRvtD-ExzGN-fRXd1wRZOPo1JFPuqgwvaIKp8jgcyMXJegy6IUjssfUfUcICN5yvh0ggOMWMeWkwQ7-PlXMJWymdhXVI3BOpNt7ZOB2vMFYSOOHNBJUunQoe1lmNxuHQdhxqoHahn3u1cLDXz-xx-JELduuMmaDWqnTFPodVPl45WBKHaQhlOiFWj3ZClUV2k5p2yBT8TmxekL8gWwgVbQk5yPnYOs-PcMjzODc9MZX4yI10ZSCSDciwf-rgkQLT7wW4uZCoqTZ7187sCodHd6nw3nghqbtqN05fQ3Yq7ykwaR8pdQBFb2L9l7DhLLuXIREDKIFUHBSUs8OnvXFMg"; + + boolean valid = signer.verify(jwtString); + + assertThat(valid, equalTo(Boolean.TRUE)); + } } diff --git a/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java b/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java index 1be36f671..e71524f08 100644 --- a/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java +++ b/server/src/test/java/org/mitre/jwt/signer/service/impl/KeyStoreTest.java @@ -52,7 +52,7 @@ public class KeyStoreTest { * @param daysNotValidAfter * @return */ - private static X509V3CertificateGenerator createCertificate( + public static X509V3CertificateGenerator createCertificate( String commonName, int daysNotValidBefore, int daysNotValidAfter) { // BC sez X509V3CertificateGenerator is deprecated and the docs say to // use another, but it seemingly isn't included jar...