integration changes to client
parent
1a1ae4c5b5
commit
b8c953281e
|
@ -10,8 +10,10 @@ import java.security.KeyPairGenerator;
|
|||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Signature;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
|
@ -21,14 +23,13 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.mitre.openid.connect.model.IdToken;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
|
@ -85,9 +86,6 @@ import com.google.gson.JsonParser;
|
|||
public class OpenIdConnectAuthenticationFilter extends
|
||||
AbstractAuthenticationProcessingFilter {
|
||||
|
||||
private static Log logger = LogFactory
|
||||
.getLog(OpenIdConnectAuthenticationFilter.class);
|
||||
|
||||
private final static int HTTP_SOCKET_TIMEOUT = 30000;
|
||||
private final static String SCOPE = "openid";
|
||||
private final static int KEY_SIZE = 1024;
|
||||
|
@ -259,9 +257,18 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
}
|
||||
|
||||
// prepend the spec necessary scope
|
||||
setScope(SCOPE + ((scope != null && !scope.isEmpty()) ? " " + scope : ""));
|
||||
setScope((scope != null && !scope.isEmpty()) ? SCOPE + " " + scope
|
||||
: SCOPE);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.security.web.authentication.
|
||||
* AbstractAuthenticationProcessingFilter
|
||||
* #attemptAuthentication(javax.servlet.http.HttpServletRequest,
|
||||
* javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -275,6 +282,8 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
HttpServletResponse response) throws AuthenticationException,
|
||||
IOException, ServletException {
|
||||
|
||||
final boolean debug = logger.isDebugEnabled();
|
||||
|
||||
if (request.getParameter("error") != null) {
|
||||
|
||||
// Handle Authorization Endpoint error
|
||||
|
@ -313,10 +322,12 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
httpClient.getParams().setParameter("http.socket.timeout",
|
||||
new Integer(httpSocketTimeout));
|
||||
|
||||
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
|
||||
clientId, clientSecret);
|
||||
((DefaultHttpClient) httpClient).getCredentialsProvider()
|
||||
.setCredentials(AuthScope.ANY, credentials);
|
||||
//
|
||||
// TODO: basic auth is untested (it wasn't working last I tested)
|
||||
// UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
|
||||
// clientId, clientSecret);
|
||||
// ((DefaultHttpClient) httpClient).getCredentialsProvider()
|
||||
// .setCredentials(AuthScope.ANY, credentials);
|
||||
|
||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
|
||||
httpClient);
|
||||
|
@ -326,7 +337,18 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||
form.add("grant_type", "authorization_code");
|
||||
form.add("code", authorizationGrant);
|
||||
form.add("redirect_uri", buildRedirectURI(request));
|
||||
form.add("redirect_uri",
|
||||
buildRedirectURI(request, new String[] { "code" }));
|
||||
|
||||
// pass clientId and clientSecret in post of request
|
||||
form.add("client_id", clientId);
|
||||
form.add("client_secret", clientSecret);
|
||||
|
||||
|
||||
if (debug) {
|
||||
logger.debug("tokenEndpointURI = " + tokenEndpointURI);
|
||||
logger.debug("form = " + form);
|
||||
}
|
||||
|
||||
String jsonString = null;
|
||||
|
||||
|
@ -341,7 +363,8 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
+ httpClientErrorException.getStatusText() + " : "
|
||||
+ httpClientErrorException.getMessage());
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(
|
||||
"Unable to obtain Access Token.");
|
||||
}
|
||||
|
||||
JsonElement jsonRoot = new JsonParser().parse(jsonString);
|
||||
|
@ -355,7 +378,9 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
|
||||
logger.error("Token Endpoint returned: " + error);
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(
|
||||
"Unable to obtain Access Token. Token Endpoint returned: "
|
||||
+ error);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -376,7 +401,8 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
logger.error("Problem parsing id_token: " + e);
|
||||
// e.printStackTrace();
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(
|
||||
"Problem parsing id_token return from Token endpoint: " + e);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -385,7 +411,8 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
|
||||
logger.error("Token Endpoint did not return a token_id");
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(
|
||||
"Token Endpoint did not return a token_id");
|
||||
}
|
||||
|
||||
// Handle Check ID Endpoint interaction
|
||||
|
@ -418,7 +445,8 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
+ httpClientErrorException.getStatusText()
|
||||
+ " : " + httpClientErrorException.getMessage());
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(
|
||||
"Unable check token.");
|
||||
}
|
||||
|
||||
jsonRoot = new JsonParser().parse(jsonString);
|
||||
|
@ -453,14 +481,20 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
+ NONCE_SIGNATURE_COOKIE_NAME
|
||||
+ " failed.");
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(
|
||||
"Possible replay attack detected! "
|
||||
+ "The comparison of the nonce in the returned "
|
||||
+ "ID Token to the signed session "
|
||||
+ NONCE_SIGNATURE_COOKIE_NAME
|
||||
+ " failed.");
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.error(NONCE_SIGNATURE_COOKIE_NAME
|
||||
+ " was found, but was null or empty.");
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME
|
||||
+ " was found, but was null or empty.");
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -468,14 +502,15 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
logger.error(NONCE_SIGNATURE_COOKIE_NAME
|
||||
+ " cookie was not found.");
|
||||
|
||||
return null;
|
||||
throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME
|
||||
+ " cookie was not found.");
|
||||
}
|
||||
|
||||
// Create an Authentication object for the token, and
|
||||
// return.
|
||||
|
||||
OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(
|
||||
idToken, userId);
|
||||
userId, idToken);
|
||||
|
||||
Authentication authentication = this
|
||||
.getAuthenticationManager().authenticate(token);
|
||||
|
@ -495,7 +530,8 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
urlVariables.put("response_type", "code");
|
||||
urlVariables.put("client_id", clientId);
|
||||
urlVariables.put("scope", scope);
|
||||
urlVariables.put("redirect_uri", buildRedirectURI(request));
|
||||
urlVariables.put("redirect_uri",
|
||||
buildRedirectURI(request, null));
|
||||
|
||||
// Create a string value used to associate a user agent session
|
||||
// with an ID Token to mitigate replay attacks. The value is
|
||||
|
@ -530,9 +566,15 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
*
|
||||
* @param request
|
||||
* the current request which is being processed by this filter
|
||||
* @return The redirect_uri.
|
||||
* @param ingoreParameters
|
||||
* an array of parameter names to ignore.
|
||||
* @return
|
||||
*/
|
||||
private String buildRedirectURI(HttpServletRequest request) {
|
||||
private String buildRedirectURI(HttpServletRequest request,
|
||||
String[] ingoreParameters) {
|
||||
|
||||
List<String> ignore = (ingoreParameters != null) ? Arrays
|
||||
.asList(ingoreParameters) : null;
|
||||
|
||||
boolean isFirst = true;
|
||||
|
||||
|
@ -542,22 +584,25 @@ public class OpenIdConnectAuthenticationFilter extends
|
|||
.hasMoreElements();) {
|
||||
|
||||
String name = (String) e.nextElement();
|
||||
// Assume for simplicity that there is only one value
|
||||
String value = request.getParameter(name);
|
||||
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
if ((ignore == null) || (!ignore.contains(name))) {
|
||||
// Assume for simplicity that there is only one value
|
||||
String value = request.getParameter(name);
|
||||
|
||||
if (isFirst) {
|
||||
sb.append("?");
|
||||
isFirst = false;
|
||||
}
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sb.append(name).append("=").append(value);
|
||||
if (isFirst) {
|
||||
sb.append("?");
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
if (e.hasMoreElements()) {
|
||||
sb.append("&");
|
||||
sb.append(name).append("=").append(value);
|
||||
|
||||
if (e.hasMoreElements()) {
|
||||
sb.append("&");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,22 @@ import org.springframework.beans.factory.InitializingBean;
|
|||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author mjwalsh
|
||||
*
|
||||
*/
|
||||
public class OpenIdConnectAuthenticationProvider implements
|
||||
AuthenticationProvider, InitializingBean {
|
||||
|
||||
private AuthenticationUserDetailsService<OpenIdConnectAuthenticationToken> userDetailsService;
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -16,7 +28,8 @@ public class OpenIdConnectAuthenticationProvider implements
|
|||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
Assert.notNull(this.userDetailsService,
|
||||
"The userDetailsService must be set");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -26,16 +39,40 @@ public class OpenIdConnectAuthenticationProvider implements
|
|||
* authenticate(org.springframework.security.core.Authentication)
|
||||
*/
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
public Authentication authenticate(final Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
|
||||
if (!supports(authentication.getClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (authentication instanceof OpenIdConnectAuthenticationToken) {
|
||||
return authentication;
|
||||
|
||||
OpenIdConnectAuthenticationToken token = (OpenIdConnectAuthenticationToken) authentication;
|
||||
|
||||
UserDetails userDetails = userDetailsService.loadUserDetails(token);
|
||||
|
||||
return new OpenIdConnectAuthenticationToken(userDetails,
|
||||
authoritiesMapper.mapAuthorities(userDetails
|
||||
.getAuthorities()), token.getUserId(),
|
||||
token.getIdToken());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authoritiesMapper
|
||||
*/
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(
|
||||
AuthenticationUserDetailsService<OpenIdConnectAuthenticationToken> userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
@ -48,5 +85,4 @@ public class OpenIdConnectAuthenticationProvider implements
|
|||
return OpenIdConnectAuthenticationToken.class
|
||||
.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.mitre.openid.connect.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.openid.connect.model.IdToken;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
|
@ -16,25 +17,46 @@ import org.springframework.security.core.SpringSecurityCoreVersion;
|
|||
public class OpenIdConnectAuthenticationToken extends
|
||||
AbstractAuthenticationToken {
|
||||
|
||||
private final Object principle;
|
||||
private final IdToken idToken;
|
||||
private final String userId;
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
/**
|
||||
* @param principle
|
||||
* @param authorities
|
||||
* @param userId
|
||||
* @param idToken
|
||||
*/
|
||||
public OpenIdConnectAuthenticationToken(Object principle,
|
||||
Collection<? extends GrantedAuthority> authorities,
|
||||
String userId, IdToken idToken) {
|
||||
|
||||
super(authorities);
|
||||
|
||||
this.principle = principle;
|
||||
this.userId = userId;
|
||||
this.idToken = idToken;
|
||||
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param idToken
|
||||
* @param userId
|
||||
*/
|
||||
public OpenIdConnectAuthenticationToken(IdToken idToken, String userId) {
|
||||
public OpenIdConnectAuthenticationToken(String userId, IdToken idToken) {
|
||||
|
||||
super(new ArrayList<GrantedAuthority>(0));
|
||||
this.idToken = idToken;
|
||||
this.userId = userId;
|
||||
|
||||
// what do I set for the principle? the idToken?
|
||||
|
||||
setAuthenticated(true);
|
||||
}
|
||||
|
||||
this.principle = userId;
|
||||
this.userId = userId;
|
||||
this.idToken = idToken;
|
||||
|
||||
setAuthenticated(false);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.core.Authentication#getCredentials()
|
||||
*/
|
||||
|
@ -53,12 +75,10 @@ public class OpenIdConnectAuthenticationToken extends
|
|||
@Override
|
||||
public Object getPrincipal() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return principle;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue