merged derryberry code, plus tweaks, still WIP
commit
adb8499bee
|
@ -1,6 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
<attributes>
|
<attributes>
|
||||||
|
|
|
@ -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
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project-modules id="moduleCoreId" project-version="1.5.0">
|
<project-modules id="moduleCoreId" project-version="1.5.0">
|
||||||
<wb-module deploy-name="openid-connect-client">
|
<wb-module deploy-name="openid-connect-client">
|
||||||
<wb-resource deploy-path="/" source-path="/src/main/java"/>
|
|
||||||
<wb-resource deploy-path="/" source-path="/src/main/resources"/>
|
<wb-resource deploy-path="/" source-path="/src/main/resources"/>
|
||||||
|
<wb-resource deploy-path="/" source-path="/src/main/java"/>
|
||||||
</wb-module>
|
</wb-module>
|
||||||
</project-modules>
|
</project-modules>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beansProjectDescription>
|
||||||
|
<version>1</version>
|
||||||
|
<pluginVersion><![CDATA[2.9.1.201203220057-RELEASE]]></pluginVersion>
|
||||||
|
<configSuffixes>
|
||||||
|
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||||
|
</configSuffixes>
|
||||||
|
<enableImports><![CDATA[false]]></enableImports>
|
||||||
|
<configs>
|
||||||
|
<config>spring-servlet.xml</config>
|
||||||
|
</configs>
|
||||||
|
<configSets>
|
||||||
|
</configSets>
|
||||||
|
</beansProjectDescription>
|
|
@ -22,10 +22,14 @@ import java.net.URLEncoder;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Signature;
|
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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -44,6 +48,12 @@ import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
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.mitre.openid.connect.model.IdToken;
|
||||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
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.client.RestTemplate;
|
||||||
import org.springframework.web.util.WebUtils;
|
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.JsonElement;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
@ -78,7 +86,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
* @author nemonik
|
* @author nemonik
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SanatizedRequest extends HttpServletRequestWrapper {
|
protected class SanatizedRequest extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
private List<String> paramsToBeSanatized;
|
private List<String> paramsToBeSanatized;
|
||||||
|
|
||||||
|
@ -109,8 +117,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
public Enumeration<String> getParameterNames() {
|
public Enumeration<String> getParameterNames() {
|
||||||
|
|
||||||
ArrayList<String> paramNames = Collections.list(super
|
ArrayList<String> paramNames = Collections.list(super.getParameterNames());
|
||||||
.getParameterNames());
|
|
||||||
|
|
||||||
for (String paramToBeSanatized : paramsToBeSanatized) {
|
for (String paramToBeSanatized : paramsToBeSanatized) {
|
||||||
paramNames.remove(paramToBeSanatized);
|
paramNames.remove(paramToBeSanatized);
|
||||||
|
@ -137,6 +144,9 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
protected final static String FILTER_PROCESSES_URL = "/openid_connect_login";
|
protected final static String FILTER_PROCESSES_URL = "/openid_connect_login";
|
||||||
|
|
||||||
|
|
||||||
|
private Map<OIDCServerConfiguration, JwtSigningAndValidationService> validationServices = new HashMap<OIDCServerConfiguration, JwtSigningAndValidationService>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the redirect_uri that will be sent to the Authorization Endpoint.
|
* 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
|
* 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
|
* http://server/path/program?query_string from the messaged
|
||||||
* parameters.
|
* parameters.
|
||||||
*/
|
*/
|
||||||
public static String buildURL(String baseURI,
|
public static String buildURL(String baseURI, Map<String, String> queryStringFields) {
|
||||||
Map<String, String> queryStringFields) {
|
|
||||||
|
|
||||||
StringBuilder URLBuilder = new StringBuilder(baseURI);
|
StringBuilder URLBuilder = new StringBuilder(baseURI);
|
||||||
|
|
||||||
|
@ -214,9 +223,10 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
URLBuilder.append(appendChar).append(param.getKey())
|
URLBuilder.append(appendChar)
|
||||||
.append('=')
|
.append(param.getKey())
|
||||||
.append(URLEncoder.encode(param.getValue(), "UTF-8"));
|
.append('=')
|
||||||
|
.append(URLEncoder.encode(param.getValue(), "UTF-8"));
|
||||||
|
|
||||||
} catch (UnsupportedEncodingException uee) {
|
} catch (UnsupportedEncodingException uee) {
|
||||||
|
|
||||||
|
@ -241,8 +251,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
* The data to be signed
|
* The data to be signed
|
||||||
* @return The signature text
|
* @return The signature text
|
||||||
*/
|
*/
|
||||||
public static String sign(Signature signer, PrivateKey privateKey,
|
public static String sign(Signature signer, PrivateKey privateKey, byte[] data) {
|
||||||
byte[] data) {
|
|
||||||
String signature;
|
String signature;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -323,8 +332,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
super.afterPropertiesSet();
|
super.afterPropertiesSet();
|
||||||
|
|
||||||
Assert.notNull(errorRedirectURI,
|
Assert.notNull(errorRedirectURI, "An Error Redirect URI must be supplied");
|
||||||
"An Error Redirect URI must be supplied");
|
|
||||||
|
|
||||||
KeyPairGenerator keyPairGenerator;
|
KeyPairGenerator keyPairGenerator;
|
||||||
|
|
||||||
|
@ -377,6 +385,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
* authentication
|
* authentication
|
||||||
* @return The authenticated user token, or null if authentication is
|
* @return The authenticated user token, or null if authentication is
|
||||||
* incomplete.
|
* incomplete.
|
||||||
|
* @throws Exception
|
||||||
* @throws UnsupportedEncodingException
|
* @throws UnsupportedEncodingException
|
||||||
*/
|
*/
|
||||||
protected Authentication handleAuthorizationGrantResponse(
|
protected Authentication handleAuthorizationGrantResponse(
|
||||||
|
@ -388,8 +397,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
// Handle Token Endpoint interaction
|
// Handle Token Endpoint interaction
|
||||||
HttpClient httpClient = new DefaultHttpClient();
|
HttpClient httpClient = new DefaultHttpClient();
|
||||||
|
|
||||||
httpClient.getParams().setParameter("http.socket.timeout",
|
httpClient.getParams().setParameter("http.socket.timeout", new Integer(httpSocketTimeout));
|
||||||
new Integer(httpSocketTimeout));
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// TODO: basic auth is untested (it wasn't working last I
|
// TODO: basic auth is untested (it wasn't working last I
|
||||||
|
@ -402,8 +410,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
// credentials);
|
// credentials);
|
||||||
//
|
//
|
||||||
|
|
||||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
|
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||||
httpClient);
|
|
||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate(factory);
|
RestTemplate restTemplate = new RestTemplate(factory);
|
||||||
|
|
||||||
|
@ -418,11 +425,10 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
form.add("client_secret", serverConfig.getClientSecret());
|
form.add("client_secret", serverConfig.getClientSecret());
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
logger.debug("tokenEndpointURI = "
|
logger.debug("tokenEndpointURI = " + serverConfig.getTokenEndpointURI());
|
||||||
+ serverConfig.getTokenEndpointURI());
|
|
||||||
logger.debug("form = " + form);
|
logger.debug("form = " + form);
|
||||||
}
|
}
|
||||||
|
;
|
||||||
String jsonString = null;
|
String jsonString = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -459,53 +465,47 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Extract the id_token
|
// Extract the id_token to insert into the
|
||||||
|
// OpenIdConnectAuthenticationToken
|
||||||
|
|
||||||
IdToken idToken = null;
|
IdToken idToken = null;
|
||||||
|
JwtSigningAndValidationService jwtValidator = getValidatorForServer(serverConfig);
|
||||||
|
|
||||||
if (jsonRoot.getAsJsonObject().get("id_token") != null) {
|
if (jsonRoot.getAsJsonObject().get("id_token") != null) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
idToken = IdToken.parse(jsonRoot.getAsJsonObject()
|
idToken = IdToken.parse(jsonRoot.getAsJsonObject().get("id_token").getAsString());
|
||||||
.get("id_token").getAsString());
|
|
||||||
|
} catch (AuthenticationServiceException e) {
|
||||||
List<String> 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) {
|
|
||||||
|
|
||||||
// I suspect this could happen
|
// I suspect this could happen
|
||||||
|
|
||||||
logger.error("Problem parsing id_token: " + e);
|
logger.error("Problem parsing id_token: " + e);
|
||||||
// e.printStackTrace();
|
// e.printStackTrace();
|
||||||
|
|
||||||
throw new AuthenticationServiceException(
|
throw new AuthenticationServiceException("Problem parsing id_token return from Token endpoint: " + e);
|
||||||
"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 {
|
} else {
|
||||||
|
|
||||||
// An error is unlikely, but it good security to check
|
// 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(
|
throw new AuthenticationServiceException("Token Endpoint did not return an id_token");
|
||||||
"Token Endpoint did not return a token_id");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clients are required to compare nonce claim in ID token to
|
// 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
|
// stores this value as a signed session cookie to detect a
|
||||||
// replay by third parties.
|
// replay by third parties.
|
||||||
//
|
//
|
||||||
// See: OpenID Connect Messages
|
// See: OpenID Connect Messages Section 2.1.1 entitled "ID Token"
|
||||||
//
|
|
||||||
// Specifically, Section 2.1.1 entitled "ID Token"
|
|
||||||
//
|
//
|
||||||
// http://openid.net/specs/openid-connect-messages-1_0.html#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");
|
//String nonce = idToken.getClaims().getClaimAsString("nonce");
|
||||||
|
|
||||||
|
@ -534,57 +530,49 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
"ID token did not contain a nonce claim.");
|
"ID token did not contain a nonce claim.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Cookie nonceSignatureCookie = WebUtils.getCookie(request,
|
Cookie nonceSignatureCookie = WebUtils.getCookie(request, NONCE_SIGNATURE_COOKIE_NAME);
|
||||||
NONCE_SIGNATURE_COOKIE_NAME);
|
|
||||||
|
|
||||||
if (nonceSignatureCookie != null) {
|
if (nonceSignatureCookie != null) {
|
||||||
|
|
||||||
String sigText = nonceSignatureCookie.getValue();
|
String sigText = nonceSignatureCookie.getValue();
|
||||||
|
|
||||||
if (sigText != null && !sigText.isEmpty()) {
|
if (sigText != null && !sigText.isEmpty()) {
|
||||||
|
|
||||||
if (!verify(signer, publicKey, nonce, sigText)) {
|
if (!verify(signer, publicKey, nonce, sigText)) {
|
||||||
logger.error("Possible replay attack detected! "
|
logger.error("Possible replay attack detected! "
|
||||||
+ "The comparison of the nonce in the returned "
|
+ "The comparison of the nonce in the returned "
|
||||||
+ "ID Token to the signed session "
|
+ "ID Token to the signed session "
|
||||||
+ NONCE_SIGNATURE_COOKIE_NAME + " failed.");
|
+ NONCE_SIGNATURE_COOKIE_NAME + " failed.");
|
||||||
|
|
||||||
throw new AuthenticationServiceException(
|
throw new AuthenticationServiceException(
|
||||||
"Possible replay attack detected! "
|
"Possible replay attack detected! "
|
||||||
+ "The comparison of the nonce in the returned "
|
+ "The comparison of the nonce in the returned "
|
||||||
+ "ID Token to the signed session "
|
+ "ID Token to the signed session "
|
||||||
+ NONCE_SIGNATURE_COOKIE_NAME + " failed.");
|
+ NONCE_SIGNATURE_COOKIE_NAME
|
||||||
|
+ " failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logger.error(NONCE_SIGNATURE_COOKIE_NAME
|
logger.error(NONCE_SIGNATURE_COOKIE_NAME + " cookie was found but value was null or empty");
|
||||||
+ " was found, but was null or empty.");
|
throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME + " cookie was found but value was null or empty");
|
||||||
|
|
||||||
throw new AuthenticationServiceException(
|
|
||||||
NONCE_SIGNATURE_COOKIE_NAME
|
|
||||||
+ " was found, but was null or empty.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
logger.error(NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found.");
|
logger.error(NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found.");
|
||||||
|
|
||||||
throw new AuthenticationServiceException(
|
throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found.");
|
||||||
NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found.");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// pull the user_id out as a claim on the id_token
|
// pull the user_id out as a claim on the id_token
|
||||||
|
|
||||||
String userId = idToken.getTokenClaims().getUserId();
|
String userId = idToken.getTokenClaims().getUserId();
|
||||||
|
|
||||||
// construct an OpenIdConnectAuthenticationToken and return
|
// construct an OpenIdConnectAuthenticationToken and return
|
||||||
// a Authentication object w/
|
// a Authentication object w/the userId and the idToken
|
||||||
|
|
||||||
OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(
|
OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(userId, idToken);
|
||||||
userId, idToken);
|
|
||||||
|
|
||||||
Authentication authentication = this.getAuthenticationManager()
|
Authentication authentication = this.getAuthenticationManager().authenticate(token);
|
||||||
.authenticate(token);
|
|
||||||
|
|
||||||
return authentication;
|
return authentication;
|
||||||
|
|
||||||
|
@ -615,8 +603,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
urlVariables.put("response_type", "code");
|
urlVariables.put("response_type", "code");
|
||||||
urlVariables.put("client_id", serverConfiguration.getClientId());
|
urlVariables.put("client_id", serverConfiguration.getClientId());
|
||||||
urlVariables.put("scope", scope);
|
urlVariables.put("scope", scope);
|
||||||
urlVariables.put("redirect_uri", AbstractOIDCAuthenticationFilter
|
urlVariables.put("redirect_uri", AbstractOIDCAuthenticationFilter.buildRedirectURI(request, null));
|
||||||
.buildRedirectURI(request, null));
|
|
||||||
|
|
||||||
// Create a string value used to associate a user agent session
|
// Create a string value used to associate a user agent session
|
||||||
// with an ID Token to mitigate replay attacks. The value is
|
// 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);
|
String nonce = new BigInteger(50, new SecureRandom()).toString(16);
|
||||||
|
|
||||||
Cookie nonceCookie = new Cookie(NONCE_SIGNATURE_COOKIE_NAME, sign(
|
Cookie nonceCookie = new Cookie(NONCE_SIGNATURE_COOKIE_NAME, sign(signer, privateKey, nonce.getBytes()));
|
||||||
signer, privateKey, nonce.getBytes()));
|
|
||||||
|
|
||||||
response.addCookie(nonceCookie);
|
response.addCookie(nonceCookie);
|
||||||
|
|
||||||
|
@ -637,9 +623,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
// TODO: display, prompt, request, request_uri
|
// TODO: display, prompt, request, request_uri
|
||||||
|
|
||||||
String authRequest = AbstractOIDCAuthenticationFilter
|
String authRequest = AbstractOIDCAuthenticationFilter.buildURL(serverConfiguration.getAuthorizationEndpointURI(), urlVariables);
|
||||||
.buildURL(serverConfiguration.getAuthorizationEndpointURI(),
|
|
||||||
urlVariables);
|
|
||||||
|
|
||||||
logger.debug("Auth Request: " + authRequest);
|
logger.debug("Auth Request: " + authRequest);
|
||||||
|
|
||||||
|
@ -687,4 +671,63 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
public void setScope(String scope) {
|
public void setScope(String scope) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
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<String, JwtSigner> signers = new HashMap<String, JwtSigner>();
|
||||||
|
|
||||||
|
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<OIDCServerConfiguration, JwtSigningAndValidationService> getValidationServices() {
|
||||||
|
return validationServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValidationServices(
|
||||||
|
Map<OIDCServerConfiguration, JwtSigningAndValidationService> validationServices) {
|
||||||
|
this.validationServices = validationServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.mitre.openid.connect.config.OIDCServerConfiguration;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -94,9 +95,12 @@ public class OIDCAuthenticationFilter extends AbstractOIDCAuthenticationFilter {
|
||||||
|
|
||||||
} else if (StringUtils.isNotBlank(request.getParameter("code"))) {
|
} else if (StringUtils.isNotBlank(request.getParameter("code"))) {
|
||||||
|
|
||||||
return handleAuthorizationGrantResponse(
|
try {
|
||||||
request.getParameter("code"), new SanatizedRequest(request,
|
return handleAuthorizationGrantResponse(request.getParameter("code"), new SanatizedRequest(request, new String[] { "code" }), oidcServerConfig);
|
||||||
new String[] { "code" }), oidcServerConfig);
|
} catch (Exception e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -125,4 +129,28 @@ public class OIDCAuthenticationFilter extends AbstractOIDCAuthenticationFilter {
|
||||||
public void setTokenEndpointURI(String tokenEndpointURI) {
|
public void setTokenEndpointURI(String tokenEndpointURI) {
|
||||||
oidcServerConfig.setTokenEndpointURI(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.mitre.openid.connect.config.OIDCServerConfiguration;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
@ -108,10 +109,13 @@ public class OIDCAuthenticationUsingChooserFilter extends
|
||||||
Cookie issuerCookie = WebUtils.getCookie(request,
|
Cookie issuerCookie = WebUtils.getCookie(request,
|
||||||
ISSUER_COOKIE_NAME);
|
ISSUER_COOKIE_NAME);
|
||||||
|
|
||||||
return handleAuthorizationGrantResponse(
|
try {
|
||||||
request.getParameter("code"), new SanatizedRequest(request,
|
return handleAuthorizationGrantResponse(request.getParameter("code"), new SanatizedRequest(request, new String[] { "code" }),
|
||||||
new String[] { "code" }),
|
oidcServerConfigs.get(issuerCookie.getValue()));
|
||||||
oidcServerConfigs.get(issuerCookie.getValue()));
|
} catch (Exception e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
|
@ -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"}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:jwt-signer="http://www.mitre.org/schema/openid-connect/jwt-signer"
|
||||||
|
xsi:schemaLocation=
|
||||||
|
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
|
http://www.mitre.org/schema/openid-connect/jwt-signer http://www.mitre.org/schema/openid-connect/jwt-signer/jwt-signer-1.0.xsd" >
|
||||||
|
|
||||||
|
<!-- Creates an in-memory database populated with test jdbc -->
|
||||||
|
<bean id="dataSource" class="org.mitre.jdbc.datasource.H2DataSourceFactory">
|
||||||
|
<property name="databaseName" value="connect"/>
|
||||||
|
<property name="scriptLocations" >
|
||||||
|
<list>
|
||||||
|
<!-- OpenID Connect Data model -->
|
||||||
|
<value>file:db/tables/accesstoken.sql</value>
|
||||||
|
<value>file:db/tables/address.sql</value>
|
||||||
|
<value>file:db/tables/approvedsite.sql</value>
|
||||||
|
<value>file:db/tables/authorities.sql</value>
|
||||||
|
<value>file:db/tables/clientdetails.sql</value>
|
||||||
|
<value>file:db/tables/event.sql</value>
|
||||||
|
<value>file:db/tables/granttypes.sql</value>
|
||||||
|
<value>file:db/tables/idtoken.sql</value>
|
||||||
|
<value>file:db/tables/idtokenclaims.sql</value>
|
||||||
|
<value>file:db/tables/refreshtoken.sql</value>
|
||||||
|
<value>file:db/tables/scope.sql</value>
|
||||||
|
<value>file:db/tables/userinfo.sql</value>
|
||||||
|
<value>file:db/tables/whitelistedsite.sql</value>
|
||||||
|
<!-- Preloaded data -->
|
||||||
|
<value>classpath:test-data.sql</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<property name="dateConversionPatterns">
|
||||||
|
<map>
|
||||||
|
<entry key="yyyy/mm/dd hh24:mi:ss" value="yyy/MM/dd HH:mm:ss" />
|
||||||
|
<entry key="yyyy-mm-dd" value="yyyy-MM-dd" />
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -1,6 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
<attributes>
|
<attributes>
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
eclipse.preferences.version=1
|
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.inlineJsrBytecode=enabled
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||||
org.eclipse.jdt.core.compiler.compliance=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.assertIdentifier=error
|
||||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
org.eclipse.jdt.core.compiler.source=1.6
|
org.eclipse.jdt.core.compiler.source=1.6
|
||||||
|
org.eclipse.jdt.core.incompatibleJDKLevel=ignore
|
||||||
|
org.eclipse.jdt.core.incompleteClasspath=error
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project-modules id="moduleCoreId" project-version="1.5.0">
|
<project-modules id="moduleCoreId" project-version="1.5.0">
|
||||||
<wb-module deploy-name="openid-connect-common">
|
<wb-module deploy-name="openid-connect-common">
|
||||||
<wb-resource deploy-path="/" source-path="/src/main/java"/>
|
|
||||||
<wb-resource deploy-path="/" source-path="/src/main/resources"/>
|
<wb-resource deploy-path="/" source-path="/src/main/resources"/>
|
||||||
|
<wb-resource deploy-path="/" source-path="/src/main/java"/>
|
||||||
</wb-module>
|
</wb-module>
|
||||||
</project-modules>
|
</project-modules>
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -133,7 +133,7 @@ public class Jwt {
|
||||||
return h64 + "." + c64;
|
return h64 + "." + c64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a wire-encoded JWT
|
* Parse a wire-encoded JWT
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,17 +15,11 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.jwt.model;
|
package org.mitre.jwt.model;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
|
|
||||||
public class JwtClaims extends ClaimSet {
|
public class JwtClaims extends ClaimSet {
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,10 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.jwt.model;
|
package org.mitre.jwt.model;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
|
|
||||||
public class JwtHeader extends ClaimSet {
|
public class JwtHeader extends ClaimSet {
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.jwt.signer;
|
package org.mitre.jwt.signer;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.mitre.jwt.model.Jwt;
|
import org.mitre.jwt.model.Jwt;
|
||||||
|
@ -52,9 +53,10 @@ public abstract class AbstractJwtSigner implements JwtSigner {
|
||||||
*
|
*
|
||||||
* @param jwt the jwt to sign
|
* @param jwt the jwt to sign
|
||||||
* @return the signed jwt
|
* @return the signed jwt
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Jwt sign(Jwt jwt) {
|
public Jwt sign(Jwt jwt) throws NoSuchAlgorithmException {
|
||||||
if (!Objects.equal(algorithm, jwt.getHeader().getAlgorithm())) {
|
if (!Objects.equal(algorithm, jwt.getHeader().getAlgorithm())) {
|
||||||
// algorithm type doesn't match
|
// algorithm type doesn't match
|
||||||
// TODO: should this be an error or should we just fix it in the incoming jwt?
|
// 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)
|
* @see org.mitre.jwt.JwtSigner#verify(java.lang.String)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean verify(String jwtString) {
|
public boolean verify(String jwtString) throws NoSuchAlgorithmException {
|
||||||
// split on the dots
|
// split on the dots
|
||||||
List<String> parts = Lists.newArrayList(Splitter.on(".").split(jwtString));
|
List<String> 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,14 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.jwt.signer;
|
package org.mitre.jwt.signer;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
import org.mitre.jwt.model.Jwt;
|
import org.mitre.jwt.model.Jwt;
|
||||||
|
|
||||||
public interface JwtSigner {
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,10 +117,15 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet(){
|
||||||
|
|
||||||
mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm())
|
try {
|
||||||
.getStandardName());
|
mac = Mac.getInstance(JwsAlgorithm.getByName(super.getAlgorithm())
|
||||||
|
.getStandardName());
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug(JwsAlgorithm.getByName(getAlgorithm()).getStandardName()
|
logger.debug(JwsAlgorithm.getByName(getAlgorithm()).getStandardName()
|
||||||
+ " ECDSA Signer ready for business");
|
+ " ECDSA Signer ready for business");
|
||||||
|
@ -134,7 +139,8 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String generateSignature(String signatureBase) {
|
public String generateSignature(String signatureBase) throws NoSuchAlgorithmException {
|
||||||
|
afterPropertiesSet();
|
||||||
if (passphrase == null) {
|
if (passphrase == null) {
|
||||||
throw new IllegalArgumentException("Passphrase cannot be null");
|
throw new IllegalArgumentException("Passphrase cannot be null");
|
||||||
}
|
}
|
||||||
|
@ -172,6 +178,7 @@ public class HmacSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
this.passphrase = passphrase;
|
this.passphrase = passphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.mitre.jwt.signer.impl;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.Signature;
|
import java.security.Signature;
|
||||||
|
@ -123,9 +124,6 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
public RsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) {
|
public RsaSigner(String algorithmName, PublicKey publicKey, PrivateKey privateKey) {
|
||||||
super(algorithmName);
|
super(algorithmName);
|
||||||
|
|
||||||
Assert.notNull(publicKey, "An publicKey must be supplied");
|
|
||||||
Assert.notNull(privateKey, "A privateKey must be supplied");
|
|
||||||
|
|
||||||
this.publicKey = publicKey;
|
this.publicKey = publicKey;
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +135,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws NoSuchAlgorithmException, GeneralSecurityException {
|
||||||
|
|
||||||
// unsupported algorithm will throw a NoSuchAlgorithmException
|
// unsupported algorithm will throw a NoSuchAlgorithmException
|
||||||
signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); // ,PROVIDER);
|
signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName()); // ,PROVIDER);
|
||||||
|
@ -173,9 +171,15 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String generateSignature(String signatureBase) {
|
public String generateSignature(String signatureBase) throws NoSuchAlgorithmException {
|
||||||
|
|
||||||
String sig = null;
|
String sig = null;
|
||||||
|
try {
|
||||||
|
initializeSigner();
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
signer.initSign(privateKey);
|
signer.initSign(privateKey);
|
||||||
|
@ -228,6 +232,10 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
public void setPrivateKey(RSAPrivateKey privateKey) {
|
public void setPrivateKey(RSAPrivateKey privateKey) {
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initializeSigner() throws NoSuchAlgorithmException{
|
||||||
|
signer = Signature.getInstance(JwsAlgorithm.getByName(super.getAlgorithm()).getStandardName());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
|
@ -266,6 +274,7 @@ public class RsaSigner extends AbstractJwtSigner implements InitializingBean {
|
||||||
String signingInput = h64 + "." + c64;
|
String signingInput = h64 + "." + c64;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
initializeSigner();
|
||||||
signer.initVerify(publicKey);
|
signer.initVerify(publicKey);
|
||||||
signer.update(signingInput.getBytes("UTF-8"));
|
signer.update(signingInput.getBytes("UTF-8"));
|
||||||
value = signer.verify(Base64.decodeBase64(s64));
|
value = signer.verify(Base64.decodeBase64(s64));
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.jwt.signer.service;
|
package org.mitre.jwt.signer.service;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.mitre.jwt.model.Jwt;
|
import org.mitre.jwt.model.Jwt;
|
||||||
|
@ -41,17 +41,6 @@ public interface JwtSigningAndValidationService {
|
||||||
*/
|
*/
|
||||||
public boolean isJwtExpired(Jwt jwt);
|
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,
|
* Checks the signature of the given JWT against all configured signers,
|
||||||
* returns true if at least one of the signers validates it.
|
* returns true if at least one of the signers validates it.
|
||||||
|
@ -59,17 +48,32 @@ public interface JwtSigningAndValidationService {
|
||||||
* @param jwtString
|
* @param jwtString
|
||||||
* the string representation of the JWT as sent on the wire
|
* the string representation of the JWT as sent on the wire
|
||||||
* @return true if the signature is valid, false if not
|
* @return true if the signature is valid, false if not
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
*/
|
*/
|
||||||
public boolean validateSignature(String jwtString);
|
public boolean validateSignature(String jwtString);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to sign a jwt in place for a client that hasn't registered a preferred signing algorithm.
|
* Checks to see when this JWT was issued
|
||||||
* Use the default algorithm to sign.
|
|
||||||
*
|
*
|
||||||
* @param jwt the jwt to sign
|
* @param jwt
|
||||||
* @return the signed 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
|
* 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
|
* @param alg the name of the algorithm to use, as specified in JWS s.6
|
||||||
* @return the signed jwt
|
* @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
|
//TODO: implement later; only need signJwt(Jwt jwt) for now
|
||||||
//public Jwt signJwt(Jwt jwt, String alg);
|
//public Jwt signJwt(Jwt jwt, String alg);
|
||||||
|
|
||||||
|
|
|
@ -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<String, ? extends JwtSigner> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,8 +15,8 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.jwt.signer.service.impl;
|
package org.mitre.jwt.signer.service.impl;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
public class JwtSigningAndValidationServiceDefault implements
|
public class JwtSigningAndValidationServiceDefault extends AbstractJwtSigningAndValidationService implements
|
||||||
JwtSigningAndValidationService, InitializingBean {
|
JwtSigningAndValidationService, InitializingBean {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationPropertiesBean configBean;
|
private ConfigurationPropertiesBean configBean;
|
||||||
|
|
||||||
// map of identifier to signer
|
// map of identifier to signer
|
||||||
|
@ -67,7 +67,7 @@ public class JwtSigningAndValidationServiceDefault implements
|
||||||
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet(){
|
||||||
// used for debugging...
|
// used for debugging...
|
||||||
if (!signers.isEmpty()) {
|
if (!signers.isEmpty()) {
|
||||||
logger.info(this.toString());
|
logger.info(this.toString());
|
||||||
|
@ -109,34 +109,6 @@ public class JwtSigningAndValidationServiceDefault implements
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the JwtSigners associated with this service
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Map<String, ? extends JwtSigner> getSigners() {
|
|
||||||
return signers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see
|
|
||||||
* org.mitre.jwt.signer.service.JwtSigningAndValidationService#isJwtExpired
|
|
||||||
* (org.mitre.jwt.model.Jwt)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isJwtExpired(Jwt jwt) {
|
|
||||||
|
|
||||||
Date expiration = jwt.getClaims().getExpiration();
|
|
||||||
|
|
||||||
if (expiration != null)
|
|
||||||
return new Date().after(expiration);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the JwtSigners associated with this service
|
* 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
|
* @return the configBean
|
||||||
*/
|
*/
|
||||||
|
@ -218,4 +141,47 @@ public class JwtSigningAndValidationServiceDefault implements
|
||||||
public void setConfigBean(ConfigurationPropertiesBean configBean) {
|
public void setConfigBean(ConfigurationPropertiesBean configBean) {
|
||||||
this.configBean = 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<String, ? extends JwtSigner> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
if (keystore.size() == 0) {
|
||||||
throw new Exception("Keystore is empty; it has no entries");
|
throw new Exception("Keystore is empty; it has no entries");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<Jwk> retrieveJwk(OIDCServerConfiguration serverConfig){
|
||||||
|
|
||||||
|
List<Jwk> keys = new ArrayList<Jwk>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.openid.connect.client;
|
package org.mitre.openid.connect.config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nemonik
|
* @author nemonik
|
||||||
|
@ -28,6 +28,16 @@ public class OIDCServerConfiguration {
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
|
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
|
private String issuer;
|
||||||
|
|
||||||
|
private String x509EncryptUrl;
|
||||||
|
|
||||||
|
private String x509SigningUrl;
|
||||||
|
|
||||||
|
private String jwkEncryptUrl;
|
||||||
|
|
||||||
|
private String jwkSigningUrl;
|
||||||
|
|
||||||
public String getAuthorizationEndpointURI() {
|
public String getAuthorizationEndpointURI() {
|
||||||
return authorizationEndpointURI;
|
return authorizationEndpointURI;
|
||||||
|
@ -36,6 +46,10 @@ public class OIDCServerConfiguration {
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
|
|
||||||
public String getClientSecret() {
|
public String getClientSecret() {
|
||||||
return clientSecret;
|
return clientSecret;
|
||||||
|
@ -53,6 +67,10 @@ public class OIDCServerConfiguration {
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setIssuer(String issuer) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
}
|
||||||
|
|
||||||
public void setClientSecret(String clientSecret) {
|
public void setClientSecret(String clientSecret) {
|
||||||
this.clientSecret = clientSecret;
|
this.clientSecret = clientSecret;
|
||||||
}
|
}
|
||||||
|
@ -60,13 +78,50 @@ public class OIDCServerConfiguration {
|
||||||
public void setTokenEndpointURI(String tokenEndpointURI) {
|
public void setTokenEndpointURI(String tokenEndpointURI) {
|
||||||
this.tokenEndpointURI = 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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "OIDCServerConfiguration [authorizationEndpointURI="
|
return "OIDCServerConfiguration [authorizationEndpointURI="
|
||||||
+ authorizationEndpointURI + ", tokenEndpointURI="
|
+ authorizationEndpointURI + ", tokenEndpointURI="
|
||||||
+ tokenEndpointURI + ", clientSecret=" + clientSecret
|
+ tokenEndpointURI + ", clientSecret=" + clientSecret
|
||||||
+ ", clientId=" + clientId + "]";
|
+ ", clientId=" + clientId + ", issuer=" + issuer
|
||||||
|
+", x509EncryptedUrl="
|
||||||
|
+ x509EncryptUrl + ", jwkEncryptedUrl="
|
||||||
|
+ jwkEncryptUrl + ", x509SigningUrl="
|
||||||
|
+ x509SigningUrl + ", jwkSigningUrl="
|
||||||
|
+ jwkSigningUrl + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,7 +18,6 @@ package org.mitre.openid.connect.service;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
|
@ -43,4 +43,5 @@ public class Utility {
|
||||||
}
|
}
|
||||||
return issuer;
|
return issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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"}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{"iss":"joe",
|
||||||
|
"user_id":34252452623,
|
||||||
|
"aud":"yolo",
|
||||||
|
"exp":35324583457247,
|
||||||
|
"iat":43215325235,
|
||||||
|
"nonce":"howdy"}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"typ":"JWT",
|
||||||
|
"alg":"HS256"}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"typ":"JWT",
|
||||||
|
"alg":"HS384"}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"typ":"JWT",
|
||||||
|
"alg":"HS512"}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"typ":"JWT",
|
||||||
|
"alg":"none"}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"typ":"JWT",
|
||||||
|
"alg":"RS256"}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"typ":"JWT",
|
||||||
|
"alg":"RS384"}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"typ":"JWT",
|
||||||
|
"alg":"RS512"}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:jwt-signer="http://www.mitre.org/schema/openid-connect/jwt-signer"
|
||||||
|
xsi:schemaLocation=
|
||||||
|
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
|
http://www.mitre.org/schema/openid-connect/jwt-signer http://www.mitre.org/schema/openid-connect/jwt-signer/jwt-signer-1.0.xsd" >
|
||||||
|
|
||||||
|
<!-- Creates an in-memory database populated with test jdbc -->
|
||||||
|
<bean id="dataSource" class="org.mitre.jdbc.datasource.H2DataSourceFactory">
|
||||||
|
<property name="databaseName" value="connect"/>
|
||||||
|
<property name="scriptLocations" >
|
||||||
|
<list>
|
||||||
|
<!-- OpenID Connect Data model -->
|
||||||
|
<value>file:db/tables/accesstoken.sql</value>
|
||||||
|
<value>file:db/tables/address.sql</value>
|
||||||
|
<value>file:db/tables/approvedsite.sql</value>
|
||||||
|
<value>file:db/tables/authorities.sql</value>
|
||||||
|
<value>file:db/tables/clientdetails.sql</value>
|
||||||
|
<value>file:db/tables/event.sql</value>
|
||||||
|
<value>file:db/tables/granttypes.sql</value>
|
||||||
|
<value>file:db/tables/idtoken.sql</value>
|
||||||
|
<value>file:db/tables/idtokenclaims.sql</value>
|
||||||
|
<value>file:db/tables/refreshtoken.sql</value>
|
||||||
|
<value>file:db/tables/scope.sql</value>
|
||||||
|
<value>file:db/tables/userinfo.sql</value>
|
||||||
|
<value>file:db/tables/whitelistedsite.sql</value>
|
||||||
|
<!-- Preloaded data -->
|
||||||
|
<value>classpath:test-data.sql</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<property name="dateConversionPatterns">
|
||||||
|
<map>
|
||||||
|
<entry key="yyyy/mm/dd hh24:mi:ss" value="yyy/MM/dd HH:mm:ss" />
|
||||||
|
<entry key="yyyy-mm-dd" value="yyyy-MM-dd" />
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
|
@ -0,0 +1,6 @@
|
||||||
|
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
|
||||||
|
.
|
||||||
|
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt
|
||||||
|
cGxlLmNvbS9pc19yb290Ijp0cnVlfQ
|
||||||
|
.
|
||||||
|
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
|
|
@ -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-----
|
|
@ -1,9 +1,19 @@
|
||||||
#Wed Jan 04 13:07:35 EST 2012
|
|
||||||
eclipse.preferences.version=1
|
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.inlineJsrBytecode=enabled
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||||
org.eclipse.jdt.core.compiler.compliance=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.assertIdentifier=error
|
||||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
org.eclipse.jdt.core.compiler.source=1.6
|
org.eclipse.jdt.core.compiler.source=1.6
|
||||||
|
org.eclipse.jdt.core.incompatibleJDKLevel=ignore
|
||||||
|
org.eclipse.jdt.core.incompleteClasspath=error
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.launching.PREF_STRICTLY_COMPATIBLE_JRE_NOT_AVAILABLE=warning
|
|
@ -15,12 +15,16 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.openid.connect.token;
|
package org.mitre.openid.connect.token;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||||
import org.mitre.openid.connect.model.IdToken;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
|
@ -32,6 +36,8 @@ import com.google.common.base.Strings;
|
||||||
@Service
|
@Service
|
||||||
public class ConnectTokenEnhancer implements TokenEnhancer {
|
public class ConnectTokenEnhancer implements TokenEnhancer {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(ConnectTokenEnhancer.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationPropertiesBean configBean;
|
private ConfigurationPropertiesBean configBean;
|
||||||
|
|
||||||
|
@ -57,7 +63,12 @@ public class ConnectTokenEnhancer implements TokenEnhancer {
|
||||||
token.getJwt().getClaims().setExpiration(token.getExpiration());
|
token.getJwt().getClaims().setExpiration(token.getExpiration());
|
||||||
|
|
||||||
//TODO: check for client's preferred signer alg and use that
|
//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
|
* Authorization request scope MUST include "openid", but access token request
|
||||||
|
@ -80,7 +91,11 @@ public class ConnectTokenEnhancer implements TokenEnhancer {
|
||||||
// TODO: expiration? other fields?
|
// TODO: expiration? other fields?
|
||||||
|
|
||||||
//TODO: check for client's preferred signer alg and use that
|
//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);
|
token.setIdToken(idToken);
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ public class JwkKeyListView extends AbstractView {
|
||||||
JsonObject o = new JsonObject();
|
JsonObject o = new JsonObject();
|
||||||
|
|
||||||
o.addProperty("use", "sig"); // since we don't do encryption yet
|
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("mod", m64);
|
||||||
o.addProperty("exp", e64);
|
o.addProperty("exp", e64);
|
||||||
o.addProperty("kid", keyId);
|
o.addProperty("kid", keyId);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package org.mitre.openid.connect.web;
|
package org.mitre.openid.connect.web;
|
||||||
|
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||||
|
@ -48,10 +50,10 @@ public class CheckIDEndpoint {
|
||||||
|
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
if (!jwtSignerService.validateSignature(tokenString)) {
|
if (!jwtSignerService.validateSignature(tokenString)) {
|
||||||
// can't validate
|
// can't validate
|
||||||
throw new InvalidJwtSignatureException("The Signature could not be validated.");
|
throw new InvalidJwtSignatureException("The Signature could not be validated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's a valid signature, parse the token
|
// it's a valid signature, parse the token
|
||||||
IdToken token = IdToken.parse(tokenString);
|
IdToken token = IdToken.parse(tokenString);
|
||||||
|
@ -63,9 +65,9 @@ public class CheckIDEndpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the issuer (sanity check)
|
// check the issuer (sanity check)
|
||||||
if (!jwtSignerService.validateIssuedJwt(token, configBean.getIssuer())) {
|
//if (!jwtSignerService.validateIssuedJwt(token, configBean.getIssuer())) {
|
||||||
throw new InvalidJwtIssuerException("The JWT issuer is invalid.");
|
// throw new InvalidJwtIssuerException("The JWT issuer is invalid.");
|
||||||
}
|
//}
|
||||||
|
|
||||||
// pass the claims directly (the view doesn't care about other fields)
|
// pass the claims directly (the view doesn't care about other fields)
|
||||||
return new ModelAndView("jsonIdTokenView", "entity", token.getClaims());
|
return new ModelAndView("jsonIdTokenView", "entity", token.getClaims());
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.mitre.swd.view;
|
package org.mitre.swd.view;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.Map;
|
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)
|
* @see org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel(java.util.Map, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||||
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
|
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -67,7 +68,14 @@ public class XrdJsonResponse extends AbstractView {
|
||||||
|
|
||||||
response.setContentType("application/json");
|
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<String, String> links = (Map<String, String>) model.get("links");
|
Map<String, String> links = (Map<String, String>) model.get("links");
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import static org.junit.Assert.assertThat;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
@ -198,7 +199,7 @@ public class JwtTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToStringPlaintext() {
|
public void testToStringPlaintext() throws NoSuchAlgorithmException {
|
||||||
Jwt jwt = new Jwt();
|
Jwt jwt = new Jwt();
|
||||||
jwt.getHeader().setAlgorithm("none");
|
jwt.getHeader().setAlgorithm("none");
|
||||||
jwt.getClaims().setExpiration(new Date(1300819380L * 1000L));
|
jwt.getClaims().setExpiration(new Date(1300819380L * 1000L));
|
||||||
|
|
Loading…
Reference in New Issue