Skip to content

Commit

Permalink
Implement password grant
Browse files Browse the repository at this point in the history
  • Loading branch information
fhanik committed Nov 25, 2015
1 parent f4a58c4 commit 8f556f6
Show file tree
Hide file tree
Showing 8 changed files with 377 additions and 134 deletions.
Expand Up @@ -17,15 +17,30 @@

import org.cloudfoundry.identity.client.token.TokenRequest;
import org.cloudfoundry.identity.uaa.oauth.token.CompositeAccessToken;
import org.springframework.http.HttpHeaders;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;
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.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpMessageConverterExtractor;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Objects;

import static org.springframework.security.oauth2.common.AuthenticationScheme.header;

public class UaaContextFactory {

Expand Down Expand Up @@ -70,22 +85,72 @@ public UaaContext authenticate(TokenRequest request) {
if (request == null) {
throw new NullPointerException(TokenRequest.class.getName() + " cannot be null.");
}
if (!request.isValid()) {
throw new IllegalArgumentException("Invalid token request.");
}
switch (request.getGrantType()) {
case CLIENT_CREDENTIALS: return authenticateClientCredentials(request);
case PASSWORD: return authenticatePassword(request);
default: throw new UnsupportedGrantTypeException("Not implemented:"+request.getGrantType());
}
}

protected UaaContext authenticatePassword(TokenRequest request) {
ResourceOwnerPasswordAccessTokenProvider provider = new ResourceOwnerPasswordAccessTokenProvider() {
@Override
protected ResponseExtractor<OAuth2AccessToken> getResponseExtractor() {
getRestTemplate(); // force initialization
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
return new HttpMessageConverterExtractor<OAuth2AccessToken>(CompositeAccessToken.class, Arrays.asList(converter));
}
};
provider.setTokenRequestEnhancer(new PasswordTokenRequestEnhancer(request));
ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
details.setUsername(request.getUsername());
details.setPassword(request.getPassword());
details.setClientId(request.getClientId());
details.setClientSecret(request.getClientSecret());
if (!Objects.isNull(request.getScopes())) {
details.setScope(new LinkedList(request.getScopes()));
}
details.setClientAuthenticationScheme(header);
details.setAccessTokenUri(request.getTokenEndpoint().toString());
OAuth2RestTemplate template = new OAuth2RestTemplate(details,new DefaultOAuth2ClientContext());
template.setAccessTokenProvider(provider);
OAuth2AccessToken token = template.getAccessToken();
return new UaaContextImpl(request, template, (CompositeAccessToken) token);
}

protected UaaContext authenticateClientCredentials(TokenRequest request) {
if (!request.isValid()) {

}
ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
details.setClientId(request.getClientId());
details.setClientSecret(request.getClientSecret());
details.setAccessTokenUri(request.getTokenEndpoint().toString());
details.setClientAuthenticationScheme(AuthenticationScheme.header);
details.setClientAuthenticationScheme(header);
OAuth2RestTemplate template = new OAuth2RestTemplate(details,new DefaultOAuth2ClientContext());
OAuth2AccessToken token = template.getAccessToken();
CompositeAccessToken result = new CompositeAccessToken(token);
return new UaaContextImpl(request, template, result);
}

public static class PasswordTokenRequestEnhancer implements RequestEnhancer {
private final TokenRequest request;

public PasswordTokenRequestEnhancer(TokenRequest request) {
this.request = request;
}

@Override
public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form, HttpHeaders headers) {
if (this.request.wantsIdToken()) {
form.put(OAuth2Utils.RESPONSE_TYPE, Arrays.asList("id_token token"));
}
}


}

}
Expand Up @@ -19,5 +19,5 @@ public enum GrantType {
PASSWORD,
IMPLICIT,
AUTHORIZATION_CODE,
REFRESH
REFRESH_TOKEN
}
Expand Up @@ -15,23 +15,58 @@
package org.cloudfoundry.identity.client.token;

import java.net.URI;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
* A token request contains all the information needed to retrieve a token from the UAA.
*
*/
public class TokenRequest {

private GrantType grantType;
private String clientId;
private String clientSecret;
private String username;
private String password;
private Set<String> scopes;
private URI tokenEndpoint;
private URI authorizationEndpoint;
private boolean idToken = false;

public TokenRequest(URI tokenEndpoint, URI authorizationEndpoint) {
this.tokenEndpoint = tokenEndpoint;
}

public boolean isValid() {
return false;
if (grantType==null) {
return false;
}
switch (grantType) {
case CLIENT_CREDENTIALS:
return !isNull(
Arrays.asList(
tokenEndpoint,
clientId,
clientSecret
)
);
case PASSWORD:
return !isNull(
Arrays.asList(
tokenEndpoint,
clientId,
clientSecret,
username,
password
)
);
default: return false;
}
}

public URI getTokenEndpoint() {
Expand Down Expand Up @@ -96,4 +131,29 @@ public TokenRequest setAuthorizationEndpoint(URI authorizationEndpoint) {
this.authorizationEndpoint = authorizationEndpoint;
return this;
}

public TokenRequest withIdToken() {
idToken = true;
return this;
}

public boolean wantsIdToken() {
return idToken;
}

public TokenRequest setScopes(Collection<String> scopes) {
this.scopes = scopes==null ? null : new HashSet<>(scopes);
return this;
}

public Set<String> getScopes() {
return scopes;
}

protected boolean isNull(List<Object> objects) {
if (Objects.isNull(objects)) {
return true;
}
return objects.stream().filter(o -> Objects.isNull(o)).count() > 0;
}
}
Expand Up @@ -19,6 +19,7 @@
import org.cloudfoundry.identity.client.UaaContextFactory;
import org.cloudfoundry.identity.client.token.GrantType;
import org.cloudfoundry.identity.client.token.TokenRequest;
import org.junit.Before;
import org.junit.Test;

import java.net.URI;
Expand All @@ -27,17 +28,22 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

public class ClientCredentialsTokenIntegrationTest {
public class ClientAPITokenIntegrationTest {

public static String uaaURI = "http://localhost:8080/uaa";

@Test
public void test_admin_client_token() throws Exception {
UaaContextFactory factory =
private UaaContextFactory factory;

@Before
public void setUp() throws Exception {
factory =
UaaContextFactory.factory(new URI(uaaURI))
.authorizePath("/oauth/authorize")
.tokenPath("/oauth/token");
.authorizePath("/oauth/authorize")
.tokenPath("/oauth/token");
}

@Test
public void test_admin_client_token() throws Exception {
TokenRequest request = factory.tokenRequest()
.setClientId("admin")
.setClientSecret("adminsecret")
Expand All @@ -51,4 +57,40 @@ public void test_admin_client_token() throws Exception {
assertTrue(context.getToken().getScope().contains("uaa.admin"));
}

@Test
public void test_password_token_no_id_token() throws Exception {
TokenRequest request = factory.tokenRequest()
.setClientId("cf")
.setClientSecret("")
.setGrantType(GrantType.PASSWORD)
.setUsername("marissa")
.setPassword("koala");

UaaContext context = factory.authenticate(request);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertFalse(context.hasIdToken());
assertTrue(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("openid"));
}

@Test
public void test_password_token_with_id_token() throws Exception {
TokenRequest request = factory.tokenRequest()
.withIdToken()
.setClientId("cf")
.setClientSecret("")
.setGrantType(GrantType.PASSWORD)
.setUsername("marissa")
.setPassword("koala");

UaaContext context = factory.authenticate(request);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertTrue(context.hasIdToken());
assertTrue(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("openid"));
}


}
Expand Up @@ -17,16 +17,51 @@
import org.junit.Before;
import org.junit.Test;

import java.net.URI;
import java.util.Arrays;

import static java.util.Collections.EMPTY_LIST;
import static org.cloudfoundry.identity.client.token.GrantType.CLIENT_CREDENTIALS;
import static org.cloudfoundry.identity.client.token.GrantType.PASSWORD;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;


public class TokenRequestTest {

private TokenRequest request;

@Before
public void setUp() throws Exception {
URI turi = new URI("http://localhost:8080/uaa/oauth/token");
URI auri = new URI("http://localhost:8080/uaa/oauth/authorize");
request = new TokenRequest(turi, auri);
}

@Test
public void test_is_client_credentials_grant_valid() throws Exception {
assertFalse(request.isValid());
assertFalse(request.setGrantType(CLIENT_CREDENTIALS).isValid());
assertFalse(request.setClientId("client_id").isValid());
assertTrue(request.setClientSecret("client_secret").isValid());
}

@Test
public void testIsValid() throws Exception {
public void test_is_password_grant_valid() throws Exception {
assertFalse(request.isValid());
assertFalse(request.setGrantType(PASSWORD).isValid());
assertFalse(request.setClientId("client_id").isValid());
assertFalse(request.setClientSecret("client_secret").isValid());
assertFalse(request.setUsername("username").isValid());
assertTrue(request.setPassword("password").isValid());
}


@Test
public void test_is_null_function() {
assertTrue(request.isNull(null));
assertFalse(request.isNull(EMPTY_LIST));
assertTrue(request.isNull(Arrays.asList("1",null,"2")));
assertFalse(request.isNull(Arrays.asList("1","2","3")));
}
}

0 comments on commit 8f556f6

Please sign in to comment.