Skip to content

Commit

Permalink
Allow default zone user to switch zone using subdomain header
Browse files Browse the repository at this point in the history
  • Loading branch information
mbhave committed Nov 20, 2015
1 parent 0371c69 commit 88d6fe2
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 50 deletions.
Expand Up @@ -43,7 +43,7 @@ public IdentityZoneSwitchingFilter(IdentityZoneProvisioning dao) {


private final IdentityZoneProvisioning dao; private final IdentityZoneProvisioning dao;
public static final String HEADER = "X-Identity-Zone-Id"; public static final String HEADER = "X-Identity-Zone-Id";

public static final String SUBDOMAIN_HEADER = "X-Identity-Zone-Subdomain";
public static final String ZONE_ID_MATCH = "{zone_id}"; public static final String ZONE_ID_MATCH = "{zone_id}";
public static final String ZONES_ZONE_ID_PREFIX = "zones." ; public static final String ZONES_ZONE_ID_PREFIX = "zones." ;
public static final String ZONES_ZONE_ID_ADMIN = ZONES_ZONE_ID_PREFIX + ZONE_ID_MATCH + "."+ "admin"; public static final String ZONES_ZONE_ID_ADMIN = ZONES_ZONE_ID_PREFIX + ZONE_ID_MATCH + "."+ "admin";
Expand Down Expand Up @@ -148,35 +148,51 @@ protected String[] getZoneSwitchingScopes(String identityZoneId) {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {


String identityZoneId = request.getHeader(HEADER);
if (StringUtils.hasText(identityZoneId)) { String identityZoneIdFromHeader = request.getHeader(HEADER);
if (!isAuthorizedToSwitchToIdentityZone(identityZoneId)) { String identityZoneSubDomain = request.getHeader(SUBDOMAIN_HEADER);
response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not authorized to switch to IdentityZone with id "+identityZoneId);
return; if (StringUtils.isEmpty(identityZoneIdFromHeader) && StringUtils.isEmpty(identityZoneSubDomain)) {
}
IdentityZone originalIdentityZone = IdentityZoneHolder.get();
try {

IdentityZone identityZone = null;
try {
identityZone = dao.retrieve(identityZoneId);
} catch (ZoneDoesNotExistsException ex) {
} catch (EmptyResultDataAccessException ex) {
} catch (Exception ex) {
throw ex;
}
if (identityZone == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Identity zone with id "+identityZoneId+" does not exist");
return;
}
stripScopesFromAuthentication(identityZoneId, request);
IdentityZoneHolder.set(identityZone);
filterChain.doFilter(request, response);
} finally {
IdentityZoneHolder.set(originalIdentityZone);
}
} else {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
return;
} }

IdentityZone identityZone = validateIdentityZone(identityZoneIdFromHeader, identityZoneSubDomain);
if (identityZone == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Identity zone with id/subdomain " + identityZoneIdFromHeader + "/" + identityZoneSubDomain + " does not exist");
return;
}

String identityZoneId = identityZone.getId();
if (!isAuthorizedToSwitchToIdentityZone(identityZoneId)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not authorized to switch to IdentityZone with id "+identityZoneId);
return;
}

IdentityZone originalIdentityZone = IdentityZoneHolder.get();
try {
stripScopesFromAuthentication(identityZoneId, request);
IdentityZoneHolder.set(identityZone);
filterChain.doFilter(request, response);
} finally {
IdentityZoneHolder.set(originalIdentityZone);
}
}

private IdentityZone validateIdentityZone(String identityZoneId, String identityZoneSubDomain) throws IOException {
IdentityZone identityZone = null;

try {
if (StringUtils.isEmpty(identityZoneId)) {
identityZone = dao.retrieveBySubdomain(identityZoneSubDomain);
} else {
identityZone = dao.retrieve(identityZoneId);
}
} catch (ZoneDoesNotExistsException | EmptyResultDataAccessException ex) {
} catch (Exception ex) {
throw ex;
}
return identityZone;
} }

} }
Expand Up @@ -26,12 +26,15 @@
import org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter; import org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.BaseClientDetails; import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.ResultMatcher;


import java.util.Arrays; import java.util.Arrays;
import java.util.UUID; import java.util.UUID;


import static org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter.HEADER;
import static org.cloudfoundry.identity.uaa.zone.IdentityZoneSwitchingFilter.SUBDOMAIN_HEADER;
import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
Expand Down Expand Up @@ -60,44 +63,81 @@ public void setUp() throws Exception {
@Test @Test
public void testSwitchingZones() throws Exception { public void testSwitchingZones() throws Exception {


final String zoneId = createZone(identityToken); IdentityZone identityZone = createZone(identityToken);
String zoneId = identityZone.getId();
String zoneAdminToken = MockMvcUtils.utils().getZoneAdminToken(getMockMvc(),adminToken, zoneId); String zoneAdminToken = MockMvcUtils.utils().getZoneAdminToken(getMockMvc(),adminToken, zoneId);
// Using Identity Client, authenticate in originating Zone // Using Identity Client, authenticate in originating Zone
// - Create Client using X-Identity-Zone-Id header in new Zone // - Create Client using X-Identity-Zone-Id header in new Zone
ClientDetails client = createClientInOtherZone(zoneAdminToken, status().isCreated(), HEADER, zoneId);

// Authenticate with new Client in new Zone
getMockMvc().perform(get("/oauth/token?grant_type=client_credentials")
.header("Authorization", "Basic "
+ new String(Base64.encodeBase64((client.getClientId() + ":" + client.getClientSecret()).getBytes())))
.with(new SetServerNameRequestPostProcessor(identityZone.getSubdomain() + ".localhost")))
.andExpect(status().isOk());
}

@Test
public void testSwitchingZoneWithSubdomain() throws Exception {
IdentityZone identityZone = createZone(identityToken);
String zoneAdminToken = MockMvcUtils.utils().getZoneAdminToken(getMockMvc(),adminToken, identityZone.getId());
ClientDetails client = createClientInOtherZone(zoneAdminToken, status().isCreated(), SUBDOMAIN_HEADER, identityZone.getSubdomain());

getMockMvc().perform(get("/oauth/token?grant_type=client_credentials")
.header("Authorization", "Basic "
+ new String(Base64.encodeBase64((client.getClientId() + ":" + client.getClientSecret()).getBytes())))
.with(new SetServerNameRequestPostProcessor(identityZone.getSubdomain() + ".localhost")))
.andExpect(status().isOk());

}

@Test
public void testNoSwitching() throws Exception{

final String clientId = UUID.randomUUID().toString(); final String clientId = UUID.randomUUID().toString();
BaseClientDetails client = new BaseClientDetails(clientId, null, null, "client_credentials", null); BaseClientDetails client = new BaseClientDetails(clientId, null, null, "client_credentials", null);
client.setClientSecret("secret"); client.setClientSecret("secret");

getMockMvc().perform(post("/oauth/clients") getMockMvc().perform(post("/oauth/clients")
.header(IdentityZoneSwitchingFilter.HEADER, zoneId) .header("Authorization", "Bearer " + adminToken)
.header("Authorization", "Bearer " + zoneAdminToken) .accept(APPLICATION_JSON)
.accept(APPLICATION_JSON) .contentType(APPLICATION_JSON)
.contentType(APPLICATION_JSON) .content(JsonUtils.writeValueAsString(client)))
.content(JsonUtils.writeValueAsString(client))) .andExpect(status().isCreated());
.andExpect(status().isCreated());


// Authenticate with new Client in new Zone
getMockMvc().perform(get("/oauth/token?grant_type=client_credentials") getMockMvc().perform(get("/oauth/token?grant_type=client_credentials")
.header("Authorization", "Basic " .header("Authorization", "Basic "
+ new String(Base64.encodeBase64((client.getClientId() + ":" + client.getClientSecret()).getBytes()))) + new String(Base64.encodeBase64((client.getClientId() + ":" + client.getClientSecret()).getBytes()))))
.with(new SetServerNameRequestPostProcessor(zoneId + ".localhost")))
.andExpect(status().isOk()); .andExpect(status().isOk());
} }


@Test
public void testSwitchingToInvalidSubDomain() throws Exception{
IdentityZone identityZone = createZone(identityToken);
String zoneAdminToken = MockMvcUtils.utils().getZoneAdminToken(getMockMvc(),adminToken, identityZone.getId());

createClientInOtherZone(zoneAdminToken, status().isNotFound(), SUBDOMAIN_HEADER, "InvalidSubDomain");
}

@Test @Test
public void testSwitchingToNonExistentZone() throws Exception { public void testSwitchingToNonExistentZone() throws Exception {
createClientInOtherZone(identityToken, "i-do-not-exist", status().isForbidden()); IdentityZone identityZone = createZone(identityToken);
String zoneAdminToken = MockMvcUtils.utils().getZoneAdminToken(getMockMvc(),adminToken, identityZone.getId());

createClientInOtherZone(zoneAdminToken, status().isNotFound(), HEADER, "i-do-not-exist");
} }


@Test @Test
public void testSwitchingZonesWithoutAuthority() throws Exception { public void testSwitchingZonesWithoutAuthority() throws Exception {
String identityTokenWithoutZonesAdmin = testClient.getClientCredentialsOAuthAccessToken("identity","identitysecret","zones.write,scim.zones"); String identityTokenWithoutZonesAdmin = testClient.getClientCredentialsOAuthAccessToken("identity","identitysecret","zones.write,scim.zones");
final String zoneId = createZone(identityTokenWithoutZonesAdmin); final String zoneId = createZone(identityTokenWithoutZonesAdmin).getId();
createClientInOtherZone(identityTokenWithoutZonesAdmin, zoneId, status().isForbidden()); createClientInOtherZone(identityTokenWithoutZonesAdmin, status().isForbidden(), HEADER, zoneId);
} }


@Test @Test
public void testSwitchingZonesWithAUser() throws Exception { public void testSwitchingZonesWithAUser() throws Exception {
final String zoneId = createZone(identityToken); final String zoneId = createZone(identityToken).getId();
String adminToken = testClient.getClientCredentialsOAuthAccessToken("admin","adminsecret","scim.write"); String adminToken = testClient.getClientCredentialsOAuthAccessToken("admin","adminsecret","scim.write");
// Create a User // Create a User
String username = RandomStringUtils.randomAlphabetic(8) + "@example.com"; String username = RandomStringUtils.randomAlphabetic(8) + "@example.com";
Expand All @@ -112,23 +152,24 @@ public void testSwitchingZonesWithAUser() throws Exception {
group.setMembers(Arrays.asList(new ScimGroupMember(createdUser.getId()))); group.setMembers(Arrays.asList(new ScimGroupMember(createdUser.getId())));
MockMvcUtils.utils().createGroup(getMockMvc(), adminToken, group); MockMvcUtils.utils().createGroup(getMockMvc(), adminToken, group);
String userToken = MockMvcUtils.utils().getUserOAuthAccessTokenAuthCode(getMockMvc(),"identity", "identitysecret", createdUser.getId(),createdUser.getUserName(), "secret", null); String userToken = MockMvcUtils.utils().getUserOAuthAccessTokenAuthCode(getMockMvc(),"identity", "identitysecret", createdUser.getId(),createdUser.getUserName(), "secret", null);
createClientInOtherZone(userToken, zoneId, status().isCreated()); createClientInOtherZone(userToken, status().isCreated(), HEADER, zoneId);
} }


private String createZone(String accessToken) throws Exception { private IdentityZone createZone(String accessToken) throws Exception {
return MockMvcUtils.utils().createZoneUsingWebRequest(getMockMvc(), accessToken).getId(); return MockMvcUtils.utils().createZoneUsingWebRequest(getMockMvc(), accessToken);
} }


private void createClientInOtherZone(String accessToken, String zoneId, ResultMatcher statusMatcher) throws Exception { private ClientDetails createClientInOtherZone(String accessToken, ResultMatcher statusMatcher, String headerKey, String headerValue) throws Exception {
final String clientId = UUID.randomUUID().toString(); String clientId = UUID.randomUUID().toString();
BaseClientDetails client = new BaseClientDetails(clientId, null, null, "client_credentials", null); BaseClientDetails client = new BaseClientDetails(clientId, null, null, "client_credentials", null);
client.setClientSecret("secret"); client.setClientSecret("secret");
getMockMvc().perform(post("/oauth/clients") getMockMvc().perform(post("/oauth/clients")
.header(IdentityZoneSwitchingFilter.HEADER, zoneId) .header(headerKey, headerValue)
.header("Authorization", "Bearer " + accessToken) .header("Authorization", "Bearer " + accessToken)
.accept(APPLICATION_JSON) .accept(APPLICATION_JSON)
.contentType(APPLICATION_JSON) .contentType(APPLICATION_JSON)
.content(JsonUtils.writeValueAsString(client))) .content(JsonUtils.writeValueAsString(client)))
.andExpect(statusMatcher); .andExpect(statusMatcher);
return client;
} }
} }

0 comments on commit 88d6fe2

Please sign in to comment.