Add support for multiple issuers per host using the path component
Closes gh-1342
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
||||
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link AuthorizationServerContextFilter}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
class AuthorizationServerContextFilterTests {
|
||||
private static final String SCHEME = "https";
|
||||
private static final String HOST = "example.com";
|
||||
private static final int PORT = 8443;
|
||||
private static final String DEFAULT_ISSUER = SCHEME + "://" + HOST + ":" + PORT;
|
||||
private AuthorizationServerContextFilter filter;
|
||||
|
||||
@Test
|
||||
public void doFilterWhenDefaultEndpointsThenIssuerResolved() throws Exception {
|
||||
AuthorizationServerSettings authorizationServerSettings = AuthorizationServerSettings.builder().build();
|
||||
this.filter = new AuthorizationServerContextFilter(authorizationServerSettings);
|
||||
|
||||
String issuerPath = "/issuer1";
|
||||
String issuerWithPath = DEFAULT_ISSUER.concat(issuerPath);
|
||||
Set<String> endpointUris = getEndpointUris(authorizationServerSettings);
|
||||
|
||||
for (String endpointUri : endpointUris) {
|
||||
assertResolvedIssuer(issuerPath.concat(endpointUri), issuerWithPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomEndpointsThenIssuerResolved() throws Exception {
|
||||
AuthorizationServerSettings authorizationServerSettings = AuthorizationServerSettings.builder()
|
||||
.authorizationEndpoint("/oauth2/v1/authorize")
|
||||
.deviceAuthorizationEndpoint("/oauth2/v1/device_authorization")
|
||||
.deviceVerificationEndpoint("/oauth2/v1/device_verification")
|
||||
.tokenEndpoint("/oauth2/v1/token")
|
||||
.jwkSetEndpoint("/oauth2/v1/jwks")
|
||||
.tokenRevocationEndpoint("/oauth2/v1/revoke")
|
||||
.tokenIntrospectionEndpoint("/oauth2/v1/introspect")
|
||||
.oidcClientRegistrationEndpoint("/connect/v1/register")
|
||||
.oidcUserInfoEndpoint("/v1/userinfo")
|
||||
.oidcLogoutEndpoint("/connect/v1/logout")
|
||||
.build();
|
||||
this.filter = new AuthorizationServerContextFilter(authorizationServerSettings);
|
||||
|
||||
String issuerPath = "/issuer2";
|
||||
String issuerWithPath = DEFAULT_ISSUER.concat(issuerPath);
|
||||
Set<String> endpointUris = getEndpointUris(authorizationServerSettings);
|
||||
|
||||
for (String endpointUri : endpointUris) {
|
||||
assertResolvedIssuer(issuerPath.concat(endpointUri), issuerWithPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenIssuerHasMultiplePathsThenIssuerResolved() throws Exception {
|
||||
AuthorizationServerSettings authorizationServerSettings = AuthorizationServerSettings.builder().build();
|
||||
this.filter = new AuthorizationServerContextFilter(authorizationServerSettings);
|
||||
|
||||
String issuerPath = "/path1/path2/issuer3";
|
||||
String issuerWithPath = DEFAULT_ISSUER.concat(issuerPath);
|
||||
Set<String> endpointUris = getEndpointUris(authorizationServerSettings);
|
||||
|
||||
for (String endpointUri : endpointUris) {
|
||||
assertResolvedIssuer(issuerPath.concat(endpointUri), issuerWithPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertResolvedIssuer(String requestUri, String expectedIssuer) throws Exception {
|
||||
MockHttpServletRequest request = createRequest(requestUri);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
AtomicReference<String> resolvedIssuer = new AtomicReference<>();
|
||||
FilterChain filterChain = (req, resp) ->
|
||||
resolvedIssuer.set(AuthorizationServerContextHolder.getContext().getIssuer());
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
assertThat(resolvedIssuer.get()).isEqualTo(expectedIssuer);
|
||||
}
|
||||
|
||||
private static Set<String> getEndpointUris(AuthorizationServerSettings authorizationServerSettings) {
|
||||
Set<String> endpointUris = new HashSet<>();
|
||||
endpointUris.add("/.well-known/oauth-authorization-server");
|
||||
endpointUris.add("/.well-known/openid-configuration");
|
||||
for (Map.Entry<String, Object> setting : authorizationServerSettings.getSettings().entrySet()) {
|
||||
if (setting.getKey().endsWith("-endpoint")) {
|
||||
endpointUris.add((String) setting.getValue());
|
||||
}
|
||||
}
|
||||
return endpointUris;
|
||||
}
|
||||
|
||||
private static MockHttpServletRequest createRequest(String requestUri) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI(requestUri);
|
||||
request.setScheme(SCHEME);
|
||||
request.setServerName(HOST);
|
||||
request.setServerPort(PORT);
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2022 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -112,6 +112,14 @@ public class JwkSetTests {
|
||||
assertJwkSetRequestThenReturnKeys(authorizationServerSettings.getJwkSetEndpoint());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenJwkSetRequestIncludesIssuerPathThenReturnKeys() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationCustomEndpoints.class).autowire();
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
assertJwkSetRequestThenReturnKeys(issuer.concat(authorizationServerSettings.getJwkSetEndpoint()));
|
||||
}
|
||||
|
||||
private void assertJwkSetRequestThenReturnKeys(String jwkSetEndpointUri) throws Exception {
|
||||
this.mvc.perform(get(jwkSetEndpointUri))
|
||||
.andExpect(status().isOk())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -826,6 +826,46 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
assertThat(securityContext.getAuthentication()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenAuthorizationAndTokenRequestIncludesIssuerPathThenIssuerResolvedWithPath() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithTokenGenerator.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredPublicClient().build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
MvcResult mvcResult = this.mvc.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI))
|
||||
.queryParams(getAuthorizationRequestParameters(registeredClient))
|
||||
.queryParam(PkceParameterNames.CODE_CHALLENGE, S256_CODE_CHALLENGE)
|
||||
.queryParam(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256")
|
||||
.with(user("user")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
|
||||
String authorizationCode = extractParameterFromRedirectUri(mvcResult.getResponse().getRedirectedUrl(), "code");
|
||||
OAuth2Authorization authorizationCodeAuthorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE);
|
||||
|
||||
this.mvc.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.params(getTokenRequestParameters(registeredClient, authorizationCodeAuthorization))
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
|
||||
.param(PkceParameterNames.CODE_VERIFIER, S256_CODE_VERIFIER))
|
||||
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, containsString("no-store")))
|
||||
.andExpect(header().string(HttpHeaders.PRAGMA, containsString("no-cache")))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.token_type").isNotEmpty())
|
||||
.andExpect(jsonPath("$.expires_in").isNotEmpty())
|
||||
.andExpect(jsonPath("$.refresh_token").doesNotExist())
|
||||
.andExpect(jsonPath("$.scope").isNotEmpty())
|
||||
.andReturn();
|
||||
|
||||
ArgumentCaptor<OAuth2TokenContext> tokenContextCaptor = ArgumentCaptor.forClass(OAuth2TokenContext.class);
|
||||
verify(tokenGenerator).generate(tokenContextCaptor.capture());
|
||||
OAuth2TokenContext tokenContext = tokenContextCaptor.getValue();
|
||||
assertThat(tokenContext.getAuthorizationServerContext().getIssuer()).isEqualTo(issuer);
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> getAuthorizationRequestParameters(RegisteredClient registeredClient) {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameters.set(OAuth2ParameterNames.RESPONSE_TYPE, OAuth2AuthorizationResponseType.CODE.getValue());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -65,7 +65,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class OAuth2AuthorizationServerMetadataTests {
|
||||
private static final String DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI = "/.well-known/oauth-authorization-server";
|
||||
private static final String ISSUER_URL = "https://example.com";
|
||||
private static final String ISSUER = "https://example.com";
|
||||
private static EmbeddedDatabase db;
|
||||
private static JWKSource<SecurityContext> jwkSource;
|
||||
|
||||
@@ -105,19 +105,37 @@ public class OAuth2AuthorizationServerMetadataTests {
|
||||
public void requestWhenAuthorizationServerMetadataRequestAndIssuerSetThenUsed() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER_URL.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI)))
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(ISSUER_URL))
|
||||
.andExpect(jsonPath("issuer").value(ISSUER))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenAuthorizationServerMetadataRequestAndIssuerNotSetThenResolveFromRequest() throws Exception {
|
||||
public void requestWhenAuthorizationServerMetadataRequestIncludesIssuerPathThenMetadataResponseHasIssuerPath() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithIssuerNotSet.class).autowire();
|
||||
|
||||
this.mvc.perform(get("http://localhost".concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI)))
|
||||
String host = "https://example.com:8443";
|
||||
|
||||
String issuerPath = "/issuer1";
|
||||
String issuer = host.concat(issuerPath);
|
||||
this.mvc.perform(get(host.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI).concat(issuerPath)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value("http://localhost"))
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
|
||||
issuerPath = "/path1/issuer2";
|
||||
issuer = host.concat(issuerPath);
|
||||
this.mvc.perform(get(host.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI).concat(issuerPath)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
|
||||
issuerPath = "/path1/path2/issuer3";
|
||||
issuer = host.concat(issuerPath);
|
||||
this.mvc.perform(get(host.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI).concat(issuerPath)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath("issuer").value(issuer))
|
||||
.andReturn();
|
||||
}
|
||||
|
||||
@@ -126,7 +144,7 @@ public class OAuth2AuthorizationServerMetadataTests {
|
||||
public void requestWhenAuthorizationServerMetadataRequestAndMetadataCustomizerSetThenReturnCustomMetadataResponse() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithMetadataCustomizer.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER_URL.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI)))
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED,
|
||||
hasItems("scope1", "scope2")));
|
||||
@@ -156,7 +174,7 @@ public class OAuth2AuthorizationServerMetadataTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER_URL).build();
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -357,6 +357,30 @@ public class OAuth2ClientCredentialsGrantTests {
|
||||
verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), eq(clientPrincipal));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenTokenRequestIncludesIssuerPathThenIssuerResolvedWithPath() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient2().build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
this.mvc.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1 scope2")
|
||||
.header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty())
|
||||
.andExpect(jsonPath("$.scope").value("scope1 scope2"));
|
||||
|
||||
ArgumentCaptor<JwtEncodingContext> jwtEncodingContextCaptor = ArgumentCaptor.forClass(JwtEncodingContext.class);
|
||||
verify(jwtCustomizer).customize(jwtEncodingContextCaptor.capture());
|
||||
JwtEncodingContext jwtEncodingContext = jwtEncodingContextCaptor.getValue();
|
||||
assertThat(jwtEncodingContext.getAuthorizationServerContext().getIssuer()).isEqualTo(issuer);
|
||||
}
|
||||
|
||||
private static String encodeBasicAuth(String clientId, String secret) throws Exception {
|
||||
clientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8.name());
|
||||
secret = URLEncoder.encode(secret, StandardCharsets.UTF_8.name());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -218,8 +218,10 @@ public class OAuth2DeviceCodeGrantTests {
|
||||
parameters.set(OAuth2ParameterNames.SCOPE,
|
||||
StringUtils.collectionToDelimitedString(registeredClient.getScopes(), " "));
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
// @formatter:off
|
||||
MvcResult mvcResult = this.mvc.perform(post(DEFAULT_DEVICE_AUTHORIZATION_ENDPOINT_URI)
|
||||
MvcResult mvcResult = this.mvc.perform(post(issuer.concat(DEFAULT_DEVICE_AUTHORIZATION_ENDPOINT_URI))
|
||||
.params(parameters)
|
||||
.headers(withClientAuth(registeredClient)))
|
||||
.andExpect(status().isOk())
|
||||
@@ -240,9 +242,9 @@ public class OAuth2DeviceCodeGrantTests {
|
||||
String userCode = deviceAuthorizationResponse.getUserCode().getTokenValue();
|
||||
assertThat(userCode).matches("[A-Z]{4}-[A-Z]{4}");
|
||||
assertThat(deviceAuthorizationResponse.getVerificationUri())
|
||||
.isEqualTo("http://localhost/oauth2/device_verification");
|
||||
.isEqualTo("https://example.com:8443/oauth2/device_verification");
|
||||
assertThat(deviceAuthorizationResponse.getVerificationUriComplete())
|
||||
.isEqualTo("http://localhost/oauth2/device_verification?user_code=" + userCode);
|
||||
.isEqualTo("https://example.com:8443/oauth2/device_verification?user_code=" + userCode);
|
||||
|
||||
String deviceCode = deviceAuthorizationResponse.getDeviceCode().getTokenValue();
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(deviceCode, DEVICE_CODE_TOKEN_TYPE);
|
||||
@@ -311,8 +313,10 @@ public class OAuth2DeviceCodeGrantTests {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameters.set(OAuth2ParameterNames.USER_CODE, USER_CODE);
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
// @formatter:off
|
||||
MvcResult mvcResult = this.mvc.perform(get(DEFAULT_DEVICE_VERIFICATION_ENDPOINT_URI)
|
||||
MvcResult mvcResult = this.mvc.perform(get(issuer.concat(DEFAULT_DEVICE_VERIFICATION_ENDPOINT_URI))
|
||||
.queryParams(parameters)
|
||||
.with(user("user")))
|
||||
.andExpect(status().isOk())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2022 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,6 +30,7 @@ import java.util.function.Consumer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -107,6 +108,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
@@ -167,6 +169,18 @@ public class OAuth2TokenIntrospectionTests {
|
||||
.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
reset(authenticationConverter);
|
||||
reset(authenticationConvertersConsumer);
|
||||
reset(authenticationProvider);
|
||||
reset(authenticationProvidersConsumer);
|
||||
reset(authenticationSuccessHandler);
|
||||
reset(authenticationFailureHandler);
|
||||
reset(accessTokenCustomizer);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
jdbcOperations.update("truncate table oauth2_authorization");
|
||||
@@ -395,6 +409,41 @@ public class OAuth2TokenIntrospectionTests {
|
||||
verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), eq(tokenIntrospectionAuthentication));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenIntrospectionRequestIncludesIssuerPathThenActive() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationCustomTokenIntrospectionEndpoint.class).autowire();
|
||||
|
||||
RegisteredClient introspectRegisteredClient = TestRegisteredClients.registeredClient2().build();
|
||||
this.registeredClientRepository.save(introspectRegisteredClient);
|
||||
|
||||
RegisteredClient authorizedRegisteredClient = TestRegisteredClients.registeredClient().build();
|
||||
this.registeredClientRepository.save(authorizedRegisteredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(authorizedRegisteredClient).build();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
||||
|
||||
Authentication clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
introspectRegisteredClient, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, introspectRegisteredClient.getClientSecret());
|
||||
OAuth2TokenIntrospectionAuthenticationToken tokenIntrospectionAuthentication =
|
||||
new OAuth2TokenIntrospectionAuthenticationToken(
|
||||
accessToken.getTokenValue(), clientPrincipal, null, null);
|
||||
|
||||
when(authenticationConverter.convert(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
when(authenticationProvider.supports(eq(OAuth2TokenIntrospectionAuthenticationToken.class))).thenReturn(true);
|
||||
when(authenticationProvider.authenticate(any())).thenReturn(tokenIntrospectionAuthentication);
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
// @formatter:off
|
||||
this.mvc.perform(post(issuer.concat(authorizationServerSettings.getTokenIntrospectionEndpoint()))
|
||||
.params(getTokenIntrospectionRequestParameters(accessToken, OAuth2TokenType.ACCESS_TOKEN))
|
||||
.header(HttpHeaders.AUTHORIZATION, getAuthorizationHeader(introspectRegisteredClient)))
|
||||
.andExpect(status().isOk());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> getTokenIntrospectionRequestParameters(OAuth2Token token,
|
||||
OAuth2TokenType tokenType) {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2022 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -201,6 +201,35 @@ public class OAuth2TokenRevocationTests {
|
||||
assertThat(refreshToken.isInvalidated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenRevokeAccessTokenAndRequestIncludesIssuerPathThenRevoked() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();
|
||||
OAuth2AccessToken token = authorization.getAccessToken().getToken();
|
||||
OAuth2TokenType tokenType = OAuth2TokenType.ACCESS_TOKEN;
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
// @formatter:off
|
||||
this.mvc.perform(post(issuer.concat(DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI))
|
||||
.params(getTokenRevocationRequestParameters(token, tokenType))
|
||||
.header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||
.andExpect(status().isOk());
|
||||
// @formatter:on
|
||||
|
||||
OAuth2Authorization updatedAuthorization = this.authorizationService.findById(authorization.getId());
|
||||
OAuth2Authorization.Token<OAuth2AccessToken> accessToken = updatedAuthorization.getAccessToken();
|
||||
assertThat(accessToken.isInvalidated()).isTrue();
|
||||
OAuth2Authorization.Token<OAuth2RefreshToken> refreshToken = updatedAuthorization.getRefreshToken();
|
||||
assertThat(refreshToken.isInvalidated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenTokenRevocationEndpointCustomizedThenUsed() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationCustomTokenRevocationEndpoint.class).autowire();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -137,6 +137,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
*/
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class OidcClientRegistrationTests {
|
||||
private static final String ISSUER = "https://example.com:8443/issuer1";
|
||||
private static final String DEFAULT_TOKEN_ENDPOINT_URI = "/oauth2/token";
|
||||
private static final String DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI = "/connect/register";
|
||||
private static final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
|
||||
@@ -374,7 +375,7 @@ public class OidcClientRegistrationTests {
|
||||
|
||||
when(authenticationProvider.authenticate(any())).thenThrow(new OAuth2AuthenticationException("error"));
|
||||
|
||||
this.mvc.perform(get(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, "invalid").with(jwt()));
|
||||
|
||||
verify(authenticationFailureHandler).onAuthenticationFailure(any(), any(), any());
|
||||
@@ -399,7 +400,7 @@ public class OidcClientRegistrationTests {
|
||||
|
||||
OidcClientRegistration clientRegistrationResponse = registerClient(clientRegistration);
|
||||
|
||||
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
|
||||
this.mvc.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1")
|
||||
.with(httpBasic(clientRegistrationResponse.getClientId(), clientRegistrationResponse.getClientSecret())))
|
||||
@@ -436,7 +437,7 @@ public class OidcClientRegistrationTests {
|
||||
JwtClaimsSet jwtClaimsSet = JwtClaimsSet.builder()
|
||||
.issuer(clientRegistrationResponse.getClientId())
|
||||
.subject(clientRegistrationResponse.getClientId())
|
||||
.audience(Collections.singletonList(asUrl(this.authorizationServerSettings.getIssuer(), this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.audience(Collections.singletonList(asUrl(ISSUER, this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.build();
|
||||
@@ -447,7 +448,7 @@ public class OidcClientRegistrationTests {
|
||||
|
||||
Jwt jwtAssertion = jwtClientAssertionEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet));
|
||||
|
||||
this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
|
||||
this.mvc.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, "scope1")
|
||||
.param(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
|
||||
@@ -520,7 +521,7 @@ public class OidcClientRegistrationTests {
|
||||
// @formatter:on
|
||||
Jwt jwtAssertion = jwtClientAssertionEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet));
|
||||
|
||||
MvcResult mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
|
||||
MvcResult mvcResult = this.mvc.perform(post(ISSUER.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue())
|
||||
.param(OAuth2ParameterNames.SCOPE, clientRegistrationScope)
|
||||
.param(OAuth2ParameterNames.CLIENT_ASSERTION_TYPE, "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
|
||||
@@ -539,7 +540,7 @@ public class OidcClientRegistrationTests {
|
||||
httpHeaders.setBearerAuth(accessToken.getTokenValue());
|
||||
|
||||
// Register the client
|
||||
mvcResult = this.mvc.perform(post(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI)
|
||||
mvcResult = this.mvc.perform(post(ISSUER.concat(DEFAULT_OIDC_CLIENT_REGISTRATION_ENDPOINT_URI))
|
||||
.headers(httpHeaders)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(getClientRegistrationRequestContent(clientRegistration)))
|
||||
@@ -557,7 +558,7 @@ public class OidcClientRegistrationTests {
|
||||
return JwtClaimsSet.builder()
|
||||
.issuer(registeredClient.getClientId())
|
||||
.subject(registeredClient.getClientId())
|
||||
.audience(Collections.singletonList(asUrl(this.authorizationServerSettings.getIssuer(), this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.audience(Collections.singletonList(asUrl(ISSUER, this.authorizationServerSettings.getTokenEndpoint())))
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt);
|
||||
}
|
||||
@@ -734,7 +735,6 @@ public class OidcClientRegistrationTests {
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.issuer("https://auth-server:9000")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,7 +63,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@ExtendWith(SpringTestContextExtension.class)
|
||||
public class OidcProviderConfigurationTests {
|
||||
private static final String DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI = "/.well-known/openid-configuration";
|
||||
private static final String ISSUER_URL = "https://example.com";
|
||||
private static final String ISSUER = "https://example.com";
|
||||
|
||||
public final SpringTestContext spring = new SpringTestContext();
|
||||
|
||||
@@ -77,9 +77,29 @@ public class OidcProviderConfigurationTests {
|
||||
public void requestWhenConfigurationRequestAndIssuerSetThenReturnDefaultConfigurationResponse() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER_URL.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers());
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenConfigurationRequestIncludesIssuerPathThenConfigurationResponseHasIssuerPath() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithIssuerNotSet.class).autowire();
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
this.mvc.perform(get(issuer.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
|
||||
issuer = "https://example.com:8443/path1/issuer2";
|
||||
this.mvc.perform(get(issuer.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
|
||||
issuer = "https://example.com:8443/path1/path2/issuer3";
|
||||
this.mvc.perform(get(issuer.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers(issuer));
|
||||
}
|
||||
|
||||
// gh-632
|
||||
@@ -87,10 +107,10 @@ public class OidcProviderConfigurationTests {
|
||||
public void requestWhenConfigurationRequestAndUserAuthenticatedThenReturnConfigurationResponse() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER_URL.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI))
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI))
|
||||
.with(user("user")))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers());
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER));
|
||||
}
|
||||
|
||||
// gh-616
|
||||
@@ -98,7 +118,7 @@ public class OidcProviderConfigurationTests {
|
||||
public void requestWhenConfigurationRequestAndConfigurationCustomizerSetThenReturnCustomConfigurationResponse() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithProviderConfigurationCustomizer.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER_URL.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(jsonPath(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED,
|
||||
hasItems(OidcScopes.OPENID, OidcScopes.PROFILE, OidcScopes.EMAIL)));
|
||||
@@ -108,35 +128,35 @@ public class OidcProviderConfigurationTests {
|
||||
public void requestWhenConfigurationRequestAndClientRegistrationEnabledThenConfigurationResponseIncludesRegistrationEndpoint() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfigurationWithClientRegistrationEnabled.class).autowire();
|
||||
|
||||
this.mvc.perform(get(ISSUER_URL.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
this.mvc.perform(get(ISSUER.concat(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(defaultConfigurationMatchers())
|
||||
.andExpect(jsonPath("$.registration_endpoint").value(ISSUER_URL.concat(this.authorizationServerSettings.getOidcClientRegistrationEndpoint())));
|
||||
.andExpectAll(defaultConfigurationMatchers(ISSUER))
|
||||
.andExpect(jsonPath("$.registration_endpoint").value(ISSUER.concat(this.authorizationServerSettings.getOidcClientRegistrationEndpoint())));
|
||||
}
|
||||
|
||||
private ResultMatcher[] defaultConfigurationMatchers() {
|
||||
private ResultMatcher[] defaultConfigurationMatchers(String issuer) {
|
||||
// @formatter:off
|
||||
return new ResultMatcher[] {
|
||||
jsonPath("issuer").value(ISSUER_URL),
|
||||
jsonPath("authorization_endpoint").value(ISSUER_URL.concat(this.authorizationServerSettings.getAuthorizationEndpoint())),
|
||||
jsonPath("token_endpoint").value(ISSUER_URL.concat(this.authorizationServerSettings.getTokenEndpoint())),
|
||||
jsonPath("issuer").value(issuer),
|
||||
jsonPath("authorization_endpoint").value(issuer.concat(this.authorizationServerSettings.getAuthorizationEndpoint())),
|
||||
jsonPath("token_endpoint").value(issuer.concat(this.authorizationServerSettings.getTokenEndpoint())),
|
||||
jsonPath("$.token_endpoint_auth_methods_supported[0]").value(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue()),
|
||||
jsonPath("$.token_endpoint_auth_methods_supported[1]").value(ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue()),
|
||||
jsonPath("$.token_endpoint_auth_methods_supported[2]").value(ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue()),
|
||||
jsonPath("$.token_endpoint_auth_methods_supported[3]").value(ClientAuthenticationMethod.PRIVATE_KEY_JWT.getValue()),
|
||||
jsonPath("jwks_uri").value(ISSUER_URL.concat(this.authorizationServerSettings.getJwkSetEndpoint())),
|
||||
jsonPath("userinfo_endpoint").value(ISSUER_URL.concat(this.authorizationServerSettings.getOidcUserInfoEndpoint())),
|
||||
jsonPath("end_session_endpoint").value(ISSUER_URL.concat(this.authorizationServerSettings.getOidcLogoutEndpoint())),
|
||||
jsonPath("jwks_uri").value(issuer.concat(this.authorizationServerSettings.getJwkSetEndpoint())),
|
||||
jsonPath("userinfo_endpoint").value(issuer.concat(this.authorizationServerSettings.getOidcUserInfoEndpoint())),
|
||||
jsonPath("end_session_endpoint").value(issuer.concat(this.authorizationServerSettings.getOidcLogoutEndpoint())),
|
||||
jsonPath("response_types_supported").value(OAuth2AuthorizationResponseType.CODE.getValue()),
|
||||
jsonPath("$.grant_types_supported[0]").value(AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||
jsonPath("$.grant_types_supported[1]").value(AuthorizationGrantType.CLIENT_CREDENTIALS.getValue()),
|
||||
jsonPath("$.grant_types_supported[2]").value(AuthorizationGrantType.REFRESH_TOKEN.getValue()),
|
||||
jsonPath("revocation_endpoint").value(ISSUER_URL.concat(this.authorizationServerSettings.getTokenRevocationEndpoint())),
|
||||
jsonPath("revocation_endpoint").value(issuer.concat(this.authorizationServerSettings.getTokenRevocationEndpoint())),
|
||||
jsonPath("$.revocation_endpoint_auth_methods_supported[0]").value(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue()),
|
||||
jsonPath("$.revocation_endpoint_auth_methods_supported[1]").value(ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue()),
|
||||
jsonPath("$.revocation_endpoint_auth_methods_supported[2]").value(ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue()),
|
||||
jsonPath("$.revocation_endpoint_auth_methods_supported[3]").value(ClientAuthenticationMethod.PRIVATE_KEY_JWT.getValue()),
|
||||
jsonPath("introspection_endpoint").value(ISSUER_URL.concat(this.authorizationServerSettings.getTokenIntrospectionEndpoint())),
|
||||
jsonPath("introspection_endpoint").value(issuer.concat(this.authorizationServerSettings.getTokenIntrospectionEndpoint())),
|
||||
jsonPath("$.introspection_endpoint_auth_methods_supported[0]").value(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.getValue()),
|
||||
jsonPath("$.introspection_endpoint_auth_methods_supported[1]").value(ClientAuthenticationMethod.CLIENT_SECRET_POST.getValue()),
|
||||
jsonPath("$.introspection_endpoint_auth_methods_supported[2]").value(ClientAuthenticationMethod.CLIENT_SECRET_JWT.getValue()),
|
||||
@@ -218,7 +238,18 @@ public class OidcProviderConfigurationTests {
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.issuer(ISSUER_URL)
|
||||
.issuer(ISSUER)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class AuthorizationServerConfigurationWithIssuerNotSet extends AuthorizationServerConfiguration {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -306,7 +337,7 @@ public class OidcProviderConfigurationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER_URL + "?param=value").build();
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER + "?param=value").build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +346,7 @@ public class OidcProviderConfigurationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER_URL + "#fragment").build();
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER + "#fragment").build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +355,7 @@ public class OidcProviderConfigurationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER_URL + "?param=value#fragment").build();
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER + "?param=value#fragment").build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +364,7 @@ public class OidcProviderConfigurationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER_URL + "?").build();
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER + "?").build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +373,7 @@ public class OidcProviderConfigurationTests {
|
||||
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER_URL + "#").build();
|
||||
return AuthorizationServerSettings.builder().issuer(ISSUER + "#").build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -303,9 +303,11 @@ public class OidcTests {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().scope(OidcScopes.OPENID).build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
// Login
|
||||
MultiValueMap<String, String> authorizationRequestParameters = getAuthorizationRequestParameters(registeredClient);
|
||||
MvcResult mvcResult = this.mvc.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI)
|
||||
MvcResult mvcResult = this.mvc.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI))
|
||||
.queryParams(authorizationRequestParameters)
|
||||
.with(user("user")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
@@ -319,7 +321,7 @@ public class OidcTests {
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(authorizationCode, AUTHORIZATION_CODE_TOKEN_TYPE);
|
||||
|
||||
// Get ID Token
|
||||
mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI)
|
||||
mvcResult = this.mvc.perform(post(issuer.concat(DEFAULT_TOKEN_ENDPOINT_URI))
|
||||
.params(getTokenRequestParameters(registeredClient, authorization))
|
||||
.header(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth(
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret())))
|
||||
@@ -334,7 +336,7 @@ public class OidcTests {
|
||||
String idToken = (String) accessTokenResponse.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN);
|
||||
|
||||
// Logout
|
||||
mvcResult = this.mvc.perform(post(DEFAULT_OIDC_LOGOUT_ENDPOINT_URI)
|
||||
mvcResult = this.mvc.perform(post(issuer.concat(DEFAULT_OIDC_LOGOUT_ENDPOINT_URI))
|
||||
.param("id_token_hint", idToken)
|
||||
.session(session))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2022 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,11 +24,12 @@ import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -193,6 +194,24 @@ public class OidcUserInfoTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenUserInfoRequestIncludesIssuerPathThenUserInfoResponse() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
OAuth2Authorization authorization = createAuthorization();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
String issuer = "https://example.com:8443/issuer1";
|
||||
|
||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
||||
// @formatter:off
|
||||
this.mvc.perform(get(issuer.concat(DEFAULT_OIDC_USER_INFO_ENDPOINT_URI))
|
||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken.getTokenValue()))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpectAll(userInfoResponse());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenUserInfoEndpointCustomizedThenUsed() throws Exception {
|
||||
this.spring.register(CustomUserInfoConfiguration.class).autowire();
|
||||
@@ -512,7 +531,6 @@ public class OidcUserInfoTests {
|
||||
@Bean
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
return AuthorizationServerSettings.builder()
|
||||
.issuer("https://auth-server:9000")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.time.temporal.ChronoUnit;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -404,6 +405,9 @@ public class OAuth2DeviceAuthorizationEndpointFilterTests {
|
||||
request.setRequestURI(AUTHORIZATION_URI);
|
||||
request.setServletPath(AUTHORIZATION_URI);
|
||||
request.setRemoteAddr(REMOTE_ADDRESS);
|
||||
request.setScheme("https");
|
||||
request.setServerName("provider.com");
|
||||
request.setServerPort(-1);
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user