Skip to content

Path based Identity Zone #3729

@fhanik

Description

@fhanik

Proposal

Rather than using subdomains, for example somedomain.login.system.com, this issue proposes using a path /z/{subdomain}/oauth/token

Requirements

  1. Zone path will only work when used against the default domain. If a zone path is added to a subdomain of the UAA, it will return a 400 error.
  2. subdomain based zones will continue to work
  3. There is no zone path for the default zone, unless the path is zone-id rather than subdomain
  4. Cookies must have the path set correctly
  5. Cookie flapping can occur, two cookies with JSESSIONID being sent, so cookie filtering must occur on the server

Example Test

public class ZonePathTokenMockMvcTests extends AbstractTokenMockMvcTests {

    private enum ZoneResolutionMode {
        SUBDOMAIN(subdomain -> get("/oauth/token")
                .with(new SetServerNameRequestPostProcessor(subdomain + ".localhost"))
        ),
        ZONE_PATH(subdomain -> get("/z/{subdomain}/oauth/token", subdomain));

        private final Function<String, MockHttpServletRequestBuilder> requestBuilder;

        ZoneResolutionMode(Function<String, MockHttpServletRequestBuilder> requestBuilder) {
            this.requestBuilder = requestBuilder;
        }

        MockHttpServletRequestBuilder createRequestBuilder(String subdomain) {
            return requestBuilder.apply(subdomain);
        }
    }

    @ParameterizedTest
    @EnumSource(ZoneResolutionMode.class)
    void clientCredentialsGrant(ZoneResolutionMode mode) throws Exception {
        String subdomain = "testzone" + generator.generate().toLowerCase();
        IdentityZone testZone = setupIdentityZone(subdomain);
        IdentityZoneHolder.set(testZone);
        setupIdentityProvider(OriginKeys.UAA);

        String scopes = "uaa.admin";

        String clientId = "testclient" + generator.generate();
        setUpClients(clientId, scopes, scopes, "client_credentials", true, null, null);

        IdentityZoneHolder.clear();

        String tokenResult = mockMvc.perform(mode.createRequestBuilder(subdomain)
                        .accept(APPLICATION_JSON)
                        .contentType(APPLICATION_FORM_URLENCODED)
                        .param(OAuth2Utils.GRANT_TYPE, GRANT_TYPE_CLIENT_CREDENTIALS)
                        .param(OAuth2Utils.RESPONSE_TYPE, "token")
                        .param(OAuth2Utils.CLIENT_ID, clientId)
                        .param(CLIENT_SECRET, SECRET)
                        .param(OAuth2Utils.REDIRECT_URI, TEST_REDIRECT_URI))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.access_token").isNotEmpty())
                .andReturn().getResponse().getContentAsString();
        Map<String, Object> response = JsonUtils.readValueAsMap(tokenResult);
        Jwt tokenClaims = JwtHelper.decode((String) response.get("access_token"));
        Assertions.assertThat(tokenClaims.getClaimSet().getStringClaim(ISS))
                .isEqualTo("http://%s.localhost:8080/uaa/oauth/token".formatted(testZone.getSubdomain()));
    }
}

Decisions

  1. Should the path use subdomain or zone-id? /z/{subdomain}/oauth/token versus /z/{zone-id}/oauth/token? Or /zid/{zone-id}/ and /zs/{subdomain}/ to support both?
  2. Do we support /z/{subdomain}/ everywhere, or should we only support it for UI (cookie based) and simply rewrite the URLs for all other places?
  3. Should the JSESSIONID cookie name be different based on domain? example JSESSIONID-foobar for the foobar domain? (special characters, encoding)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Inbox

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions