/*
* *****************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
* *****************************************************************************
*/
package org.cloudfoundry.identity.client.integration;
import org.cloudfoundry.identity.client.UaaContext;
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.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
import org.springframework.web.client.HttpClientErrorException;
import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import static org.cloudfoundry.identity.client.integration.ClientIntegrationTestUtilities.UAA_URI;
import static org.cloudfoundry.identity.client.token.GrantType.AUTHORIZATION_CODE;
import static org.cloudfoundry.identity.client.token.GrantType.AUTHORIZATION_CODE_WITH_TOKEN;
import static org.cloudfoundry.identity.client.token.GrantType.FETCH_TOKEN_FROM_CODE;
import static org.cloudfoundry.identity.client.token.GrantType.PASSWORD;
import static org.cloudfoundry.identity.client.token.GrantType.PASSWORD_WITH_PASSCODE;
import static org.cloudfoundry.identity.client.token.GrantType.SAML2_BEARER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class ClientAPITokenIntegrationTest {
public static String uaaURI = UAA_URI;
private UaaContextFactory factory;
private RandomValueStringGenerator generator = new RandomValueStringGenerator();
@Rule
public IsUAAListeningRule uaaListeningRule = new IsUAAListeningRule(uaaURI, false);
@Before
public void setUp() throws Exception {
factory =
UaaContextFactory.factory(new URI(uaaURI))
.authorizePath("/oauth/authorize")
.tokenPath("/oauth/token");
}
@Test
public void test_admin_client_token() throws Exception {
TokenRequest clientCredentials = factory.tokenRequest()
.setClientId("admin")
.setClientSecret("adminsecret")
.setGrantType(GrantType.CLIENT_CREDENTIALS);
UaaContext context = factory.authenticate(clientCredentials);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertFalse(context.hasIdToken());
assertFalse(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("uaa.admin"));
}
@Test
public void test_password_token_without_id_token() throws Exception {
UaaContext context = retrievePasswordToken(null);
assertTrue(context.getToken().getScope().contains("openid"));
}
protected UaaContext retrievePasswordToken(Collection<String> scopes) {
TokenRequest passwordGrant = factory.tokenRequest()
.setClientId("cf")
.setClientSecret("")
.setGrantType(PASSWORD)
.setUsername("marissa")
.setPassword("koala")
.setScopes(scopes);
UaaContext context = factory.authenticate(passwordGrant);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertFalse(context.hasIdToken());
assertTrue(context.hasRefreshToken());
return context;
}
@Test
public void test_password_token_with_id_token() throws Exception {
TokenRequest passwordGrant = factory.tokenRequest()
.setClientId("cf")
.setClientSecret("")
.setGrantType(PASSWORD)
.setUsername("marissa")
.setPassword("koala")
.withIdToken()
.setScopes(Arrays.asList("openid"));
UaaContext context = factory.authenticate(passwordGrant);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertTrue(context.hasIdToken());
assertTrue(context.hasRefreshToken());
}
protected void performPasswordGrant(String clientId,
String clientSecret,
GrantType grantType,
String username,
String password) {
TokenRequest passwordGrant = factory.tokenRequest()
.withIdToken()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setGrantType(grantType)
.setUsername(username);
switch (grantType) {
case PASSWORD:
passwordGrant.setPassword(password);
break;
case PASSWORD_WITH_PASSCODE:
passwordGrant.setPasscode(password);
break;
default:
throw new IllegalArgumentException("Invalid grant:"+grantType);
}
UaaContext context = factory.authenticate(passwordGrant);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertTrue(context.hasIdToken());
assertTrue(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("openid"));
}
@Test
public void test_password_token_with_passcode() throws Exception {
HttpHeaders headers = ClientIntegrationTestUtilities.performFormLogin(uaaURI, "marissa", "koala");
String passcode = ClientIntegrationTestUtilities.getPasscode(uaaURI, headers);
performPasswordGrant("cf",
"",
PASSWORD_WITH_PASSCODE,
"marissa",
passcode);
}
@Test
public void test_fetch_token_from_authorization_code() throws Exception {
test_fetch_token_from_authorization_code(factory, uaaURI, false, false, "login", "loginsecret", "http://localhost/redirect");
}
@Test
public void test_fetch_token_from_authorization_code_with_id_token() throws Exception {
test_fetch_token_from_authorization_code(factory, uaaURI, true, false, "login", "loginsecret", "http://localhost/redirect");
}
public static void test_fetch_token_from_authorization_code(UaaContextFactory factory,
String uaaURI,
boolean idToken,
boolean skipSslValidation,
String clientId,
String clientSecret,
String redirectUri) throws Exception {
HttpHeaders headers = ClientIntegrationTestUtilities.performFormLogin(uaaURI, "marissa", "koala");
String code = ClientIntegrationTestUtilities.getAuthorizationCode(
factory.getAuthorizeUri().toString(),
clientId,
redirectUri,
headers
);
TokenRequest fetchTokenRequest = factory.tokenRequest()
.setGrantType(FETCH_TOKEN_FROM_CODE)
.setRedirectUri(new URI(redirectUri))
.setClientId(clientId)
.setClientSecret(clientSecret)
.setAuthorizationCode(code);
if (idToken) {
fetchTokenRequest.withIdToken();
}
if (skipSslValidation) {
fetchTokenRequest.setSkipSslValidation(true);
}
UaaContext context = factory.authenticate(fetchTokenRequest);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertEquals(idToken, context.hasIdToken());
assertTrue(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("openid"));
}
@Test
@Ignore("test_auth_code_token_with_id_token ignored - No UI/browser implementation yet") //until we have decided if we want to be able to do this without a UI
public void test_auth_code_token_with_id_token() throws Exception {
TokenRequest authorizationCode = factory.tokenRequest()
.withIdToken()
.setGrantType(AUTHORIZATION_CODE)
.setRedirectUri(new URI("http://localhost/redirect"))
.setState(generator.generate())
.setScopes(Collections.singleton("openid"))
.setClientId("app")
.setClientSecret("appclientsecret")
.setUsername("marissa")
.setPassword("koala");
UaaContext context = factory.authenticate(authorizationCode);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertFalse(context.hasIdToken());
assertTrue(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("openid"));
}
@Test
@Ignore("test_auth_code_token_without_id_token ignred - No UI/browser implementation yet") //until we have decided if we want to be able to do this without a UI
public void test_auth_code_token_without_id_token() throws Exception {
TokenRequest authorizationCode = factory.tokenRequest()
.setGrantType(AUTHORIZATION_CODE)
.setRedirectUri(new URI("http://localhost/redirect"))
.setState(generator.generate())
.setScopes(Collections.singleton("openid"))
.setClientId("app")
.setClientSecret("appclientsecret")
.setUsername("marissa")
.setPassword("koala");
UaaContext context = factory.authenticate(authorizationCode);
assertNotNull(context);
assertTrue(context.hasAccessToken());
assertFalse(context.hasIdToken());
assertTrue(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("openid"));
}
@Test
public void test_auth_code_token_using_api() throws Exception {
UaaContext passwordContext = retrievePasswordToken(Arrays.asList("uaa.user"));
assertTrue(passwordContext.getToken().getScope().contains("uaa.user"));
TokenRequest authorizationCode = factory.tokenRequest()
.setGrantType(AUTHORIZATION_CODE_WITH_TOKEN)
.setRedirectUri(new URI("http://localhost:8080/app/"))
.setState(generator.generate())
.setClientId("app")
.setClientSecret("appclientsecret")
.setScopes(Arrays.asList("openid"))
.setAuthCodeAPIToken(passwordContext.getToken().getValue());
UaaContext context = factory.authenticate(authorizationCode);
assertNotNull(context);
assertTrue(context.hasAccessToken());
//we receive an id_token because we request 'openid' explicitly
assertTrue(context.hasIdToken());
assertTrue(context.hasRefreshToken());
assertTrue(context.getToken().getScope().contains("openid"));
}
@Test
public void test_saml2_bearer_using_api() throws Exception {
UaaContext passwordContext = retrievePasswordToken(Arrays.asList("uaa.user"));
assertTrue(passwordContext.getToken().getScope().contains("uaa.user"));
TokenRequest saml2Code = factory.tokenRequest()
.setGrantType(SAML2_BEARER)
.setRedirectUri(new URI("http://localhost:8080/app/"))
.setClientId("app")
.setClientSecret("appclientsecret")
.setScopes(Arrays.asList("openid"))
.setAuthCodeAPIToken(passwordContext.getToken().getValue());
try {
factory.authenticate(saml2Code);
} catch(HttpClientErrorException he) {}
}
}