diff --git a/openid-connect-client/.classpath b/openid-connect-client/.classpath index 1b28ee5d7..784c4613e 100644 --- a/openid-connect-client/.classpath +++ b/openid-connect-client/.classpath @@ -1,6 +1,8 @@ + + diff --git a/openid-connect-client/.settings/org.eclipse.jdt.core.prefs b/openid-connect-client/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 69c31cd49..000000000 --- a/openid-connect-client/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,8 +0,0 @@ -eclipse.preferences.version=1 -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.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 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/.settings/org.eclipse.wst.common.component b/openid-connect-client/.settings/org.eclipse.wst.common.component index fc2629825..d46f50e39 100755 --- a/openid-connect-client/.settings/org.eclipse.wst.common.component +++ b/openid-connect-client/.settings/org.eclipse.wst.common.component @@ -1,7 +1,7 @@ - + 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 e91ea9cb8..a498904fb 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 @@ -22,10 +22,14 @@ import java.net.URLEncoder; import java.security.GeneralSecurityException; 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.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -44,6 +48,12 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.DefaultHttpClient; +import org.mitre.jwt.signer.JwtSigner; +import org.mitre.jwt.signer.impl.RsaSigner; +import org.mitre.jwt.signer.service.JwtSigningAndValidationService; +import org.mitre.jwt.signer.service.impl.JwtSigningAndValidationServiceDefault; +import org.mitre.key.fetch.KeyFetcher; +import org.mitre.openid.connect.config.OIDCServerConfiguration; import org.mitre.openid.connect.model.IdToken; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.security.authentication.AuthenticationServiceException; @@ -57,8 +67,6 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; 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.JsonParser; @@ -78,7 +86,7 @@ public class AbstractOIDCAuthenticationFilter extends * @author nemonik * */ - class SanatizedRequest extends HttpServletRequestWrapper { + protected class SanatizedRequest extends HttpServletRequestWrapper { private List paramsToBeSanatized; @@ -109,8 +117,7 @@ public class AbstractOIDCAuthenticationFilter extends public Enumeration getParameterNames() { - ArrayList paramNames = Collections.list(super - .getParameterNames()); + ArrayList paramNames = Collections.list(super.getParameterNames()); for (String paramToBeSanatized : paramsToBeSanatized) { paramNames.remove(paramToBeSanatized); @@ -137,6 +144,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 @@ -203,8 +213,7 @@ public class AbstractOIDCAuthenticationFilter extends * http://server/path/program?query_string from the messaged * parameters. */ - public static String buildURL(String baseURI, - Map queryStringFields) { + public static String buildURL(String baseURI, Map queryStringFields) { StringBuilder URLBuilder = new StringBuilder(baseURI); @@ -214,9 +223,10 @@ public class AbstractOIDCAuthenticationFilter extends try { - URLBuilder.append(appendChar).append(param.getKey()) - .append('=') - .append(URLEncoder.encode(param.getValue(), "UTF-8")); + URLBuilder.append(appendChar) + .append(param.getKey()) + .append('=') + .append(URLEncoder.encode(param.getValue(), "UTF-8")); } catch (UnsupportedEncodingException uee) { @@ -241,8 +251,7 @@ public class AbstractOIDCAuthenticationFilter extends * The data to be signed * @return The signature text */ - public static String sign(Signature signer, PrivateKey privateKey, - byte[] data) { + public static String sign(Signature signer, PrivateKey privateKey, byte[] data) { String signature; try { @@ -323,8 +332,7 @@ public class AbstractOIDCAuthenticationFilter extends public void afterPropertiesSet() { super.afterPropertiesSet(); - Assert.notNull(errorRedirectURI, - "An Error Redirect URI must be supplied"); + Assert.notNull(errorRedirectURI, "An Error Redirect URI must be supplied"); KeyPairGenerator keyPairGenerator; @@ -377,6 +385,7 @@ public class AbstractOIDCAuthenticationFilter extends * authentication * @return The authenticated user token, or null if authentication is * incomplete. + * @throws Exception * @throws UnsupportedEncodingException */ protected Authentication handleAuthorizationGrantResponse( @@ -388,8 +397,7 @@ public class AbstractOIDCAuthenticationFilter extends // Handle Token Endpoint interaction HttpClient httpClient = new DefaultHttpClient(); - httpClient.getParams().setParameter("http.socket.timeout", - new Integer(httpSocketTimeout)); + httpClient.getParams().setParameter("http.socket.timeout", new Integer(httpSocketTimeout)); // // TODO: basic auth is untested (it wasn't working last I @@ -402,8 +410,7 @@ public class AbstractOIDCAuthenticationFilter extends // credentials); // - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory( - httpClient); + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); RestTemplate restTemplate = new RestTemplate(factory); @@ -418,11 +425,10 @@ public class AbstractOIDCAuthenticationFilter extends form.add("client_secret", serverConfig.getClientSecret()); if (debug) { - logger.debug("tokenEndpointURI = " - + serverConfig.getTokenEndpointURI()); + logger.debug("tokenEndpointURI = " + serverConfig.getTokenEndpointURI()); logger.debug("form = " + form); } - +; String jsonString = null; try { @@ -459,53 +465,47 @@ public class AbstractOIDCAuthenticationFilter extends } else { - // Extract the id_token - + // Extract the id_token to insert into the + // OpenIdConnectAuthenticationToken + IdToken idToken = null; - + JwtSigningAndValidationService jwtValidator = getValidatorForServer(serverConfig); + if (jsonRoot.getAsJsonObject().get("id_token") != null) { - + try { - idToken = IdToken.parse(jsonRoot.getAsJsonObject() - .get("id_token").getAsString()); - - List parts = Lists.newArrayList(Splitter.on(".") - .split(jsonRoot.getAsJsonObject().get("id_token") - .getAsString())); - - if (parts.size() != 3) { - throw new IllegalArgumentException( - "Invalid JWT format."); - } - - String h64 = parts.get(0); - String c64 = parts.get(1); - String s64 = parts.get(2); - - logger.debug("h64 = " + h64); - logger.debug("c64 = " + c64); - logger.debug("s64 = " + s64); - - } catch (Exception e) { + 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); + throw new AuthenticationServiceException("Problem parsing id_token return from Token endpoint: " + e); + } + + if(jwtValidator.validateSignature(jsonRoot.getAsJsonObject().get("id_token").getAsString()) + && idToken.getClaims().getIssuer() != null + && idToken.getClaims().getIssuer().equals(serverConfig.getIssuer()) + && idToken.getClaims().getIssuer().equals(serverConfig.getClientId()) + && !jwtValidator.isJwtExpired(idToken) + && jwtValidator.validateIssuedAt(idToken)){ + + + } + else{ + throw new AuthenticationServiceException("Problem verifying id_token"); } } else { // An error is unlikely, but it good security to check - logger.error("Token Endpoint did not return a token_id"); + logger.error("Token Endpoint did not return an id_token"); - throw new AuthenticationServiceException( - "Token Endpoint did not return a token_id"); + throw new AuthenticationServiceException("Token Endpoint did not return an id_token"); } // Clients are required to compare nonce claim in ID token to @@ -513,14 +513,10 @@ public class AbstractOIDCAuthenticationFilter extends // stores this value as a signed session cookie to detect a // replay by third parties. // - // See: OpenID Connect Messages - // - // Specifically, Section 2.1.1 entitled "ID Token" + // See: OpenID Connect Messages Section 2.1.1 entitled "ID Token" // // http://openid.net/specs/openid-connect-messages-1_0.html#id_token // - // Read the paragraph describing "nonce". Required w/ implicit flow. - // //String nonce = idToken.getClaims().getClaimAsString("nonce"); @@ -534,57 +530,49 @@ public class AbstractOIDCAuthenticationFilter extends "ID token did not contain a nonce claim."); } - Cookie nonceSignatureCookie = WebUtils.getCookie(request, - NONCE_SIGNATURE_COOKIE_NAME); + Cookie nonceSignatureCookie = WebUtils.getCookie(request, NONCE_SIGNATURE_COOKIE_NAME); if (nonceSignatureCookie != null) { String sigText = nonceSignatureCookie.getValue(); - + 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."); + + NONCE_SIGNATURE_COOKIE_NAME + + " failed."); } - } else { - logger.error(NONCE_SIGNATURE_COOKIE_NAME - + " was found, but was null or empty."); - - throw new AuthenticationServiceException( - NONCE_SIGNATURE_COOKIE_NAME - + " was found, but was null or empty."); + logger.error(NONCE_SIGNATURE_COOKIE_NAME + " cookie was found but value was null or empty"); + throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME + " cookie was found but value was null or empty"); } - + } else { logger.error(NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found."); - throw new AuthenticationServiceException( - NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found."); - } + throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found."); + } // pull the user_id out as a claim on the id_token String userId = idToken.getTokenClaims().getUserId(); // construct an OpenIdConnectAuthenticationToken and return - // a Authentication object w/ + // a Authentication object w/the userId and the idToken - OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken( - userId, idToken); + OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(userId, idToken); - Authentication authentication = this.getAuthenticationManager() - .authenticate(token); + Authentication authentication = this.getAuthenticationManager().authenticate(token); return authentication; @@ -615,8 +603,7 @@ public class AbstractOIDCAuthenticationFilter extends urlVariables.put("response_type", "code"); urlVariables.put("client_id", serverConfiguration.getClientId()); urlVariables.put("scope", scope); - urlVariables.put("redirect_uri", AbstractOIDCAuthenticationFilter - .buildRedirectURI(request, null)); + urlVariables.put("redirect_uri", AbstractOIDCAuthenticationFilter.buildRedirectURI(request, null)); // Create a string value used to associate a user agent session // with an ID Token to mitigate replay attacks. The value is @@ -626,8 +613,7 @@ public class AbstractOIDCAuthenticationFilter extends String nonce = new BigInteger(50, new SecureRandom()).toString(16); - Cookie nonceCookie = new Cookie(NONCE_SIGNATURE_COOKIE_NAME, sign( - signer, privateKey, nonce.getBytes())); + Cookie nonceCookie = new Cookie(NONCE_SIGNATURE_COOKIE_NAME, sign(signer, privateKey, nonce.getBytes())); response.addCookie(nonceCookie); @@ -637,9 +623,7 @@ public class AbstractOIDCAuthenticationFilter extends // TODO: display, prompt, request, request_uri - String authRequest = AbstractOIDCAuthenticationFilter - .buildURL(serverConfiguration.getAuthorizationEndpointURI(), - urlVariables); + String authRequest = AbstractOIDCAuthenticationFilter.buildURL(serverConfiguration.getAuthorizationEndpointURI(), urlVariables); logger.debug("Auth Request: " + authRequest); @@ -687,4 +671,63 @@ public class AbstractOIDCAuthenticationFilter extends public void setScope(String scope) { this.scope = scope; } -} \ No newline at end of file + + + protected JwtSigningAndValidationService getValidatorForServer(OIDCServerConfiguration serverConfig) { + + if(getValidationServices().containsKey(serverConfig)){ + return validationServices.get(serverConfig); + } else { + + KeyFetcher keyFetch = new KeyFetcher(); + PublicKey signingKey = null; + + // If the config has the X509 url, prefer that to the JWK + if(serverConfig.getX509SigningUrl() != null) { + signingKey = keyFetch.retrieveX509Key(serverConfig); + + } else { + // otherwise prefer the JWK + signingKey = keyFetch.retrieveJwkKey(serverConfig); + } + + if (signingKey != null) { + Map signers = new HashMap(); + + if (signingKey instanceof RSAPublicKey) { + + RSAPublicKey rsaKey = (RSAPublicKey)signingKey; + + // build an RSA signer + // FIXME: where do we get the algorithm name? + RsaSigner signer = new RsaSigner("RS256", rsaKey, null); + + signers.put(serverConfig.getIssuer(), signer); + } + + JwtSigningAndValidationService signingAndValidationService = new JwtSigningAndValidationServiceDefault(signers); + + validationServices.put(serverConfig, signingAndValidationService); + + return signingAndValidationService; + + } else { + // if we can't build a validation service, return null + return null; + } + } + + } + + 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/OIDCAuthenticationFilter.java b/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java index 93a362528..23dd02ca0 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 @@ -22,6 +22,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; +import org.mitre.openid.connect.config.OIDCServerConfiguration; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.util.Assert; @@ -94,9 +95,12 @@ 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 { @@ -125,4 +129,28 @@ 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); + } + + /** + * @param issuer + * @see org.mitre.openid.connect.config.OIDCServerConfiguration#setIssuer(java.lang.String) + */ + public void setIssuer(String issuer) { + oidcServerConfig.setIssuer(issuer); + } } 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 985f63750..8c47a6ae5 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 @@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; +import org.mitre.openid.connect.config.OIDCServerConfiguration; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; @@ -108,10 +109,13 @@ 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/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/test-context.xml b/openid-connect-client/src/test/resources/test-context.xml new file mode 100644 index 000000000..c849de679 --- /dev/null +++ b/openid-connect-client/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-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 1b28ee5d7..bf96ac098 100644 --- a/openid-connect-common/.classpath +++ b/openid-connect-common/.classpath @@ -1,6 +1,9 @@ + + + diff --git a/openid-connect-common/.settings/org.eclipse.jdt.core.prefs b/openid-connect-common/.settings/org.eclipse.jdt.core.prefs index 69c31cd49..d47a0fc68 100644 --- a/openid-connect-common/.settings/org.eclipse.jdt.core.prefs +++ b/openid-connect-common/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,19 @@ 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/.settings/org.eclipse.wst.common.component b/openid-connect-common/.settings/org.eclipse.wst.common.component index 4a3e4abda..e46a33a0e 100644 --- a/openid-connect-common/.settings/org.eclipse.wst.common.component +++ b/openid-connect-common/.settings/org.eclipse.wst.common.component @@ -1,7 +1,7 @@ - + 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..c09d9c1b4 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwk/model/Rsa.java @@ -0,0 +1,64 @@ +package org.mitre.jwk.model; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +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/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..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,17 +15,11 @@ ******************************************************************************/ 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; 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/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/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..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"); @@ -134,7 +139,8 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { * ) */ @Override - public String generateSignature(String signatureBase) { + public String generateSignature(String signatureBase) throws NoSuchAlgorithmException { + afterPropertiesSet(); if (passphrase == null) { throw new IllegalArgumentException("Passphrase cannot be null"); } @@ -172,6 +178,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean { this.passphrase = passphrase; } + /* * (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..4ab53303d 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; @@ -123,9 +124,6 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public RsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) { super(algorithmName); - Assert.notNull(publicKey, "An publicKey must be supplied"); - Assert.notNull(privateKey, "A privateKey must be supplied"); - this.publicKey = publicKey; this.privateKey = privateKey; } @@ -137,7 +135,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); @@ -173,9 +171,15 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { * ) */ @Override - public String generateSignature(String signatureBase) { + public String generateSignature(String signatureBase) throws NoSuchAlgorithmException { String sig = null; + try { + initializeSigner(); + } catch (GeneralSecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } try { signer.initSign(privateKey); @@ -228,6 +232,10 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { public void setPrivateKey(RSAPrivateKey privateKey) { this.privateKey = privateKey; } + + public void initializeSigner() throws NoSuchAlgorithmException{ + signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); + } /* * (non-Javadoc) @@ -266,6 +274,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean { String signingInput = h64 + "." + c64; try { + initializeSigner(); signer.initVerify(publicKey); signer.update(signingInput.getBytes("UTF-8")); value = signer.verify(Base64.decodeBase64(s64)); 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..8281501db 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,8 +15,8 @@ ******************************************************************************/ 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; @@ -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. @@ -59,17 +48,32 @@ 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); + /** - * Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm. - * Use the default algorithm to sign. + * Checks to see when this JWT was issued * - * @param jwt the jwt to sign - * @return the signed jwt + * @param jwt + * the JWT to check + * @return true if the issued at is valid, false if not + * @throws NoSuchAlgorithmException */ - public void signJwt(Jwt jwt); + public boolean validateIssuedAt(Jwt jwt); + + /** + * 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 boolean validateNonce(Jwt jwt, String nonce); /** * Sign a jwt using the selected algorithm. The algorithm is selected using the String parameter values specified @@ -79,6 +83,17 @@ 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 //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 new file mode 100644 index 000000000..f14f3b80e --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwt/signer/service/impl/AbstractJwtSigningAndValidationService.java @@ -0,0 +1,68 @@ +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 validateSignature(String jwtString) { + + for (JwtSigner signer : getSigners().values()) { + try { + if (signer.verify(jwtString)) { + return true; + } + } catch (NoSuchAlgorithmException e) { + // ignore, signer didn't verify signature, try the next one + e.printStackTrace(); + } + } + 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 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 3120b605a..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 @@ -15,8 +15,8 @@ ******************************************************************************/ 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,10 +31,10 @@ 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 + @Autowired private ConfigurationPropertiesBean configBean; // map of identifier to signer @@ -67,7 +67,7 @@ public class JwtSigningAndValidationServiceDefault implements * 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()); @@ -109,34 +109,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 * @@ -156,55 +128,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 */ @@ -218,4 +141,47 @@ 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; + } + + @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 validateNonce(Jwt jwt, String nonce) { + if(nonce.equals(jwt.getClaims().getNonce())){ + return true; + } + else{ + return false; + } + } } 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/key/fetch/KeyFetcher.java b/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java new file mode 100644 index 000000000..2d94dc803 --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/key/fetch/KeyFetcher.java @@ -0,0 +1,125 @@ +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.interfaces.RSAPublicKey; +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.config.OIDCServerConfiguration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.security.authentication.AuthenticationServiceException; +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; + +public class KeyFetcher { + + private HttpClient httpClient = new DefaultHttpClient(); + private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + private RestTemplate restTemplate = new RestTemplate(httpFactory); + + public List retrieveJwk(OIDCServerConfiguration serverConfig){ + + List keys = new ArrayList(); + + String jsonString = null; + + try { + jsonString = restTemplate.getForObject( + serverConfig.getTokenEndpointURI(), 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 PublicKey retrieveX509Key(OIDCServerConfiguration serverConfig) { + + + PublicKey key = null; + + try { + InputStream x509Stream = restTemplate.getForObject(serverConfig.getX509SigningUrl(), InputStream.class); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) factory.generateCertificate(x509Stream); + key = cert.getPublicKey(); + } catch (HttpClientErrorException httpClientErrorException) { + // TODO: add to log instead of this + httpClientErrorException.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return key; + } + + public PublicKey retrieveJwkKey(OIDCServerConfiguration serverConfig) { + RSAPublicKey pub = null; + + try { + String jwkString = restTemplate.getForObject(serverConfig.getJwkSigningUrl(), String.class); + JsonObject json = (JsonObject) new JsonParser().parse(jwkString); + JsonArray getArray = json.getAsJsonArray("keys"); + JsonObject object = getArray.get(0).getAsJsonObject(); // TODO: this only does something on the first key and assumes it's RSA... + + 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"); + pub = (RSAPublicKey) factory.generatePublic(spec); + } catch (HttpClientErrorException httpClientErrorException) { + // TODO: add to log + httpClientErrorException.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return pub; + } + +} diff --git a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java b/openid-connect-common/src/main/java/org/mitre/openid/connect/config/OIDCServerConfiguration.java similarity index 60% rename from openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java rename to openid-connect-common/src/main/java/org/mitre/openid/connect/config/OIDCServerConfiguration.java index 02dcbf065..f0589daa9 100644 --- a/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCServerConfiguration.java +++ b/openid-connect-common/src/main/java/org/mitre/openid/connect/config/OIDCServerConfiguration.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ -package org.mitre.openid.connect.client; +package org.mitre.openid.connect.config; /** * @author nemonik @@ -28,6 +28,16 @@ public class OIDCServerConfiguration { private String clientSecret; private String clientId; + + private String issuer; + + private String x509EncryptUrl; + + private String x509SigningUrl; + + private String jwkEncryptUrl; + + private String jwkSigningUrl; public String getAuthorizationEndpointURI() { return authorizationEndpointURI; @@ -36,6 +46,10 @@ public class OIDCServerConfiguration { public String getClientId() { return clientId; } + + public String getIssuer() { + return issuer; + } public String getClientSecret() { return clientSecret; @@ -53,6 +67,10 @@ public class OIDCServerConfiguration { this.clientId = clientId; } + public void setIssuer(String issuer) { + this.issuer = issuer; + } + public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } @@ -60,13 +78,50 @@ 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; + } @Override public String toString() { return "OIDCServerConfiguration [authorizationEndpointURI=" + authorizationEndpointURI + ", tokenEndpointURI=" + tokenEndpointURI + ", clientSecret=" + clientSecret - + ", clientId=" + clientId + "]"; + + ", clientId=" + clientId + ", issuer=" + issuer + +", x509EncryptedUrl=" + + x509EncryptUrl + ", jwkEncryptedUrl=" + + jwkEncryptUrl + ", x509SigningUrl=" + + x509SigningUrl + ", jwkSigningUrl=" + + jwkSigningUrl + "]"; } } \ No newline at end of file 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 d6655286a..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 @@ -43,4 +43,5 @@ public class Utility { } return issuer; } + } 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 new file mode 100644 index 000000000..f67a9e476 --- /dev/null +++ b/openid-connect-common/src/test/java/org/mitre/jwt/signer/impl/PlaintextSignerTest.java @@ -0,0 +1,67 @@ +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; + +@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"); + 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(plaintextUrl.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 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/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 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/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-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 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/token/ConnectTokenEnhancer.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java index 544ddcde5..1665941b9 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java @@ -15,12 +15,16 @@ ******************************************************************************/ package org.mitre.openid.connect.token; +import java.security.NoSuchAlgorithmException; import java.util.Date; import org.mitre.jwt.signer.service.JwtSigningAndValidationService; import org.mitre.oauth2.model.OAuth2AccessTokenEntity; import org.mitre.openid.connect.config.ConfigurationPropertiesBean; import org.mitre.openid.connect.model.IdToken; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.spi.LoggerFactoryBinder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; @@ -32,6 +36,8 @@ import com.google.common.base.Strings; @Service public class ConnectTokenEnhancer implements TokenEnhancer { + Logger logger = LoggerFactory.getLogger(ConnectTokenEnhancer.class); + @Autowired private ConfigurationPropertiesBean configBean; @@ -57,7 +63,12 @@ public class ConnectTokenEnhancer implements TokenEnhancer { token.getJwt().getClaims().setExpiration(token.getExpiration()); //TODO: check for client's preferred signer alg and use that - jwtService.signJwt(token.getJwt()); + try { + jwtService.signJwt(token.getJwt()); + } catch (NoSuchAlgorithmException e) { + // couldn't sign token + logger.warn("Couldn't sign access token", e); + } /** * Authorization request scope MUST include "openid", but access token request @@ -80,7 +91,11 @@ public class ConnectTokenEnhancer implements TokenEnhancer { // TODO: expiration? other fields? //TODO: check for client's preferred signer alg and use that - jwtService.signJwt(idToken); + try { + jwtService.signJwt(idToken); + } catch (NoSuchAlgorithmException e) { + logger.warn("Couldn't sign id token", e); + } token.setIdToken(idToken); } diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JwkKeyListView.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JwkKeyListView.java index c8088f159..c9f3a6de4 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JwkKeyListView.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/view/JwkKeyListView.java @@ -101,7 +101,7 @@ public class JwkKeyListView extends AbstractView { JsonObject o = new JsonObject(); o.addProperty("use", "sig"); // since we don't do encryption yet - o.addProperty("alg", "RSA"); // we know this is RSA + o.addProperty("alg", "RS" + rsa.getModulus().bitLength()); // we know this is RSA o.addProperty("mod", m64); o.addProperty("exp", e64); o.addProperty("kid", keyId); 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..448567872 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; @@ -48,10 +50,10 @@ public class CheckIDEndpoint { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (!jwtSignerService.validateSignature(tokenString)) { - // can't validate - throw new InvalidJwtSignatureException("The Signature could not be validated."); - } + if (!jwtSignerService.validateSignature(tokenString)) { + // can't validate + throw new InvalidJwtSignatureException("The Signature could not be validated."); + } // it's a valid signature, parse the token IdToken token = IdToken.parse(tokenString); @@ -63,9 +65,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()); 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"); 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));