stripped out check id endpoint interaction as it deprecated, refactored nonce checking based on spec change, pull user_id as id_token token claim
parent
901d3afff4
commit
f9558f0955
|
@ -63,9 +63,7 @@ import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The OpenID Connect Authentication Filter
|
* Abstract OpenID Connect Authentication Filter class
|
||||||
*
|
|
||||||
* See README.md to to configure
|
|
||||||
*
|
*
|
||||||
* @author nemonik
|
* @author nemonik
|
||||||
*
|
*
|
||||||
|
@ -74,10 +72,11 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
AbstractAuthenticationProcessingFilter {
|
AbstractAuthenticationProcessingFilter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to remove parameters from a Request before passing it down the chain...
|
* Used to remove parameters from a Request before passing it down the
|
||||||
|
* chain...
|
||||||
*
|
*
|
||||||
* @author nemonik
|
* @author nemonik
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class SanatizedRequest extends HttpServletRequestWrapper {
|
class SanatizedRequest extends HttpServletRequestWrapper {
|
||||||
|
|
||||||
|
@ -128,8 +127,8 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
return super.getParameterValues(name);
|
return super.getParameterValues(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final static int HTTP_SOCKET_TIMEOUT = 30000;
|
protected final static int HTTP_SOCKET_TIMEOUT = 30000;
|
||||||
protected final static String SCOPE = "openid";
|
protected final static String SCOPE = "openid";
|
||||||
protected final static int KEY_SIZE = 1024;
|
protected final static int KEY_SIZE = 1024;
|
||||||
|
@ -154,7 +153,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
List<String> ignore = (ignoreFields != null) ? Arrays
|
List<String> ignore = (ignoreFields != null) ? Arrays
|
||||||
.asList(ignoreFields) : null;
|
.asList(ignoreFields) : null;
|
||||||
|
|
||||||
boolean isFirst = true;
|
boolean isFirst = true;
|
||||||
|
|
||||||
StringBuffer sb = request.getRequestURL();
|
StringBuffer sb = request.getRequestURL();
|
||||||
|
@ -360,8 +359,10 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
HttpServletResponse response) throws AuthenticationException,
|
HttpServletResponse response) throws AuthenticationException,
|
||||||
IOException, ServletException {
|
IOException, ServletException {
|
||||||
|
|
||||||
logger.debug("Request: " + request.getRequestURI() + (StringUtils.isNotBlank(request.getQueryString()) ? "?"
|
logger.debug("Request: "
|
||||||
+ request.getQueryString() : "") );
|
+ request.getRequestURI()
|
||||||
|
+ (StringUtils.isNotBlank(request.getQueryString()) ? "?"
|
||||||
|
+ request.getQueryString() : ""));
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -399,6 +400,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
// ((DefaultHttpClient)
|
// ((DefaultHttpClient)
|
||||||
// httpClient).getCredentialsProvider().setCredentials(AuthScope.ANY,
|
// httpClient).getCredentialsProvider().setCredentials(AuthScope.ANY,
|
||||||
// credentials);
|
// credentials);
|
||||||
|
//
|
||||||
|
|
||||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
|
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
|
||||||
httpClient);
|
httpClient);
|
||||||
|
@ -438,6 +440,8 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
"Unable to obtain Access Token.");
|
"Unable to obtain Access Token.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("from TokenEndpoint jsonString = " + jsonString);
|
||||||
|
|
||||||
JsonElement jsonRoot = new JsonParser().parse(jsonString);
|
JsonElement jsonRoot = new JsonParser().parse(jsonString);
|
||||||
|
|
||||||
if (jsonRoot.getAsJsonObject().get("error") != null) {
|
if (jsonRoot.getAsJsonObject().get("error") != null) {
|
||||||
|
@ -455,8 +459,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Extract the id_token to insert into the
|
// Extract the id_token
|
||||||
// OpenIdConnectAuthenticationToken
|
|
||||||
|
|
||||||
IdToken idToken = null;
|
IdToken idToken = null;
|
||||||
|
|
||||||
|
@ -504,54 +507,22 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
throw new AuthenticationServiceException(
|
throw new AuthenticationServiceException(
|
||||||
"Token Endpoint did not return a token_id");
|
"Token Endpoint did not return a token_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Check ID Endpoint interaction
|
// Clients are required to compare nonce claim in ID token to
|
||||||
|
// the nonce sent in the Authorization request. The client
|
||||||
httpClient = new DefaultHttpClient();
|
// stores this value as a signed session cookie to detect a
|
||||||
|
// replay by third parties.
|
||||||
httpClient.getParams().setParameter("http.socket.timeout",
|
//
|
||||||
new Integer(httpSocketTimeout));
|
// See: OpenID Connect Messages
|
||||||
|
//
|
||||||
factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
// Specifically, Section 2.1.1 entitled "ID Token"
|
||||||
restTemplate = new RestTemplate(factory);
|
//
|
||||||
|
// http://openid.net/specs/openid-connect-messages-1_0.html#id_token
|
||||||
form = new LinkedMultiValueMap<String, String>();
|
//
|
||||||
|
// Read the paragraph describing "nonce". Required w/ implicit flow.
|
||||||
form.add("access_token", jsonRoot.getAsJsonObject().get("id_token")
|
//
|
||||||
.getAsString());
|
|
||||||
|
String nonce = idToken.getClaims().getNonce();
|
||||||
jsonString = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
jsonString = restTemplate.postForObject(
|
|
||||||
serverConfig.getCheckIDEndpointURI(), form,
|
|
||||||
String.class);
|
|
||||||
} catch (HttpClientErrorException httpClientErrorException) {
|
|
||||||
|
|
||||||
// Handle error
|
|
||||||
|
|
||||||
logger.error("Check ID Endpoint error response: "
|
|
||||||
+ httpClientErrorException.getStatusText() + " : "
|
|
||||||
+ httpClientErrorException.getMessage());
|
|
||||||
|
|
||||||
throw new AuthenticationServiceException("Unable check token.");
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonRoot = new JsonParser().parse(jsonString);
|
|
||||||
|
|
||||||
// String iss = jsonRoot.getAsJsonObject().get("iss")
|
|
||||||
// .getAsString();
|
|
||||||
String userId = jsonRoot.getAsJsonObject().get("user_id")
|
|
||||||
.getAsString();
|
|
||||||
// String aud = jsonRoot.getAsJsonObject().get("aud")
|
|
||||||
// .getAsString();
|
|
||||||
String nonce = jsonRoot.getAsJsonObject().get("nonce")
|
|
||||||
.getAsString();
|
|
||||||
// String exp = jsonRoot.getAsJsonObject().get("exp")
|
|
||||||
// .getAsString();
|
|
||||||
|
|
||||||
// Compare returned ID Token to signed session cookie
|
|
||||||
// to detect ID Token replay by third parties.
|
|
||||||
|
|
||||||
Cookie nonceSignatureCookie = WebUtils.getCookie(request,
|
Cookie nonceSignatureCookie = WebUtils.getCookie(request,
|
||||||
NONCE_SIGNATURE_COOKIE_NAME);
|
NONCE_SIGNATURE_COOKIE_NAME);
|
||||||
|
@ -572,8 +543,7 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
"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
|
+ NONCE_SIGNATURE_COOKIE_NAME + " failed.");
|
||||||
+ " failed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -587,16 +557,19 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
logger.error(NONCE_SIGNATURE_COOKIE_NAME
|
logger.error(NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found.");
|
||||||
+ " 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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an Authentication object for the token, and
|
|
||||||
// return.
|
|
||||||
|
|
||||||
|
// pull the user_id out as a claim on the id_token
|
||||||
|
|
||||||
|
String userId = idToken.getTokenClaims().getUserId();
|
||||||
|
|
||||||
|
// construct an OpenIdConnectAuthenticationToken and return
|
||||||
|
// a Authentication object w/
|
||||||
|
|
||||||
OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(
|
OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(
|
||||||
userId, idToken);
|
userId, idToken);
|
||||||
|
|
||||||
|
@ -704,4 +677,4 @@ public class AbstractOIDCAuthenticationFilter extends
|
||||||
public void setScope(String scope) {
|
public void setScope(String scope) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,10 +64,7 @@ public class OIDCAuthenticationFilter extends AbstractOIDCAuthenticationFilter {
|
||||||
|
|
||||||
Assert.notNull(oidcServerConfig.getTokenEndpointURI(),
|
Assert.notNull(oidcServerConfig.getTokenEndpointURI(),
|
||||||
"A Token ID Endpoint URI must be supplied");
|
"A Token ID Endpoint URI must be supplied");
|
||||||
|
|
||||||
Assert.notNull(oidcServerConfig.getCheckIDEndpointURI(),
|
|
||||||
"A Check ID Endpoint URI must be supplied");
|
|
||||||
|
|
||||||
Assert.notNull(oidcServerConfig.getClientId(),
|
Assert.notNull(oidcServerConfig.getClientId(),
|
||||||
"A Client ID must be supplied");
|
"A Client ID must be supplied");
|
||||||
|
|
||||||
|
@ -113,10 +110,6 @@ public class OIDCAuthenticationFilter extends AbstractOIDCAuthenticationFilter {
|
||||||
oidcServerConfig.setAuthorizationEndpointURI(authorizationEndpointURI);
|
oidcServerConfig.setAuthorizationEndpointURI(authorizationEndpointURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCheckIDEndpointURI(String checkIDEndpointURI) {
|
|
||||||
oidcServerConfig.setCheckIDEndpointURI(checkIDEndpointURI);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientId(String clientId) {
|
public void setClientId(String clientId) {
|
||||||
oidcServerConfig.setClientId(clientId);
|
oidcServerConfig.setClientId(clientId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,8 +129,7 @@ public class OIDCAuthenticationUsingChooserFilter extends
|
||||||
// The Client is configured to support this Issuer
|
// The Client is configured to support this Issuer
|
||||||
// Identifier
|
// Identifier
|
||||||
|
|
||||||
Cookie issuerCookie = new Cookie(ISSUER_COOKIE_NAME,
|
Cookie issuerCookie = new Cookie(ISSUER_COOKIE_NAME, issuer);
|
||||||
issuer);
|
|
||||||
response.addCookie(issuerCookie);
|
response.addCookie(issuerCookie);
|
||||||
|
|
||||||
handleAuthorizationRequest(new SanatizedRequest(request,
|
handleAuthorizationRequest(new SanatizedRequest(request,
|
||||||
|
@ -157,7 +156,7 @@ public class OIDCAuthenticationUsingChooserFilter extends
|
||||||
urlVariables.put("redirect_uri",
|
urlVariables.put("redirect_uri",
|
||||||
OIDCAuthenticationUsingChooserFilter.buildRedirectURI(
|
OIDCAuthenticationUsingChooserFilter.buildRedirectURI(
|
||||||
request, null));
|
request, null));
|
||||||
|
|
||||||
urlVariables.put("client_id", accountChooserClientID);
|
urlVariables.put("client_id", accountChooserClientID);
|
||||||
|
|
||||||
response.sendRedirect(OIDCAuthenticationUsingChooserFilter
|
response.sendRedirect(OIDCAuthenticationUsingChooserFilter
|
||||||
|
|
|
@ -25,8 +25,6 @@ public class OIDCServerConfiguration {
|
||||||
|
|
||||||
private String tokenEndpointURI;
|
private String tokenEndpointURI;
|
||||||
|
|
||||||
private String checkIDEndpointURI;
|
|
||||||
|
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
|
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
@ -35,10 +33,6 @@ public class OIDCServerConfiguration {
|
||||||
return authorizationEndpointURI;
|
return authorizationEndpointURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCheckIDEndpointURI() {
|
|
||||||
return checkIDEndpointURI;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return clientId;
|
return clientId;
|
||||||
}
|
}
|
||||||
|
@ -49,16 +43,12 @@ public class OIDCServerConfiguration {
|
||||||
|
|
||||||
public String getTokenEndpointURI() {
|
public String getTokenEndpointURI() {
|
||||||
return tokenEndpointURI;
|
return tokenEndpointURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthorizationEndpointURI(String authorizationEndpointURI) {
|
public void setAuthorizationEndpointURI(String authorizationEndpointURI) {
|
||||||
this.authorizationEndpointURI = authorizationEndpointURI;
|
this.authorizationEndpointURI = authorizationEndpointURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCheckIDEndpointURI(String checkIDEndpointURI) {
|
|
||||||
this.checkIDEndpointURI = checkIDEndpointURI;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClientId(String clientId) {
|
public void setClientId(String clientId) {
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
}
|
}
|
||||||
|
@ -75,9 +65,8 @@ public class OIDCServerConfiguration {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "OIDCServerConfiguration [authorizationEndpointURI="
|
return "OIDCServerConfiguration [authorizationEndpointURI="
|
||||||
+ authorizationEndpointURI + ", tokenEndpointURI="
|
+ authorizationEndpointURI + ", tokenEndpointURI="
|
||||||
+ tokenEndpointURI + ", checkIDEndpointURI="
|
+ tokenEndpointURI + ", clientSecret=" + clientSecret
|
||||||
+ checkIDEndpointURI + ", clientSecret=" + clientSecret
|
|
||||||
+ ", clientId=" + clientId + "]";
|
+ ", clientId=" + clientId + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -27,7 +27,7 @@ import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nemonik
|
* @author nemonik
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class OpenIdConnectAuthenticationProvider implements
|
public class OpenIdConnectAuthenticationProvider implements
|
||||||
AuthenticationProvider, InitializingBean {
|
AuthenticationProvider, InitializingBean {
|
||||||
|
|
|
@ -24,10 +24,9 @@ import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* @author nemonik
|
* @author nemonik
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class OpenIdConnectAuthenticationToken extends
|
public class OpenIdConnectAuthenticationToken extends
|
||||||
AbstractAuthenticationToken {
|
AbstractAuthenticationToken {
|
||||||
|
@ -37,42 +36,48 @@ public class OpenIdConnectAuthenticationToken extends
|
||||||
private final String userId;
|
private final String userId;
|
||||||
|
|
||||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Constructs OpenIdConnectAuthenticationToken provided
|
||||||
|
*
|
||||||
* @param principle
|
* @param principle
|
||||||
* @param authorities
|
* @param authorities
|
||||||
* @param userId
|
* @param userId
|
||||||
* @param idToken
|
* @param idToken
|
||||||
*/
|
*/
|
||||||
public OpenIdConnectAuthenticationToken(Object principle,
|
public OpenIdConnectAuthenticationToken(Object principle,
|
||||||
Collection<? extends GrantedAuthority> authorities,
|
Collection<? extends GrantedAuthority> authorities, String userId,
|
||||||
String userId, IdToken idToken) {
|
IdToken idToken) {
|
||||||
|
|
||||||
super(authorities);
|
super(authorities);
|
||||||
|
|
||||||
this.principle = principle;
|
this.principle = principle;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.idToken = idToken;
|
this.idToken = idToken;
|
||||||
|
|
||||||
setAuthenticated(true);
|
setAuthenticated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Constructs OpenIdConnectAuthenticationToken provided
|
||||||
|
*
|
||||||
* @param idToken
|
* @param idToken
|
||||||
* @param userId
|
* @param userId
|
||||||
*/
|
*/
|
||||||
public OpenIdConnectAuthenticationToken(String userId, IdToken idToken) {
|
public OpenIdConnectAuthenticationToken(String userId, IdToken idToken) {
|
||||||
|
|
||||||
super(new ArrayList<GrantedAuthority>(0));
|
super(new ArrayList<GrantedAuthority>(0));
|
||||||
|
|
||||||
this.principle = userId;
|
this.principle = userId;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.idToken = idToken;
|
this.idToken = idToken;
|
||||||
|
|
||||||
setAuthenticated(false);
|
setAuthenticated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
* @see org.springframework.security.core.Authentication#getCredentials()
|
* @see org.springframework.security.core.Authentication#getCredentials()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,7 +89,9 @@ public class OpenIdConnectAuthenticationToken extends
|
||||||
return idToken;
|
return idToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
* @see org.springframework.security.core.Authentication#getPrincipal()
|
* @see org.springframework.security.core.Authentication#getPrincipal()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,4 +103,4 @@ public class OpenIdConnectAuthenticationToken extends
|
||||||
public String getUserId() {
|
public String getUserId() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,17 +1,11 @@
|
||||||
<?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">
|
<wb-module deploy-name="openid">
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
|
||||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
|
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
|
||||||
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
||||||
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
||||||
<dependent-module archiveName="spring-security-oauth2-1.0.0.BUILD-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/spring-security-oauth2/spring-security-oauth2">
|
<property name="java-output-path" value="/openid/target/classes"/>
|
||||||
<dependency-type>uses</dependency-type>
|
<property name="context-root" value="openid-connect-server"/>
|
||||||
</dependent-module>
|
</wb-module>
|
||||||
<dependent-module archiveName="openid-connect-common-0.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/openid-connect-common/openid-connect-common">
|
</project-modules>
|
||||||
<dependency-type>uses</dependency-type>
|
|
||||||
</dependent-module>
|
|
||||||
<property name="java-output-path" value="/openid/target/classes"/>
|
|
||||||
<property name="context-root" value="openid-connect-server"/>
|
|
||||||
</wb-module>
|
|
||||||
</project-modules>
|
|
||||||
|
|
Loading…
Reference in New Issue