Skip to content

Commit

Permalink
wip - stub out auth code process
Browse files Browse the repository at this point in the history
  • Loading branch information
fhanik committed Nov 25, 2015
1 parent 76babfb commit f361ee0
Show file tree
Hide file tree
Showing 8 changed files with 369 additions and 86 deletions.
Expand Up @@ -20,14 +20,44 @@


public interface UaaContext { public interface UaaContext {


/**
* Returns true if the context is authenticated and has an access token
* @return true if the context is authenticated and has an access token
*/
boolean hasAccessToken(); boolean hasAccessToken();

/**
* Returns true if the context contains an OpenID Connect id_token.
* The token can be retrieved by {@link CompositeAccessToken#getIdTokenValue()}
* @return true if the context contains an OpenID Connect id_token
*/
boolean hasIdToken(); boolean hasIdToken();

/**
* Returns true if the context has a refresh token
* The token can be retrieved by {@link CompositeAccessToken#getRefreshToken()}
* @return true if the context has a refresh token
*/
boolean hasRefreshToken(); boolean hasRefreshToken();


/**
* Returns the token for this context. A token object will always contain an access token and may
* contain an OpenID Connect id_token and/or a refresh token
* @return the token for this context
*/
CompositeAccessToken getToken(); CompositeAccessToken getToken();


/**
* Returns the token request that was used to acquire the token
* @return the token request that was used to acquire the token
*/
TokenRequest getTokenRequest(); TokenRequest getTokenRequest();


/**
* Returns a {@link org.springframework.security.oauth2.client.OAuth2RestTemplate}
* that has the access token enabled on this object.
* @return the rest template that can be used to invoke UAA APIs
*/
RestTemplate getRestTemplate(); RestTemplate getRestTemplate();




Expand Down
Expand Up @@ -21,10 +21,12 @@
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest; import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer; import org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider; import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails; import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken;
Expand All @@ -40,47 +42,80 @@
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Objects; import java.util.Objects;


import static org.cloudfoundry.identity.client.token.GrantType.AUTHORIZATION_CODE;
import static org.springframework.security.oauth2.common.AuthenticationScheme.header; import static org.springframework.security.oauth2.common.AuthenticationScheme.header;


public class UaaContextFactory { public class UaaContextFactory {


private final URI uaaUri; /**

* UAA Base URI
private UaaContextFactory(URI uaaUri) { */
this.uaaUri = uaaUri; private final URI uaaURI;

/**
* Instantiates a context factory to authenticate against the UAA
* @param uaaURI the UAA base URI
*/
private UaaContextFactory(URI uaaURI) {
this.uaaURI = uaaURI;
} }


private String tokenPath = "/oauth/token"; private String tokenPath = "/oauth/token";
private String authorizePath = "/oauth/authorize"; private String authorizePath = "/oauth/authorize";


/**
* Instantiates a context factory to authenticate against the UAA
* The default token path, /oauth/token, and authorize path, /oauth/authorize are set.
* @param uaaURI the UAA base URI
*/
public static UaaContextFactory factory(URI uaaURI) { public static UaaContextFactory factory(URI uaaURI) {
return new UaaContextFactory(uaaURI); return new UaaContextFactory(uaaURI);
} }


/**
* Sets the token endpoint path. If not invoked, the default is /oauth/token
* @param path the path for the token endpoint.
* @return this mutable object
*/
public UaaContextFactory tokenPath(String path) { public UaaContextFactory tokenPath(String path) {
this.tokenPath = path; this.tokenPath = path;
return this; return this;
} }


/**
* Sets the authorize endpoint path. If not invoked, the default is /oauth/authorize
* @param path the path for the authorize endpoint.
* @return this mutable object
*/
public UaaContextFactory authorizePath(String path) { public UaaContextFactory authorizePath(String path) {
this.authorizePath = path; this.authorizePath = path;
return this; return this;
} }


/**
* Creates a new {@link TokenRequest} object.
* The object will have the token an authorize endpoints already configured.
* @return the new token request that can be used for an access token request.
*/
public TokenRequest tokenRequest() { public TokenRequest tokenRequest() {
UriComponentsBuilder tokenURI = UriComponentsBuilder.newInstance(); UriComponentsBuilder tokenURI = UriComponentsBuilder.newInstance();
tokenURI.uri(uaaUri); tokenURI.uri(uaaURI);
tokenURI.path(tokenPath); tokenURI.path(tokenPath);

UriComponentsBuilder authorizationURI = UriComponentsBuilder.newInstance(); UriComponentsBuilder authorizationURI = UriComponentsBuilder.newInstance();
authorizationURI.uri(uaaUri); authorizationURI.uri(uaaURI);
authorizationURI.path(authorizePath); authorizationURI.path(authorizePath);

return new TokenRequest(tokenURI.build().toUri(), authorizationURI.build().toUri()); return new TokenRequest(tokenURI.build().toUri(), authorizationURI.build().toUri());
} }





/**
* Authenticates the client and optionally the user and retrieves an access token
* @param request - a fully configured token request
* @return an authenticated UAA context with
* @throws NullPointerException if the request object is null
* @throws IllegalArgumentException if the token request is invalid
* @see {@link TokenRequest#isValid()}
*/
public UaaContext authenticate(TokenRequest request) { public UaaContext authenticate(TokenRequest request) {
if (request == null) { if (request == null) {
throw new NullPointerException(TokenRequest.class.getName() + " cannot be null."); throw new NullPointerException(TokenRequest.class.getName() + " cannot be null.");
Expand All @@ -91,10 +126,33 @@ public UaaContext authenticate(TokenRequest request) {
switch (request.getGrantType()) { switch (request.getGrantType()) {
case CLIENT_CREDENTIALS: return authenticateClientCredentials(request); case CLIENT_CREDENTIALS: return authenticateClientCredentials(request);
case PASSWORD: return authenticatePassword(request); case PASSWORD: return authenticatePassword(request);
case AUTHORIZATION_CODE: return authenticateAuthCode(request);
default: throw new UnsupportedGrantTypeException("Not implemented:"+request.getGrantType()); default: throw new UnsupportedGrantTypeException("Not implemented:"+request.getGrantType());
} }
} }


/**
* Not yet implemented
* @param tokenRequest
* @return
*/
protected UaaContext authenticateAuthCode(final TokenRequest tokenRequest) {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setPreEstablishedRedirectUri(tokenRequest.getRedirectUriRedirectUri().toString());
configureResourceDetails(tokenRequest, details);
setClientCredentials(tokenRequest, details);
setRequestScopes(tokenRequest, details);
OAuth2RestTemplate template = new OAuth2RestTemplate(details,new DefaultOAuth2ClientContext());
template.getAccessToken();
throw new UnsupportedOperationException(AUTHORIZATION_CODE +" is not yet implemented");
}


/**
* Performs a {@link org.cloudfoundry.identity.client.token.GrantType#PASSWORD authentication}
* @param tokenRequest - a configured TokenRequest
* @return an authenticated {@link UaaContext}
*/
protected UaaContext authenticatePassword(final TokenRequest tokenRequest) { protected UaaContext authenticatePassword(final TokenRequest tokenRequest) {
ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider() { ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider() {
@Override @Override
Expand All @@ -104,6 +162,19 @@ protected ResponseExtractor<OAuth2AccessToken> getResponseExtractor() {
return new HttpMessageConverterExtractor<OAuth2AccessToken>(CompositeAccessToken.class, Arrays.asList(converter)); return new HttpMessageConverterExtractor<OAuth2AccessToken>(CompositeAccessToken.class, Arrays.asList(converter));
} }
}; };
enhanceForIdTokenRetrieval(tokenRequest, provider);
ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
configureResourceDetails(tokenRequest, details);
setUserCredentials(tokenRequest, details);
setClientCredentials(tokenRequest, details);
setRequestScopes(tokenRequest, details);
OAuth2RestTemplate template = new OAuth2RestTemplate(details,new DefaultOAuth2ClientContext());
template.setAccessTokenProvider(provider);
OAuth2AccessToken token = template.getAccessToken();
return new UaaContextImpl(tokenRequest, template, (CompositeAccessToken) token);
}

protected void enhanceForIdTokenRetrieval(TokenRequest tokenRequest, OAuth2AccessTokenSupport provider) {
provider.setTokenRequestEnhancer( //add id_token to the response type if requested. provider.setTokenRequestEnhancer( //add id_token to the response type if requested.
(AccessTokenRequest request, (AccessTokenRequest request,
OAuth2ProtectedResourceDetails resource, OAuth2ProtectedResourceDetails resource,
Expand All @@ -112,53 +183,67 @@ protected ResponseExtractor<OAuth2AccessToken> getResponseExtractor() {
if (tokenRequest.wantsIdToken()) { if (tokenRequest.wantsIdToken()) {
form.put(OAuth2Utils.RESPONSE_TYPE, Arrays.asList("id_token token")); form.put(OAuth2Utils.RESPONSE_TYPE, Arrays.asList("id_token token"));
} }

} }
); );
ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
details.setUsername(tokenRequest.getUsername());
details.setPassword(tokenRequest.getPassword());
details.setClientId(tokenRequest.getClientId());
details.setClientSecret(tokenRequest.getClientSecret());
if (!Objects.isNull(tokenRequest.getScopes())) {
details.setScope(new LinkedList(tokenRequest.getScopes()));
}
details.setClientAuthenticationScheme(header);
details.setAccessTokenUri(tokenRequest.getTokenEndpoint().toString());
OAuth2RestTemplate template = new OAuth2RestTemplate(details,new DefaultOAuth2ClientContext());
template.setAccessTokenProvider(provider);
OAuth2AccessToken token = template.getAccessToken();
return new UaaContextImpl(tokenRequest, template, (CompositeAccessToken) token);
} }


protected UaaContext authenticateClientCredentials(TokenRequest request) { /**
if (!request.isValid()) { * Performs a {@link org.cloudfoundry.identity.client.token.GrantType#CLIENT_CREDENTIALS authentication}
* @param request - a configured TokenRequest
* @return an authenticated {@link UaaContext}
*/


} protected UaaContext authenticateClientCredentials(TokenRequest request) {
ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails(); ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
details.setClientId(request.getClientId()); configureResourceDetails(request, details);
details.setClientSecret(request.getClientSecret()); setClientCredentials(request, details);
details.setAccessTokenUri(request.getTokenEndpoint().toString()); setRequestScopes(request, details);
details.setClientAuthenticationScheme(header);
OAuth2RestTemplate template = new OAuth2RestTemplate(details,new DefaultOAuth2ClientContext()); OAuth2RestTemplate template = new OAuth2RestTemplate(details,new DefaultOAuth2ClientContext());
OAuth2AccessToken token = template.getAccessToken(); OAuth2AccessToken token = template.getAccessToken();
CompositeAccessToken result = new CompositeAccessToken(token); CompositeAccessToken result = new CompositeAccessToken(token);
return new UaaContextImpl(request, template, result); return new UaaContextImpl(request, template, result);
} }


public static class PasswordTokenRequestEnhancer implements RequestEnhancer { /**
private final TokenRequest request; * Sets the token endpoint on the resource details

* Sets the authentication scheme to be {@link org.springframework.security.oauth2.common.AuthenticationScheme#header}
public PasswordTokenRequestEnhancer(TokenRequest request) { * @param tokenRequest the token request containing the token endpoint
this.request = request; * @param details the details object that will be configured
} */

protected void configureResourceDetails(TokenRequest tokenRequest, BaseOAuth2ProtectedResourceDetails details) {
@Override details.setAuthenticationScheme(header);
public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form, HttpHeaders headers) { details.setAccessTokenUri(tokenRequest.getTokenEndpoint().toString());
}


/**
* Sets the requested scopes on the resource details, if and only if the requested scopes are not null
* @param tokenRequest the token request containing the requested scopes, if any
* @param details the details object that will be configured
*/
protected void setRequestScopes(TokenRequest tokenRequest, BaseOAuth2ProtectedResourceDetails details) {
if (!Objects.isNull(tokenRequest.getScopes())) {
details.setScope(new LinkedList(tokenRequest.getScopes()));
} }
}


/**
* Sets the client_id and client_secret on the resource details object
* @param tokenRequest the token request containing the client_id and client_secret
* @param details the details object that. will be configured
*/
protected void setClientCredentials(TokenRequest tokenRequest, BaseOAuth2ProtectedResourceDetails details) {
details.setClientId(tokenRequest.getClientId());
details.setClientSecret(tokenRequest.getClientSecret());
}


/**
* Sets the username and password on the resource details object
* @param tokenRequest the token request containing the client_id and client_secret
* @param details the details object that. will be configured
*/
protected void setUserCredentials(TokenRequest tokenRequest, ResourceOwnerPasswordResourceDetails details) {
details.setUsername(tokenRequest.getUsername());
details.setPassword(tokenRequest.getPassword());
} }


} }
Expand Up @@ -31,31 +31,49 @@ public UaaContextImpl(TokenRequest request, OAuth2RestTemplate template, Composi
this.token = token; this.token = token;
} }


/**
* {@inheritDoc}
*/
@Override @Override
public boolean hasAccessToken() { public boolean hasAccessToken() {
return token!=null; return token!=null;
} }


/**
* {@inheritDoc}
*/
@Override @Override
public boolean hasIdToken() { public boolean hasIdToken() {
return token!=null && StringUtils.hasText(token.getIdTokenValue()); return token!=null && StringUtils.hasText(token.getIdTokenValue());
} }


/**
* {@inheritDoc}
*/
@Override @Override
public boolean hasRefreshToken() { public boolean hasRefreshToken() {
return token!=null && token.getRefreshToken()!=null; return token!=null && token.getRefreshToken()!=null;
} }


/**
* {@inheritDoc}
*/
@Override @Override
public TokenRequest getTokenRequest() { public TokenRequest getTokenRequest() {
return request; return request;
} }


/**
* {@inheritDoc}
*/
@Override @Override
public RestTemplate getRestTemplate() { public RestTemplate getRestTemplate() {
return template; return template;
} }


/**
* {@inheritDoc}
*/
@Override @Override
public CompositeAccessToken getToken() { public CompositeAccessToken getToken() {
return token; return token;
Expand Down
Expand Up @@ -14,6 +14,9 @@


package org.cloudfoundry.identity.client.token; package org.cloudfoundry.identity.client.token;


/**
* Represent the standard Oauth 2 grant types
*/
public enum GrantType { public enum GrantType {
CLIENT_CREDENTIALS, CLIENT_CREDENTIALS,
PASSWORD, PASSWORD,
Expand Down

This file was deleted.

0 comments on commit f361ee0

Please sign in to comment.