/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2016] 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.uaa.integration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.cloudfoundry.identity.uaa.ServerRunning;
import org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils;
import org.cloudfoundry.identity.uaa.oauth.UaaTokenServices;
import org.cloudfoundry.identity.uaa.scim.ScimGroup;
import org.cloudfoundry.identity.uaa.scim.ScimGroupMember;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
import org.cloudfoundry.identity.uaa.security.web.CookieBasedCsrfTokenRepository;
import org.cloudfoundry.identity.uaa.test.TestAccountSetup;
import org.cloudfoundry.identity.uaa.test.UaaTestAccounts;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
import org.springframework.security.oauth2.client.test.OAuth2ContextConfiguration;
import org.springframework.security.oauth2.client.test.OAuth2ContextSetup;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.cloudfoundry.identity.uaa.integration.util.IntegrationTestUtils.getHeaders;
import static org.cloudfoundry.identity.uaa.security.web.CookieBasedCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.security.oauth2.common.util.OAuth2Utils.USER_OAUTH_APPROVAL;
@OAuth2ContextConfiguration(OAuth2ContextConfiguration.ClientCredentials.class)
public class ScimGroupEndpointsIntegrationTests {
private ScimGroupMember DALE, JOEL, VIDYA;
private final String DELETE_ME = "deleteme_" + new RandomValueStringGenerator().generate().toLowerCase();
private final String CF_DEV = "cf_dev_" + new RandomValueStringGenerator().generate().toLowerCase();
private final String CF_MGR = "cf_mgr_" + new RandomValueStringGenerator().generate().toLowerCase();
private final String CFID = "cfid_" + new RandomValueStringGenerator().generate().toLowerCase();
private final String groupEndpoint = "/Groups";
private final String userEndpoint = "/Users";
private List<String> groupIds = new ArrayList<String>();
private final Log logger = LogFactory.getLog(getClass());
private static final List<String> defaultGroups = Arrays.asList("openid", "scim.me", "cloud_controller.read",
"cloud_controller.write", "password.write", "scim.userids", "uaa.user", "approvals.me",
"oauth.approvals", "cloud_controller_service_permissions.read", "profile", "roles", "user_attributes", UaaTokenServices.UAA_REFRESH_TOKEN);
@Rule
public ServerRunning serverRunning = ServerRunning.isRunning();
private UaaTestAccounts testAccounts = UaaTestAccounts.standard(serverRunning);
@Rule
public OAuth2ContextSetup context = OAuth2ContextSetup.withTestAccounts(serverRunning, testAccounts);
@Rule
public TestAccountSetup testAccountSetup = TestAccountSetup.standard(serverRunning, testAccounts);
private RestTemplate client;
@Before
public void createRestTemplate() throws Exception {
client = (RestTemplate)serverRunning.getRestTemplate();
client.setErrorHandler(new OAuth2ErrorHandler(context.getResource()) {
// Pass errors through in response entity for status code analysis
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
}
});
JOEL = new ScimGroupMember(createUser("joel_" + new RandomValueStringGenerator().generate().toLowerCase(), "Passwo3d").getId());
DALE = new ScimGroupMember(createUser("dale_" + new RandomValueStringGenerator().generate().toLowerCase(), "Passwo3d").getId());
VIDYA = new ScimGroupMember(createUser("vidya_" + new RandomValueStringGenerator().generate().toLowerCase(), "Passwo3d").getId());
}
@After
public void tearDown() {
deleteResource(userEndpoint, DALE.getMemberId());
deleteResource(userEndpoint, JOEL.getMemberId());
deleteResource(userEndpoint, VIDYA.getMemberId());
for (String id : groupIds) {
deleteResource(groupEndpoint, id);
}
}
@SuppressWarnings("rawtypes")
private ResponseEntity<Map> deleteResource(String url, String id) {
HttpHeaders headers = new HttpHeaders();
headers.add("If-Match", "*");
return client.exchange(serverRunning.getUrl(url + "/{id}"), HttpMethod.DELETE, new HttpEntity<Void>(headers),
Map.class, id);
}
private ScimUser createUser(String username, String password) {
ScimUser user = new ScimUser();
user.setUserName(username);
user.setName(new ScimUser.Name(username, username));
user.addEmail(username);
user.setVerified(true);
user.setPassword(password);
ResponseEntity<ScimUser> result = client.postForEntity(serverRunning.getUrl(userEndpoint), user, ScimUser.class);
assertEquals(HttpStatus.CREATED, result.getStatusCode());
return result.getBody();
}
private ScimGroup createGroup(String name, ScimGroupMember... members) {
ScimGroup g = new ScimGroup(null,name,IdentityZoneHolder.get().getId());
List<ScimGroupMember> m = members != null ? Arrays.asList(members) : Collections.<ScimGroupMember> emptyList();
g.setMembers(m);
ScimGroup g1 = client.postForEntity(serverRunning.getUrl(groupEndpoint), g, ScimGroup.class).getBody();
assertEquals(name, g1.getDisplayName());
assertEquals(m.size(), g1.getMembers().size());
groupIds.add(g1.getId());
return g1;
}
private ScimGroup updateGroup(String id, String name, ScimGroupMember... members) {
HttpHeaders headers = new HttpHeaders();
headers.add("If-Match", "*");
ScimGroup g = new ScimGroup(null,name,IdentityZoneHolder.get().getId());
List<ScimGroupMember> m = members != null ? Arrays.asList(members) : Collections.<ScimGroupMember> emptyList();
g.setMembers(m);
@SuppressWarnings("rawtypes")
ResponseEntity<Map> r = client.exchange(serverRunning.getUrl(groupEndpoint + "/{id}"), HttpMethod.PUT,
new HttpEntity<>(g, headers), Map.class, id);
logger.warn(r.getBody());
ScimGroup g1 = client.exchange(serverRunning.getUrl(groupEndpoint + "/{id}"), HttpMethod.PUT,
new HttpEntity<>(g, headers), ScimGroup.class, id).getBody();
assertEquals(name, g1.getDisplayName());
assertEquals(m.size(), g1.getMembers().size());
return g1;
}
private void validateUserGroups(String id, String... groups) {
List<String> groupNames = groups != null ? Arrays.asList(groups) : Collections.<String> emptyList();
assertEquals(groupNames.size() + defaultGroups.size(), getUser(id).getGroups().size());
for (ScimUser.Group g : getUser(id).getGroups()) {
assertTrue(defaultGroups.contains(g.getDisplay()) || groupNames.contains(g.getDisplay()));
}
}
private ScimUser getUser(String id) {
return client.getForEntity(serverRunning.getUrl(userEndpoint + "/{id}"), ScimUser.class, id).getBody();
}
@Test
public void getGroupsWithoutAttributesReturnsAllData() {
@SuppressWarnings("rawtypes")
ResponseEntity<Map> response = client.getForEntity(serverRunning.getUrl(groupEndpoint), Map.class);
@SuppressWarnings("rawtypes")
Map results = response.getBody();
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue("There should be more than zero users", (Integer) results.get("totalResults") > 0);
assertTrue("There should be some resources", ((Collection<?>) results.get("resources")).size() > 0);
@SuppressWarnings("rawtypes")
Map firstGroup = (Map) ((List) results.get("resources")).get(0);
assertTrue(firstGroup.containsKey("id"));
assertTrue(firstGroup.containsKey("displayName"));
assertTrue(firstGroup.containsKey("schemas"));
assertTrue(firstGroup.containsKey("meta"));
}
@Test
public void createGroupSucceeds() throws Exception {
ScimGroup g1 = createGroup(CFID);
// Check we can GET the group
ScimGroup g2 = client.getForObject(serverRunning.getUrl(groupEndpoint + "/{id}"), ScimGroup.class, g1.getId());
assertEquals(g1, g2);
}
@Test
public void createGroupWithMembersSucceeds() {
ScimGroup g1 = createGroup(CFID, JOEL, DALE, VIDYA);
// Check we can GET the group
ScimGroup g2 = client.getForObject(serverRunning.getUrl(groupEndpoint + "/{id}"), ScimGroup.class, g1.getId());
assertEquals(g1, g2);
assertEquals(3, g2.getMembers().size());
assertTrue(g2.getMembers().contains(JOEL));
assertTrue(g2.getMembers().contains(DALE));
assertTrue(g2.getMembers().contains(VIDYA));
// check that User.groups is updated
validateUserGroups(JOEL.getMemberId(), CFID);
validateUserGroups(DALE.getMemberId(), CFID);
validateUserGroups(VIDYA.getMemberId(), CFID);
}
@Test
public void createGroupWithInvalidMembersFailsCorrectly() {
ScimGroup g = new ScimGroup(null, CFID, IdentityZoneHolder.get().getId());
ScimGroupMember m2 = new ScimGroupMember("wrongid");
g.setMembers(Arrays.asList(VIDYA, m2));
@SuppressWarnings("rawtypes")
ResponseEntity<Map> r = client.postForEntity(serverRunning.getUrl(groupEndpoint), g, Map.class);
@SuppressWarnings("unchecked")
Map<String, String> g1 = r.getBody();
assertEquals(HttpStatus.BAD_REQUEST, r.getStatusCode());
assertTrue(g1.containsKey("error"));
assertTrue(g1.containsKey("message"));
assertTrue(g1.get("message").contains("Invalid group member"));
// check that the group was not created
@SuppressWarnings("unchecked")
Map<String, String> g2 = client.getForObject(
serverRunning.getUrl(groupEndpoint + "?filter=displayName eq \"{name}\""), Map.class, CFID);
assertTrue(g2.containsKey("totalResults"));
assertEquals(0, g2.get("totalResults"));
}
@Test
public void createGroupWithMemberGroupSucceeds() {
ScimGroup g1 = createGroup(CFID, VIDYA);
ScimGroupMember m2 = new ScimGroupMember(g1.getId(), ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_MEMBER);
ScimGroup g2 = createGroup(CF_DEV, m2);
// Check we can GET the group
ScimGroup g3 = client.getForObject(serverRunning.getUrl(groupEndpoint + "/{id}"), ScimGroup.class, g2.getId());
assertEquals(g2, g3);
assertEquals(1, g3.getMembers().size());
assertTrue(g3.getMembers().contains(m2));
// check that User.groups is updated
validateUserGroups(VIDYA.getMemberId(), CFID, CF_DEV);
}
@Test
public void createExistingGroupFailsCorrectly() {
ScimGroup g1 = createGroup(CFID);
@SuppressWarnings("unchecked")
Map<String, String> g2 = client.postForEntity(serverRunning.getUrl(groupEndpoint), g1, Map.class).getBody();
assertTrue(g2.containsKey("error"));
assertEquals("scim_resource_already_exists", g2.get("error"));
}
@Test
public void deleteGroupUpdatesUser() {
ScimGroup g1 = createGroup(DELETE_ME, DALE, VIDYA);
validateUserGroups(DALE.getMemberId(), DELETE_ME);
validateUserGroups(VIDYA.getMemberId(), DELETE_ME);
deleteResource(groupEndpoint, g1.getId());
// check that the group does not exist anymore
@SuppressWarnings("unchecked")
Map<String, Object> g2 = client.getForObject(
serverRunning.getUrl(groupEndpoint + "?filter=displayName eq \"{name}\""), Map.class, DELETE_ME);
assertTrue(g2.containsKey("totalResults"));
assertEquals(0, g2.get("totalResults"));
// check that group membership is updated
validateUserGroups(DALE.getMemberId());
validateUserGroups(VIDYA.getMemberId());
}
@Test
public void deleteNonExistentGroupFailsCorrectly() {
@SuppressWarnings("unchecked")
Map<String, Object> g = deleteResource(groupEndpoint, DELETE_ME).getBody();
assertTrue(g.containsKey("error"));
assertEquals("scim_resource_not_found", g.get("error"));
}
@Test
public void deleteMemberGroupUpdatesGroup() {
ScimGroup g1 = createGroup(CFID, VIDYA);
ScimGroupMember m2 = new ScimGroupMember(g1.getId(), ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_MEMBER);
ScimGroup g2 = createGroup(CF_DEV, DALE, m2);
assertTrue(g2.getMembers().contains(m2));
validateUserGroups(VIDYA.getMemberId(), CFID, CF_DEV);
deleteResource(groupEndpoint, g1.getId());
// check that parent group is updated
ScimGroup g3 = client.getForObject(serverRunning.getUrl(groupEndpoint + "/{id}"), ScimGroup.class, g2.getId());
assertEquals(1, g3.getMembers().size());
assertFalse(g3.getMembers().contains(m2));
}
@Test
public void testDeleteMemberUserUpdatesGroups() {
ScimGroupMember toDelete = new ScimGroupMember(createUser(DELETE_ME, "Passwo3d").getId());
ScimGroup g1 = createGroup(CFID, JOEL, DALE, toDelete);
ScimGroup g2 = createGroup(CF_MGR, DALE, toDelete);
deleteResource(userEndpoint, toDelete.getMemberId());
// check that membership has been updated
ScimGroup g3 = client.getForObject(serverRunning.getUrl(groupEndpoint + "/{id}"), ScimGroup.class, g1.getId());
assertEquals(2, g3.getMembers().size());
assertFalse(g3.getMembers().contains(toDelete));
g3 = client.getForObject(serverRunning.getUrl(groupEndpoint + "/{id}"), ScimGroup.class, g2.getId());
assertEquals(1, g3.getMembers().size());
assertFalse(g3.getMembers().contains(toDelete));
}
@Test
public void testUpdateGroupUpdatesMemberUsers() {
ScimGroup g1 = createGroup(CFID, JOEL, VIDYA);
ScimGroup g2 = createGroup(CF_MGR, DALE);
ScimGroupMember m1 = new ScimGroupMember(g1.getId(), ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_MEMBER);
ScimGroupMember m2 = new ScimGroupMember(g2.getId(), ScimGroupMember.Type.GROUP, ScimGroupMember.GROUP_MEMBER);
ScimGroup g3 = createGroup(CF_DEV, m1, m2);
validateUserGroups(JOEL.getMemberId(), CFID, CF_DEV);
validateUserGroups(VIDYA.getMemberId(), CFID, CF_DEV);
validateUserGroups(DALE.getMemberId(), CF_MGR, CF_DEV);
ScimGroup g4 = updateGroup(g3.getId(), "new_name", m1);
// check that we did not create a new group, but only updated the
// existing one
assertEquals(g3, g4);
// check that member users were updated
validateUserGroups(DALE.getMemberId(), CF_MGR);
validateUserGroups(JOEL.getMemberId(), CFID, "new_name");
validateUserGroups(VIDYA.getMemberId(), CFID, "new_name");
}
@Test
public void testAccessTokenReflectsGroupMembership() throws Exception {
createTestClient(DELETE_ME, "secret", CFID);
ScimUser user = createUser(DELETE_ME, "Passwo3d");
createGroup(CFID, new ScimGroupMember(user.getId()));
OAuth2AccessToken token = getAccessToken(DELETE_ME, "secret", DELETE_ME, "Passwo3d");
assertTrue("Wrong token: " + token, token.getScope().contains(CFID));
deleteTestClient(DELETE_ME);
deleteResource(userEndpoint, user.getId());
}
@Test
public void testAccessTokenReflectsGroupMembershipForPasswordGrant() throws Exception {
createTestClient(DELETE_ME, "secret", CFID);
ScimUser user = createUser(DELETE_ME, "Passwo3d");
createGroup(CFID, new ScimGroupMember(user.getId()));
OAuth2AccessToken token = getAccessTokenWithPassword(DELETE_ME, "secret", DELETE_ME, "Passwo3d");
assertTrue("Wrong token: " + token, token.getScope().contains(CFID));
deleteTestClient(DELETE_ME);
deleteResource(userEndpoint, user.getId());
}
private void createTestClient(String name, String secret, String scope) throws Exception {
OAuth2AccessToken token = getClientCredentialsAccessToken("clients.read,clients.write,clients.admin");
HttpHeaders headers = getAuthenticatedHeaders(token);
BaseClientDetails client = new BaseClientDetails(name, "", scope, "authorization_code,password",
"scim.read,scim.write","http://redirect.uri");
client.setClientSecret(secret);
ResponseEntity<Void> result = serverRunning.getRestTemplate().exchange(serverRunning.getUrl("/oauth/clients"),
HttpMethod.POST, new HttpEntity<BaseClientDetails>(client, headers), Void.class);
assertEquals(HttpStatus.CREATED, result.getStatusCode());
}
private void deleteTestClient(String clientId) throws Exception {
OAuth2AccessToken token = getClientCredentialsAccessToken("clients.read,clients.write");
HttpHeaders headers = getAuthenticatedHeaders(token);
ResponseEntity<Void> result = serverRunning.getRestTemplate().exchange(
serverRunning.getUrl("/oauth/clients/{client}"), HttpMethod.DELETE,
new HttpEntity<Void>(headers),
Void.class, clientId);
assertEquals(HttpStatus.OK, result.getStatusCode());
}
private OAuth2AccessToken getClientCredentialsAccessToken(String scope) throws Exception {
String clientId = testAccounts.getAdminClientId();
String clientSecret = testAccounts.getAdminClientSecret();
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("grant_type", "client_credentials");
formData.add("client_id", clientId);
formData.add("scope", scope);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.set("Authorization",
"Basic " + new String(Base64.encode(String.format("%s:%s", clientId, clientSecret).getBytes())));
@SuppressWarnings("rawtypes")
ResponseEntity<Map> response = serverRunning.postForMap("/oauth/token", formData, headers);
assertEquals(HttpStatus.OK, response.getStatusCode());
@SuppressWarnings("unchecked")
OAuth2AccessToken accessToken = DefaultOAuth2AccessToken.valueOf(response.getBody());
return accessToken;
}
private HttpHeaders getAuthenticatedHeaders(OAuth2AccessToken token) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + token.getValue());
return headers;
}
private OAuth2AccessToken getAccessTokenWithPassword(String clientId, String clientSecret, String username,
String password) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("client_id", clientId);
formData.add("grant_type", "password");
formData.add("username", username);
formData.add("password", password);
HttpHeaders tokenHeaders = new HttpHeaders();
tokenHeaders.set("Authorization", testAccounts.getAuthorizationHeader(clientId, clientSecret));
@SuppressWarnings("rawtypes")
ResponseEntity<Map> tokenResponse = serverRunning.postForMap("/oauth/token", formData, tokenHeaders);
assertEquals(HttpStatus.OK, tokenResponse.getStatusCode());
@SuppressWarnings("unchecked")
OAuth2AccessToken accessToken = DefaultOAuth2AccessToken.valueOf(tokenResponse.getBody());
return accessToken;
}
private OAuth2AccessToken getAccessToken(String clientId, String clientSecret, String username, String password) throws URISyntaxException {
BasicCookieStore cookies = new BasicCookieStore();
URI uri = serverRunning.buildUri("/oauth/authorize").queryParam("response_type", "code")
.queryParam("state", "mystateid").queryParam("client_id", clientId)
.queryParam("redirect_uri", "http://redirect.uri").build();
ResponseEntity<Void> result = serverRunning.createRestTemplate().exchange(
uri.toString(), HttpMethod.GET, new HttpEntity<>(null, getHeaders(cookies)),
Void.class);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
String location = result.getHeaders().getLocation().toString();
if (result.getHeaders().containsKey("Set-Cookie")) {
for (String cookie : result.getHeaders().get("Set-Cookie")) {
int nameLength = cookie.indexOf('=');
cookies.addCookie(new BasicClientCookie(cookie.substring(0, nameLength), cookie.substring(nameLength+1)));
}
}
ResponseEntity<String> response = serverRunning.getForString(location, getHeaders(cookies));
// should be directed to the login screen...
assertTrue(response.getBody().contains("/login.do"));
assertTrue(response.getBody().contains("username"));
assertTrue(response.getBody().contains("password"));
if (response.getHeaders().containsKey("Set-Cookie")) {
String cookie = response.getHeaders().getFirst("Set-Cookie");
int nameLength = cookie.indexOf('=');
cookies.addCookie(new BasicClientCookie(cookie.substring(0, nameLength), cookie.substring(nameLength+1)));
}
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("username", username);
formData.add("password", password);
formData.add(CookieBasedCsrfTokenRepository.DEFAULT_CSRF_COOKIE_NAME, IntegrationTestUtils.extractCookieCsrf(response.getBody()));
// Should be redirected to the original URL, but now authenticated
result = serverRunning.postForResponse("/login.do", getHeaders(cookies), formData);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
cookies.clear();
if (result.getHeaders().containsKey("Set-Cookie")) {
for (String cookie : result.getHeaders().get("Set-Cookie")) {
int nameLength = cookie.indexOf('=');
cookies.addCookie(new BasicClientCookie(cookie.substring(0, nameLength), cookie.substring(nameLength+1)));
}
}
response = serverRunning.createRestTemplate().exchange(
new URI(result.getHeaders().getLocation().toString()),
HttpMethod.GET,
new HttpEntity<>(null, getHeaders(cookies)),
String.class);
if (response.getHeaders().containsKey("Set-Cookie")) {
for (String cookie : response.getHeaders().get("Set-Cookie")) {
int nameLength = cookie.indexOf('=');
cookies.addCookie(new BasicClientCookie(cookie.substring(0, nameLength), cookie.substring(nameLength+1)));
}
}
if (response.getStatusCode() == HttpStatus.OK) {
// The grant access page should be returned
assertTrue(response.getBody().contains("<h1>Application Authorization</h1>"));
formData.clear();
formData.add(DEFAULT_CSRF_COOKIE_NAME, IntegrationTestUtils.extractCookieCsrf(response.getBody()));
formData.add(USER_OAUTH_APPROVAL, "true");
formData.add("scope.0", "scope." + CFID);
result = serverRunning.postForResponse("/oauth/authorize", getHeaders(cookies), formData);
assertEquals(HttpStatus.FOUND, result.getStatusCode());
location = result.getHeaders().getLocation().toString();
}
else {
// Token cached so no need for second approval
assertEquals(HttpStatus.FOUND, response.getStatusCode());
location = response.getHeaders().getLocation().toString();
}
assertTrue("Wrong location: " + location, location.matches("http://redirect.uri" + ".*code=.+"));
formData.clear();
formData.add("client_id", clientId);
formData.add("redirect_uri", "http://redirect.uri");
formData.add("grant_type", "authorization_code");
formData.add("code", location.split("code=")[1].split("&")[0]);
HttpHeaders tokenHeaders = new HttpHeaders();
tokenHeaders.set("Authorization", testAccounts.getAuthorizationHeader(clientId, clientSecret));
@SuppressWarnings("rawtypes")
ResponseEntity<Map> tokenResponse = serverRunning.postForMap("/oauth/token", formData, tokenHeaders);
assertEquals(HttpStatus.OK, tokenResponse.getStatusCode());
@SuppressWarnings("unchecked")
OAuth2AccessToken accessToken = DefaultOAuth2AccessToken.valueOf(tokenResponse.getBody());
return accessToken;
}
}