Polish gh-167

This commit is contained in:
Joe Grandja
2021-04-28 04:46:11 -04:00
parent 0a4775423b
commit 7dc9da3340
28 changed files with 1667 additions and 1599 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 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 com.nimbusds.jose.proc.SecurityContext;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -30,7 +31,7 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.oauth2.jose.TestJwks;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerConfigurationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.Mockito.mock;
@@ -39,11 +40,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Integration tests for OAuth 2.0 Authorization Server Configuration.
* Integration tests for the OAuth 2.0 Authorization Server Metadata endpoint.
*
* @author Daniel Garnier-Moiroux
*/
public class OAuth2AuthorizationServerConfigurationTests {
public class OAuth2AuthorizationServerMetadataTests {
private static final String issuerUrl = "https://example.com/issuer1";
private static JWKSource<SecurityContext> jwkSource;
@@ -60,10 +61,10 @@ public class OAuth2AuthorizationServerConfigurationTests {
}
@Test
public void requestWhenServerConfigurationRequestAndIssuerSetThenReturnServerConfigurationResponse() throws Exception {
public void requestWhenAuthorizationServerMetadataRequestAndIssuerSetThenReturnMetadataResponse() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.mvc.perform(get(OAuth2AuthorizationServerConfigurationEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_CONFIGURATION_ENDPOINT_URI))
this.mvc.perform(get(OAuth2AuthorizationServerMetadataEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath("issuer").value(issuerUrl))
.andReturn();
@@ -88,4 +89,5 @@ public class OAuth2AuthorizationServerConfigurationTests {
return new ProviderSettings().issuer(issuerUrl);
}
}
}

View File

@@ -0,0 +1,585 @@
/*
* Copyright 2020-2021 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.core;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.junit.Test;
import org.springframework.security.oauth2.core.OAuth2AuthorizationServerMetadata.Builder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link OAuth2AuthorizationServerMetadata}.
*
* @author Daniel Garnier-Moiroux
*/
public class OAuth2AuthorizationServerMetadataTests {
// @formatter:off
private final Builder minimalBuilder =
OAuth2AuthorizationServerMetadata.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.responseType("code");
// @formatter:on
@Test
public void buildWhenAllClaimsProvidedThenCreated() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = OAuth2AuthorizationServerMetadata.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.tokenEndpointAuthenticationMethod("client_secret_basic")
.jwkSetUrl("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.grantType("authorization_code")
.grantType("client_credentials")
.tokenRevocationEndpoint("https://example.com/issuer1/oauth2/revoke")
.tokenRevocationEndpointAuthenticationMethod("client_secret_basic")
.tokenIntrospectionEndpoint("https://example.com/issuer1/oauth2/introspect")
.tokenIntrospectionEndpointAuthenticationMethod("client_secret_basic")
.codeChallengeMethod("plain")
.codeChallengeMethod("S256")
.claim("a-claim", "a-value")
.build();
assertThat(authorizationServerMetadata.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerMetadata.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerMetadata.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerMetadata.getTokenEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerMetadata.getJwkSetUrl()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerMetadata.getScopes()).containsExactly("openid");
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerMetadata.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "client_credentials");
assertThat(authorizationServerMetadata.getTokenRevocationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/revoke"));
assertThat(authorizationServerMetadata.getTokenRevocationEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/introspect"));
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerMetadata.getCodeChallengeMethods()).containsExactlyInAnyOrder("plain", "S256");
assertThat(authorizationServerMetadata.getClaimAsString("a-claim")).isEqualTo("a-value");
}
@Test
public void buildWhenOnlyRequiredClaimsProvidedThenCreated() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = OAuth2AuthorizationServerMetadata.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.responseType("code")
.build();
assertThat(authorizationServerMetadata.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerMetadata.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerMetadata.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerMetadata.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getJwkSetUrl()).isNull();
assertThat(authorizationServerMetadata.getScopes()).isNull();
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerMetadata.getGrantTypes()).isNull();
assertThat(authorizationServerMetadata.getTokenRevocationEndpoint()).isNull();
assertThat(authorizationServerMetadata.getTokenRevocationEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpoint()).isNull();
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getCodeChallengeMethods()).isNull();
}
@Test
public void withClaimsWhenClaimsProvidedThenCreated() {
HashMap<String, Object> claims = new HashMap<>();
claims.put(OAuth2AuthorizationServerMetadataClaimNames.ISSUER, "https://example.com/issuer1");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT, "https://example.com/issuer1/oauth2/authorize");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT, "https://example.com/issuer1/oauth2/token");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI, "https://example.com/issuer1/oauth2/jwks");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED, Collections.singletonList("openid"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, Collections.singletonList("code"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.REVOCATION_ENDPOINT, "https://example.com/issuer1/oauth2/revoke");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.INTROSPECTION_ENDPOINT, "https://example.com/issuer1/oauth2/introspect");
claims.put("some-claim", "some-value");
OAuth2AuthorizationServerMetadata authorizationServerMetadata = OAuth2AuthorizationServerMetadata.withClaims(claims).build();
assertThat(authorizationServerMetadata.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerMetadata.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerMetadata.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerMetadata.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getJwkSetUrl()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerMetadata.getScopes()).containsExactly("openid");
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerMetadata.getGrantTypes()).isNull();
assertThat(authorizationServerMetadata.getTokenRevocationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/revoke"));
assertThat(authorizationServerMetadata.getTokenRevocationEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/introspect"));
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getCodeChallengeMethods()).isNull();
assertThat(authorizationServerMetadata.getClaimAsString("some-claim")).isEqualTo("some-value");
}
@Test
public void withClaimsWhenClaimsWithUrlsProvidedThenCreated() {
HashMap<String, Object> claims = new HashMap<>();
claims.put(OAuth2AuthorizationServerMetadataClaimNames.ISSUER, url("https://example.com/issuer1"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT, url("https://example.com/issuer1/oauth2/authorize"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT, url("https://example.com/issuer1/oauth2/token"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI, url("https://example.com/issuer1/oauth2/jwks"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, Collections.singletonList("code"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.REVOCATION_ENDPOINT, url("https://example.com/issuer1/oauth2/revoke"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.INTROSPECTION_ENDPOINT, url("https://example.com/issuer1/oauth2/introspect"));
claims.put("some-claim", "some-value");
OAuth2AuthorizationServerMetadata authorizationServerMetadata = OAuth2AuthorizationServerMetadata.withClaims(claims).build();
assertThat(authorizationServerMetadata.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerMetadata.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerMetadata.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerMetadata.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getJwkSetUrl()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerMetadata.getScopes()).isNull();
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerMetadata.getGrantTypes()).isNull();
assertThat(authorizationServerMetadata.getTokenRevocationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/revoke"));
assertThat(authorizationServerMetadata.getTokenRevocationEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/introspect"));
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getCodeChallengeMethods()).isNull();
assertThat(authorizationServerMetadata.getClaimAsString("some-claim")).isEqualTo("some-value");
}
@Test
public void withClaimsWhenNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerMetadata.withClaims(null))
.withMessage("claims cannot be empty");
}
@Test
public void withClaimsWhenMissingRequiredClaimsThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerMetadata.withClaims(Collections.emptyMap()))
.withMessage("claims cannot be empty");
}
@Test
public void buildWhenCalledTwiceThenGeneratesTwoConfigurations() {
OAuth2AuthorizationServerMetadata first = this.minimalBuilder
.grantType("client_credentials")
.build();
OAuth2AuthorizationServerMetadata second = this.minimalBuilder
.claims((claims) ->
{
List<String> newGrantTypes = new ArrayList<>();
newGrantTypes.add("authorization_code");
newGrantTypes.add("custom_grant");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED, newGrantTypes);
}
)
.build();
assertThat(first.getGrantTypes()).containsExactly("client_credentials");
assertThat(second.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "custom_grant");
}
@Test
public void buildWhenMissingIssuerThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.ISSUER));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("issuer cannot be null");
}
@Test
public void buildWhenIssuerNotUrlThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.ISSUER, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("issuer must be a valid URL");
}
@Test
public void buildWhenMissingAuthorizationEndpointThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("authorizationEndpoint cannot be null");
}
@Test
public void buildWhenAuthorizationEndpointNotUrlThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("authorizationEndpoint must be a valid URL");
}
@Test
public void buildWhenMissingTokenEndpointThenThrowsIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenEndpoint cannot be null");
}
@Test
public void buildWhenTokenEndpointNotUrlThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenEndpoint must be a valid URL");
}
@Test
public void buildWhenTokenEndpointAuthenticationMethodsNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT_AUTH_METHODS_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("tokenEndpointAuthenticationMethods must be of type List");
}
@Test
public void buildWhenTokenEndpointAuthenticationMethodsEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT_AUTH_METHODS_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenEndpointAuthenticationMethods cannot be empty");
}
@Test
public void buildWhenTokenEndpointAuthenticationMethodsAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.tokenEndpointAuthenticationMethod("should-be-removed")
.tokenEndpointAuthenticationMethods(authMethods -> {
authMethods.clear();
authMethods.add("some-authentication-method");
})
.build();
assertThat(authorizationServerMetadata.getTokenEndpointAuthenticationMethods()).containsExactly("some-authentication-method");
}
@Test
public void buildWhenJwksUriNotUrlThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("jwksUri must be a valid URL");
}
@Test
public void buildWhenScopesNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("scopes must be of type List");
}
@Test
public void buildWhenScopesEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("scopes cannot be empty");
}
@Test
public void buildWhenScopesAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.scope("should-be-removed")
.scopes(scopes -> {
scopes.clear();
scopes.add("some-scope");
})
.build();
assertThat(authorizationServerMetadata.getScopes()).containsExactly("some-scope");
}
@Test
public void buildWhenMissingResponseTypesThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("responseTypes cannot be null");
}
@Test
public void buildWhenResponseTypesNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("responseTypes must be of type List");
}
@Test
public void buildWhenResponseTypesEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("responseTypes cannot be empty");
}
@Test
public void buildWhenResponseTypesAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.responseType("should-be-removed")
.responseTypes(responseTypes -> {
responseTypes.clear();
responseTypes.add("some-response-type");
})
.build();
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("some-response-type");
}
@Test
public void buildWhenResponseTypesNotPresentAndAddingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.claims(claims -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED))
.responseTypes(responseTypes -> responseTypes.add("some-response-type"))
.build();
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("some-response-type");
}
@Test
public void buildWhenGrantTypesNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("grantTypes must be of type List");
}
@Test
public void buildWhenGrantTypesEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("grantTypes cannot be empty");
}
@Test
public void buildWhenGrantTypesAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.grantType("should-be-removed")
.grantTypes(grantTypes -> {
grantTypes.clear();
grantTypes.add("some-grant-type");
})
.build();
assertThat(authorizationServerMetadata.getGrantTypes()).containsExactly("some-grant-type");
}
@Test
public void buildWhenTokenRevocationEndpointNotUrlThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.tokenRevocationEndpoint("not a valid URL");
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenRevocationEndpoint must be a valid URL");
}
@Test
public void buildWhenTokenRevocationEndpointAuthenticationMethodsNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.REVOCATION_ENDPOINT_AUTH_METHODS_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("tokenRevocationEndpointAuthenticationMethods must be of type List");
}
@Test
public void buildWhenTokenRevocationEndpointAuthenticationMethodsEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.REVOCATION_ENDPOINT_AUTH_METHODS_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenRevocationEndpointAuthenticationMethods cannot be empty");
}
@Test
public void buildWhenTokenRevocationEndpointAuthenticationMethodsAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.tokenRevocationEndpointAuthenticationMethod("should-be-removed")
.tokenRevocationEndpointAuthenticationMethods(authMethods -> {
authMethods.clear();
authMethods.add("some-authentication-method");
})
.build();
assertThat(authorizationServerMetadata.getTokenRevocationEndpointAuthenticationMethods()).containsExactly("some-authentication-method");
}
@Test
public void buildWhenTokenIntrospectionEndpointNotUrlThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.tokenIntrospectionEndpoint("not a valid URL");
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenIntrospectionEndpoint must be a valid URL");
}
@Test
public void buildWhenTokenIntrospectionEndpointAuthenticationMethodsNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.INTROSPECTION_ENDPOINT_AUTH_METHODS_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("tokenIntrospectionEndpointAuthenticationMethods must be of type List");
}
@Test
public void buildWhenTokenIntrospectionEndpointAuthenticationMethodsEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.INTROSPECTION_ENDPOINT_AUTH_METHODS_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenIntrospectionEndpointAuthenticationMethods cannot be empty");
}
@Test
public void buildWhenTokenIntrospectionEndpointAuthenticationMethodsAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.tokenIntrospectionEndpointAuthenticationMethod("should-be-removed")
.tokenIntrospectionEndpointAuthenticationMethods(authMethods -> {
authMethods.clear();
authMethods.add("some-authentication-method");
})
.build();
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpointAuthenticationMethods()).containsExactly("some-authentication-method");
}
@Test
public void buildWhenCodeChallengeMethodsNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.CODE_CHALLENGE_METHODS_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("codeChallengeMethods must be of type List");
}
@Test
public void buildWhenCodeChallengeMethodsEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.CODE_CHALLENGE_METHODS_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("codeChallengeMethods cannot be empty");
}
@Test
public void buildWhenCodeChallengeMethodsAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.minimalBuilder
.codeChallengeMethod("should-be-removed")
.codeChallengeMethods(codeChallengeMethods -> {
codeChallengeMethods.clear();
codeChallengeMethods.add("some-authentication-method");
})
.build();
assertThat(authorizationServerMetadata.getCodeChallengeMethods()).containsExactly("some-authentication-method");
}
@Test
public void claimWhenNameNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerMetadata.builder().claim(null, "claim-value"))
.withMessage("name cannot be empty");
}
@Test
public void claimWhenValueNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerMetadata.builder().claim("claim-name", null))
.withMessage("value cannot be null");
}
@Test
public void claimsWhenRemovingClaimThenNotPresent() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata =
this.minimalBuilder
.claim("claim-name", "claim-value")
.claims((claims) -> claims.remove("claim-name"))
.build();
assertThat(authorizationServerMetadata.containsClaim("claim-name")).isFalse();
}
@Test
public void claimsWhenAddingClaimThenPresent() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata =
this.minimalBuilder
.claim("claim-name", "claim-value")
.build();
assertThat(authorizationServerMetadata.containsClaim("claim-name")).isTrue();
}
private static URL url(String urlString) {
try {
return new URL(urlString);
} catch (Exception ex) {
throw new IllegalArgumentException("urlString must be a valid URL and valid URI");
}
}
}

View File

@@ -1,451 +0,0 @@
/*
* Copyright 2020 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.core.endpoint;
import org.junit.Test;
import org.springframework.security.oauth2.core.OAuth2AuthorizationServerMetadataClaimNames;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationServerConfiguration.Builder;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link OAuth2AuthorizationServerConfiguration}.
*
* @author Daniel Garnier-Moiroux
*/
public class OAuth2AuthorizationServerConfigurationTests {
private final Builder minimalConfigurationBuilder =
OAuth2AuthorizationServerConfiguration.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code");
@Test
public void buildWhenAllRequiredClaimsAndAdditionalClaimsThenCreated() {
OAuth2AuthorizationServerConfiguration authorizationServerConfiguration = OAuth2AuthorizationServerConfiguration.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.tokenRevocationEndpoint("https://example.com/issuer1/oauth2/revoke")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.grantType("authorization_code")
.grantType("client_credentials")
.tokenEndpointAuthenticationMethod("client_secret_basic")
.tokenRevocationEndpointAuthenticationMethod("client_secret_basic")
.codeChallengeMethod("plain")
.codeChallengeMethod("S256")
.claim("a-claim", "a-value")
.build();
assertThat(authorizationServerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerConfiguration.getTokenRevocationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/revoke"));
assertThat(authorizationServerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerConfiguration.getScopes()).containsExactly("openid");
assertThat(authorizationServerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerConfiguration.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "client_credentials");
assertThat(authorizationServerConfiguration.getTokenEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerConfiguration.getTokenRevocationEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerConfiguration.getCodeChallengeMethods()).containsExactlyInAnyOrder("plain", "S256");
assertThat(authorizationServerConfiguration.getClaimAsString("a-claim")).isEqualTo("a-value");
}
@Test
public void buildWhenOnlyRequiredClaimsThenCreated() {
OAuth2AuthorizationServerConfiguration authorizationServerConfiguration = OAuth2AuthorizationServerConfiguration.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.build();
assertThat(authorizationServerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerConfiguration.getScopes()).containsExactly("openid");
assertThat(authorizationServerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerConfiguration.getGrantTypes()).isNull();
assertThat(authorizationServerConfiguration.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerConfiguration.getTokenRevocationEndpoint()).isNull();
assertThat(authorizationServerConfiguration.getTokenRevocationEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerConfiguration.getCodeChallengeMethods()).isNull();
}
@Test
public void buildFromClaimsThenCreated() {
HashMap<String, Object> claims = new HashMap<>();
claims.put(OAuth2AuthorizationServerMetadataClaimNames.ISSUER, "https://example.com/issuer1");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT, "https://example.com/issuer1/oauth2/authorize");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT, "https://example.com/issuer1/oauth2/token");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI, "https://example.com/issuer1/oauth2/jwks");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED, Collections.singletonList("openid"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, Collections.singletonList("code"));
claims.put("some-claim", "some-value");
OAuth2AuthorizationServerConfiguration authorizationServerConfiguration = OAuth2AuthorizationServerConfiguration.withClaims(claims).build();
assertThat(authorizationServerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerConfiguration.getScopes()).containsExactly("openid");
assertThat(authorizationServerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerConfiguration.getGrantTypes()).isNull();
assertThat(authorizationServerConfiguration.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerConfiguration.getTokenRevocationEndpoint()).isNull();
assertThat(authorizationServerConfiguration.getTokenRevocationEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerConfiguration.getCodeChallengeMethods()).isNull();
assertThat(authorizationServerConfiguration.getClaimAsString("some-claim")).isEqualTo("some-value");
}
@Test
public void buildFromClaimsWhenUsingUrlsThenCreated() {
HashMap<String, Object> claims = new HashMap<>();
claims.put(OAuth2AuthorizationServerMetadataClaimNames.ISSUER, url("https://example.com/issuer1"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT, url("https://example.com/issuer1/oauth2/authorize"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT, url("https://example.com/issuer1/oauth2/token"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.REVOCATION_ENDPOINT, url("https://example.com/issuer1/oauth2/revoke"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI, url("https://example.com/issuer1/oauth2/jwks"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.SCOPES_SUPPORTED, Collections.singletonList("openid"));
claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, Collections.singletonList("code"));
claims.put("some-claim", "some-value");
OAuth2AuthorizationServerConfiguration authorizationServerConfiguration = OAuth2AuthorizationServerConfiguration.withClaims(claims).build();
assertThat(authorizationServerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(authorizationServerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerConfiguration.getTokenRevocationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/revoke"));
assertThat(authorizationServerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerConfiguration.getScopes()).containsExactly("openid");
assertThat(authorizationServerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerConfiguration.getGrantTypes()).isNull();
assertThat(authorizationServerConfiguration.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerConfiguration.getTokenRevocationEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerConfiguration.getCodeChallengeMethods()).isNull();
assertThat(authorizationServerConfiguration.getClaimAsString("some-claim")).isEqualTo("some-value");
}
@Test
public void withClaimsWhenNullThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerConfiguration.withClaims(null))
.withMessage("claims cannot be empty");
}
@Test
public void withClaimsWhenMissingRequiredClaimsThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerConfiguration.withClaims(Collections.emptyMap()))
.withMessage("claims cannot be empty");
}
@Test
public void buildWhenCalledTwiceThenGeneratesTwoConfigurations() {
OAuth2AuthorizationServerConfiguration first = this.minimalConfigurationBuilder
.grantType("client_credentials")
.build();
OAuth2AuthorizationServerConfiguration second = this.minimalConfigurationBuilder
.claims((claims) ->
{
LinkedHashSet<String> newGrantTypes = new LinkedHashSet<>();
newGrantTypes.add("authorization_code");
newGrantTypes.add("custom_grant");
claims.put(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED, newGrantTypes);
}
)
.build();
assertThat(first.getGrantTypes()).containsExactly("client_credentials");
assertThat(second.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "custom_grant");
}
@Test
public void buildWhenEmptyClaimsThenOmitted() {
OAuth2AuthorizationServerConfiguration authorizationServerConfiguration = this.minimalConfigurationBuilder
.claim("some-claim", Collections.emptyList())
.claims(claims -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED, Collections.emptyList()))
.build();
assertThat(authorizationServerConfiguration.getClaimAsStringList("some-claim")).isNull();
assertThat(authorizationServerConfiguration.getClaimAsStringList(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED)).isNull();
}
@Test
public void buildWhenMissingIssuerThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.ISSUER));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("issuer cannot be null");
}
@Test
public void buildWhenIssuerIsNotAnUrlThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.ISSUER, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("issuer must be a valid URL");
}
@Test
public void buildWhenMissingAuthorizationEndpointThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("authorizationEndpoint cannot be null");
}
@Test
public void buildWhenAuthorizationEndpointIsNotAnUrlThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.AUTHORIZATION_ENDPOINT, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("authorizationEndpoint must be a valid URL");
}
@Test
public void buildWhenMissingTokenEndpointThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenEndpoint cannot be null");
}
@Test
public void buildWhenTokenEndpointIsNotAnUrlThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.TOKEN_ENDPOINT, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("tokenEndpoint must be a valid URL");
}
@Test
public void buildWhenMissingJwksUriThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("jwksUri cannot be null");
}
@Test
public void buildWhenJwksUriIsNotAnUrlThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.JWKS_URI, "not an url"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("jwksUri must be a valid URL");
}
@Test
public void buildWhenMissingResponseTypesThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("responseTypes cannot be null");
}
@Test
public void buildWhenResponseTypesNotListThenThrowIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, "not-a-list"));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessageStartingWith("responseTypes must be of type List");
}
@Test
public void buildWhenResponseTypesEmptyListThenThrowIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED, Collections.emptyList()));
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("responseTypes cannot be empty");
}
@Test
public void buildWhenInvalidTokenRevocationEndpointThenThrowsIllegalArgumentException() {
Builder builder = this.minimalConfigurationBuilder
.tokenRevocationEndpoint("not a valid URL");
assertThatIllegalArgumentException()
.isThrownBy(builder::build)
.withMessage("tokenRevocationEndpoint must be a valid URL");
}
@Test
public void responseTypesWhenAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerConfiguration configuration = this.minimalConfigurationBuilder
.responseType("should-be-removed")
.responseTypes(responseTypes -> {
responseTypes.clear();
responseTypes.add("some-response-type");
})
.build();
assertThat(configuration.getResponseTypes()).containsExactly("some-response-type");
}
@Test
public void responseTypesWhenNotPresentAndAddingThenCorrectValues() {
OAuth2AuthorizationServerConfiguration configuration = this.minimalConfigurationBuilder
.claims(claims -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.RESPONSE_TYPES_SUPPORTED))
.responseTypes(responseTypes -> responseTypes.add("some-response-type"))
.build();
assertThat(configuration.getResponseTypes()).containsExactly("some-response-type");
}
@Test
public void scopesWhenAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerConfiguration configuration = this.minimalConfigurationBuilder
.scope("should-be-removed")
.scopes(scopes -> {
scopes.clear();
scopes.add("some-scope");
})
.build();
assertThat(configuration.getScopes()).containsExactly("some-scope");
}
@Test
public void grantTypesWhenAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerConfiguration configuration = this.minimalConfigurationBuilder
.grantType("should-be-removed")
.grantTypes(grantTypes -> {
grantTypes.clear();
grantTypes.add("some-grant-type");
})
.build();
assertThat(configuration.getGrantTypes()).containsExactly("some-grant-type");
}
@Test
public void tokenEndpointAuthenticationMethodsWhenAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerConfiguration configuration = this.minimalConfigurationBuilder
.tokenEndpointAuthenticationMethod("should-be-removed")
.tokenEndpointAuthenticationMethods(authMethods -> {
authMethods.clear();
authMethods.add("some-authentication-method");
})
.build();
assertThat(configuration.getTokenEndpointAuthenticationMethods()).containsExactly("some-authentication-method");
}
@Test
public void tokenRevocationEndpointAuthenticationMethodsWhenAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerConfiguration configuration = this.minimalConfigurationBuilder
.tokenRevocationEndpointAuthenticationMethod("should-be-removed")
.tokenRevocationEndpointAuthenticationMethods(authMethods -> {
authMethods.clear();
authMethods.add("some-authentication-method");
})
.build();
assertThat(configuration.getTokenRevocationEndpointAuthenticationMethods()).containsExactly("some-authentication-method");
}
@Test
public void codeChallengeMethodsMethodsWhenAddingOrRemovingThenCorrectValues() {
OAuth2AuthorizationServerConfiguration configuration = this.minimalConfigurationBuilder
.codeChallengeMethod("should-be-removed")
.codeChallengeMethods(codeChallengeMethods -> {
codeChallengeMethods.clear();
codeChallengeMethods.add("some-authentication-method");
})
.build();
assertThat(configuration.getCodeChallengeMethods()).containsExactly("some-authentication-method");
}
@Test
public void claimWhenNameIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerConfiguration.builder().claim(null, "value"))
.withMessage("name cannot be empty");
}
@Test
public void claimWhenValueIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> OAuth2AuthorizationServerConfiguration.builder().claim("claim-name", null))
.withMessage("value cannot be null");
}
@Test
public void claimsWhenRemovingClaimThenNotPresent() {
OAuth2AuthorizationServerConfiguration configuration =
this.minimalConfigurationBuilder
.grantType("some-grant-type")
.claims((claims) -> claims.remove(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED))
.build();
assertThat(configuration.getGrantTypes()).isNull();
}
@Test
public void claimsWhenAddingClaimThenPresent() {
OAuth2AuthorizationServerConfiguration configuration =
this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OAuth2AuthorizationServerMetadataClaimNames.GRANT_TYPES_SUPPORTED, "authorization_code"))
.build();
assertThat(configuration.getGrantTypes()).containsExactly("authorization_code");
}
private static URL url(String urlString) {
try {
return new URL(urlString);
} catch (Exception ex) {
throw new IllegalArgumentException("urlString must be a valid URL and valid URI");
}
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2020 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.core.endpoint;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* TODO
* This class is temporary and will be removed after upgrading to Spring Security 5.5.0 GA.
*
* Tests for {@link PkceCodeChallengeMethod2}.
*
* @author Daniel Garnier-Moiroux
*/
public class PkceCodeChallengeMethod2Test {
@Test
public void getValueWhenCodeChallengeMethodPlainThenReturnPlain() {
assertThat(PkceCodeChallengeMethod2.PLAIN.getValue()).isEqualTo("plain");
}
@Test
public void getValueWhenCodeChallengeMethodS256ThenReturnS256() {
assertThat(PkceCodeChallengeMethod2.S256.getValue()).isEqualTo("S256");
}
}

View File

@@ -1,218 +0,0 @@
/*
* Copyright 2020 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.core.http.converter;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationServerConfiguration;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link OAuth2AuthorizationServerConfigurationHttpMessageConverter}
*
* @author Daniel Garnier-Moiroux
*/
public class OAuth2AuthorizationServerConfigurationHttpMessageConverterTests {
private final OAuth2AuthorizationServerConfigurationHttpMessageConverter messageConverter = new OAuth2AuthorizationServerConfigurationHttpMessageConverter();
@Test
public void supportsWhenOAuth2AuthorizationServerConfigurationThenTrue() {
assertThat(this.messageConverter.supports(OAuth2AuthorizationServerConfiguration.class)).isTrue();
}
@Test
public void setAuthorizationServerConfigurationParametersConverterWhenConverterIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.messageConverter.setAuthorizationServerConfigurationParametersConverter(null));
}
@Test
public void setAuthorizationServerConfigurationConverterWhenConverterIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.messageConverter.setAuthorizationServerConfigurationConverter(null));
}
@Test
public void readInternalWhenRequiredParametersThenSuccess() throws Exception {
// @formatter:off
String serverConfigurationResponse = "{\n"
+ " \"issuer\": \"https://example.com/issuer1\",\n"
+ " \"authorization_endpoint\": \"https://example.com/issuer1/oauth2/authorize\",\n"
+ " \"token_endpoint\": \"https://example.com/issuer1/oauth2/token\",\n"
+ " \"jwks_uri\": \"https://example.com/issuer1/oauth2/jwks\",\n"
+ " \"response_types_supported\": [\"code\"]\n"
+ "}\n";
// @formatter:on
MockClientHttpResponse response = new MockClientHttpResponse(serverConfigurationResponse.getBytes(), HttpStatus.OK);
OAuth2AuthorizationServerConfiguration serverConfiguration = this.messageConverter
.readInternal(OAuth2AuthorizationServerConfiguration.class, response);
assertThat(serverConfiguration.getIssuer()).isEqualTo(new URL("https://example.com/issuer1"));
assertThat(serverConfiguration.getAuthorizationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/authorize"));
assertThat(serverConfiguration.getTokenEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/token"));
assertThat(serverConfiguration.getJwkSetUri()).isEqualTo(new URL("https://example.com/issuer1/oauth2/jwks"));
assertThat(serverConfiguration.getResponseTypes()).containsExactly("code");
assertThat(serverConfiguration.getScopes()).isNull();
assertThat(serverConfiguration.getGrantTypes()).isNull();
assertThat(serverConfiguration.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(serverConfiguration.getCodeChallengeMethods()).isNull();
assertThat(serverConfiguration.getTokenRevocationEndpoint()).isNull();
assertThat(serverConfiguration.getTokenRevocationEndpointAuthenticationMethods()).isNull();
}
@Test
public void readInternalWhenValidParametersThenSuccess() throws Exception {
// @formatter:off
String serverConfigurationResponse = "{\n"
+ " \"issuer\": \"https://example.com/issuer1\",\n"
+ " \"authorization_endpoint\": \"https://example.com/issuer1/oauth2/authorize\",\n"
+ " \"token_endpoint\": \"https://example.com/issuer1/oauth2/token\",\n"
+ " \"revocation_endpoint\": \"https://example.com/issuer1/oauth2/revoke\",\n"
+ " \"jwks_uri\": \"https://example.com/issuer1/oauth2/jwks\",\n"
+ " \"response_types_supported\": [\"code\"],\n"
+ " \"grant_types_supported\": [\"authorization_code\", \"client_credentials\"],\n"
+ " \"scopes_supported\": [\"openid\"],\n"
+ " \"token_endpoint_auth_methods_supported\": [\"client_secret_basic\"],\n"
+ " \"revocation_endpoint_auth_methods_supported\": [\"client_secret_basic\"],\n"
+ " \"code_challenge_methods_supported\": [\"plain\",\"S256\"],\n"
+ " \"custom_claim\": \"value\",\n"
+ " \"custom_collection_claim\": [\"value1\", \"value2\"]\n"
+ "}\n";
// @formatter:on
MockClientHttpResponse response = new MockClientHttpResponse(serverConfigurationResponse.getBytes(), HttpStatus.OK);
OAuth2AuthorizationServerConfiguration serverConfiguration = this.messageConverter
.readInternal(OAuth2AuthorizationServerConfiguration.class, response);
assertThat(serverConfiguration.getClaims()).hasSize(13);
assertThat(serverConfiguration.getIssuer()).isEqualTo(new URL("https://example.com/issuer1"));
assertThat(serverConfiguration.getAuthorizationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/authorize"));
assertThat(serverConfiguration.getTokenEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/token"));
assertThat(serverConfiguration.getTokenRevocationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/revoke"));
assertThat(serverConfiguration.getJwkSetUri()).isEqualTo(new URL("https://example.com/issuer1/oauth2/jwks"));
assertThat(serverConfiguration.getResponseTypes()).containsExactly("code");
assertThat(serverConfiguration.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "client_credentials");
assertThat(serverConfiguration.getScopes()).containsExactly("openid");
assertThat(serverConfiguration.getTokenEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(serverConfiguration.getTokenRevocationEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(serverConfiguration.getCodeChallengeMethods()).containsExactlyInAnyOrder("plain", "S256");
assertThat(serverConfiguration.getClaimAsString("custom_claim")).isEqualTo("value");
assertThat(serverConfiguration.getClaimAsStringList("custom_collection_claim")).containsExactlyInAnyOrder("value1", "value2");
}
@Test
public void readInternalWhenFailingConverterThenThrowException() {
String errorMessage = "this is not a valid converter";
this.messageConverter.setAuthorizationServerConfigurationConverter(source -> {
throw new RuntimeException(errorMessage);
});
MockClientHttpResponse response = new MockClientHttpResponse("{}".getBytes(), HttpStatus.OK);
assertThatExceptionOfType(HttpMessageNotReadableException.class)
.isThrownBy(() -> this.messageConverter.readInternal(OAuth2AuthorizationServerConfiguration.class, response))
.withMessageContaining("An error occurred reading the OAuth 2.0 Authorization Server Configuration")
.withMessageContaining(errorMessage);
}
@Test
public void readInternalWhenInvalidOAuth2AuthorizationServerConfigurationThenThrowException() {
String providerConfigurationResponse = "{ \"issuer\": null }";
MockClientHttpResponse response = new MockClientHttpResponse(providerConfigurationResponse.getBytes(), HttpStatus.OK);
assertThatExceptionOfType(HttpMessageNotReadableException.class)
.isThrownBy(() -> this.messageConverter.readInternal(OAuth2AuthorizationServerConfiguration.class, response))
.withMessageContaining("An error occurred reading the OAuth 2.0 Authorization Server Configuration")
.withMessageContaining("issuer cannot be null");
}
@Test
public void writeInternalWhenOAuth2AuthorizationServerConfigurationThenSuccess() {
OAuth2AuthorizationServerConfiguration serverConfiguration =
OAuth2AuthorizationServerConfiguration
.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.tokenRevocationEndpoint("https://example.com/issuer1/oauth2/revoke")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.grantType("authorization_code")
.grantType("client_credentials")
.tokenEndpointAuthenticationMethod("client_secret_basic")
.tokenRevocationEndpointAuthenticationMethod("client_secret_basic")
.codeChallengeMethod("plain")
.codeChallengeMethod("S256")
.claim("custom_claim", "value")
.claim("custom_collection_claim", Arrays.asList("value1", "value2"))
.build();
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
this.messageConverter.writeInternal(serverConfiguration, outputMessage);
String serverConfigurationResponse = outputMessage.getBodyAsString();
assertThat(serverConfigurationResponse).contains("\"issuer\":\"https://example.com/issuer1\"");
assertThat(serverConfigurationResponse).contains("\"authorization_endpoint\":\"https://example.com/issuer1/oauth2/authorize\"");
assertThat(serverConfigurationResponse).contains("\"token_endpoint\":\"https://example.com/issuer1/oauth2/token\"");
assertThat(serverConfigurationResponse).contains("\"revocation_endpoint\":\"https://example.com/issuer1/oauth2/revoke\"");
assertThat(serverConfigurationResponse).contains("\"jwks_uri\":\"https://example.com/issuer1/oauth2/jwks\"");
assertThat(serverConfigurationResponse).contains("\"scopes_supported\":[\"openid\"]");
assertThat(serverConfigurationResponse).contains("\"response_types_supported\":[\"code\"]");
assertThat(serverConfigurationResponse).contains("\"grant_types_supported\":[\"authorization_code\",\"client_credentials\"]");
assertThat(serverConfigurationResponse).contains("\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\"]");
assertThat(serverConfigurationResponse).contains("\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\"]");
assertThat(serverConfigurationResponse).contains("\"code_challenge_methods_supported\":[\"plain\",\"S256\"]");
assertThat(serverConfigurationResponse).contains("\"custom_claim\":\"value\"");
assertThat(serverConfigurationResponse).contains("\"custom_collection_claim\":[\"value1\",\"value2\"]");
}
@Test
public void writeInternalWhenWriteFailsThenThrowsException() {
String errorMessage = "this is not a valid converter";
Converter<OAuth2AuthorizationServerConfiguration, Map<String, Object>> failingConverter =
source -> {
throw new RuntimeException(errorMessage);
};
this.messageConverter.setAuthorizationServerConfigurationParametersConverter(failingConverter);
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
OAuth2AuthorizationServerConfiguration serverConfiguration =
OAuth2AuthorizationServerConfiguration
.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.responseType("code")
.build();
assertThatExceptionOfType(HttpMessageNotWritableException.class)
.isThrownBy(() -> this.messageConverter.writeInternal(serverConfiguration, outputMessage))
.withMessageContaining("An error occurred writing the OAuth 2.0 Authorization Server Configuration")
.withMessageContaining(errorMessage);
}
}

View File

@@ -0,0 +1,224 @@
/*
* Copyright 2020-2021 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.core.http.converter;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.security.oauth2.core.OAuth2AuthorizationServerMetadata;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link OAuth2AuthorizationServerMetadataHttpMessageConverter}
*
* @author Daniel Garnier-Moiroux
*/
public class OAuth2AuthorizationServerMetadataHttpMessageConverterTests {
private final OAuth2AuthorizationServerMetadataHttpMessageConverter messageConverter = new OAuth2AuthorizationServerMetadataHttpMessageConverter();
@Test
public void supportsWhenOAuth2AuthorizationServerMetadataThenTrue() {
assertThat(this.messageConverter.supports(OAuth2AuthorizationServerMetadata.class)).isTrue();
}
@Test
public void setAuthorizationServerMetadataParametersConverterWhenConverterIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.messageConverter.setAuthorizationServerMetadataParametersConverter(null));
}
@Test
public void setAuthorizationServerMetadataConverterWhenConverterIsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.messageConverter.setAuthorizationServerMetadataConverter(null));
}
@Test
public void readInternalWhenRequiredParametersThenSuccess() throws Exception {
// @formatter:off
String authorizationServerMetadataResponse = "{\n"
+ " \"issuer\": \"https://example.com/issuer1\",\n"
+ " \"authorization_endpoint\": \"https://example.com/issuer1/oauth2/authorize\",\n"
+ " \"token_endpoint\": \"https://example.com/issuer1/oauth2/token\",\n"
+ " \"response_types_supported\": [\"code\"]\n"
+ "}\n";
// @formatter:on
MockClientHttpResponse response = new MockClientHttpResponse(authorizationServerMetadataResponse.getBytes(), HttpStatus.OK);
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.messageConverter
.readInternal(OAuth2AuthorizationServerMetadata.class, response);
assertThat(authorizationServerMetadata.getIssuer()).isEqualTo(new URL("https://example.com/issuer1"));
assertThat(authorizationServerMetadata.getAuthorizationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerMetadata.getTokenEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerMetadata.getTokenEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getJwkSetUrl()).isNull();
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerMetadata.getScopes()).isNull();
assertThat(authorizationServerMetadata.getGrantTypes()).isNull();
assertThat(authorizationServerMetadata.getTokenRevocationEndpoint()).isNull();
assertThat(authorizationServerMetadata.getTokenRevocationEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpoint()).isNull();
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpointAuthenticationMethods()).isNull();
assertThat(authorizationServerMetadata.getCodeChallengeMethods()).isNull();
}
@Test
public void readInternalWhenValidParametersThenSuccess() throws Exception {
// @formatter:off
String authorizationServerMetadataResponse = "{\n"
+ " \"issuer\": \"https://example.com/issuer1\",\n"
+ " \"authorization_endpoint\": \"https://example.com/issuer1/oauth2/authorize\",\n"
+ " \"token_endpoint\": \"https://example.com/issuer1/oauth2/token\",\n"
+ " \"token_endpoint_auth_methods_supported\": [\"client_secret_basic\"],\n"
+ " \"jwks_uri\": \"https://example.com/issuer1/oauth2/jwks\",\n"
+ " \"scopes_supported\": [\"openid\"],\n"
+ " \"response_types_supported\": [\"code\"],\n"
+ " \"grant_types_supported\": [\"authorization_code\", \"client_credentials\"],\n"
+ " \"revocation_endpoint\": \"https://example.com/issuer1/oauth2/revoke\",\n"
+ " \"revocation_endpoint_auth_methods_supported\": [\"client_secret_basic\"],\n"
+ " \"introspection_endpoint\": \"https://example.com/issuer1/oauth2/introspect\",\n"
+ " \"introspection_endpoint_auth_methods_supported\": [\"client_secret_basic\"],\n"
+ " \"code_challenge_methods_supported\": [\"plain\",\"S256\"],\n"
+ " \"custom_claim\": \"value\",\n"
+ " \"custom_collection_claim\": [\"value1\", \"value2\"]\n"
+ "}\n";
// @formatter:on
MockClientHttpResponse response = new MockClientHttpResponse(authorizationServerMetadataResponse.getBytes(), HttpStatus.OK);
OAuth2AuthorizationServerMetadata authorizationServerMetadata = this.messageConverter
.readInternal(OAuth2AuthorizationServerMetadata.class, response);
assertThat(authorizationServerMetadata.getClaims()).hasSize(15);
assertThat(authorizationServerMetadata.getIssuer()).isEqualTo(new URL("https://example.com/issuer1"));
assertThat(authorizationServerMetadata.getAuthorizationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/authorize"));
assertThat(authorizationServerMetadata.getTokenEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/token"));
assertThat(authorizationServerMetadata.getTokenEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerMetadata.getJwkSetUrl()).isEqualTo(new URL("https://example.com/issuer1/oauth2/jwks"));
assertThat(authorizationServerMetadata.getScopes()).containsExactly("openid");
assertThat(authorizationServerMetadata.getResponseTypes()).containsExactly("code");
assertThat(authorizationServerMetadata.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "client_credentials");
assertThat(authorizationServerMetadata.getTokenRevocationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/revoke"));
assertThat(authorizationServerMetadata.getTokenRevocationEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/introspect"));
assertThat(authorizationServerMetadata.getTokenIntrospectionEndpointAuthenticationMethods()).containsExactly("client_secret_basic");
assertThat(authorizationServerMetadata.getCodeChallengeMethods()).containsExactlyInAnyOrder("plain", "S256");
assertThat(authorizationServerMetadata.getClaimAsString("custom_claim")).isEqualTo("value");
assertThat(authorizationServerMetadata.getClaimAsStringList("custom_collection_claim")).containsExactlyInAnyOrder("value1", "value2");
}
@Test
public void readInternalWhenFailingConverterThenThrowException() {
String errorMessage = "this is not a valid converter";
this.messageConverter.setAuthorizationServerMetadataConverter(source -> {
throw new RuntimeException(errorMessage);
});
MockClientHttpResponse response = new MockClientHttpResponse("{}".getBytes(), HttpStatus.OK);
assertThatExceptionOfType(HttpMessageNotReadableException.class)
.isThrownBy(() -> this.messageConverter.readInternal(OAuth2AuthorizationServerMetadata.class, response))
.withMessageContaining("An error occurred reading the OAuth 2.0 Authorization Server Metadata")
.withMessageContaining(errorMessage);
}
@Test
public void readInternalWhenInvalidOAuth2AuthorizationServerMetadataThenThrowException() {
String authorizationServerMetadataResponse = "{ \"issuer\": null }";
MockClientHttpResponse response = new MockClientHttpResponse(authorizationServerMetadataResponse.getBytes(), HttpStatus.OK);
assertThatExceptionOfType(HttpMessageNotReadableException.class)
.isThrownBy(() -> this.messageConverter.readInternal(OAuth2AuthorizationServerMetadata.class, response))
.withMessageContaining("An error occurred reading the OAuth 2.0 Authorization Server Metadata")
.withMessageContaining("issuer cannot be null");
}
@Test
public void writeInternalWhenOAuth2AuthorizationServerMetadataThenSuccess() {
OAuth2AuthorizationServerMetadata authorizationServerMetadata =
OAuth2AuthorizationServerMetadata.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.tokenEndpointAuthenticationMethod("client_secret_basic")
.jwkSetUrl("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.grantType("authorization_code")
.grantType("client_credentials")
.tokenRevocationEndpoint("https://example.com/issuer1/oauth2/revoke")
.tokenRevocationEndpointAuthenticationMethod("client_secret_basic")
.tokenIntrospectionEndpoint("https://example.com/issuer1/oauth2/introspect")
.tokenIntrospectionEndpointAuthenticationMethod("client_secret_basic")
.codeChallengeMethod("plain")
.codeChallengeMethod("S256")
.claim("custom_claim", "value")
.claim("custom_collection_claim", Arrays.asList("value1", "value2"))
.build();
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
this.messageConverter.writeInternal(authorizationServerMetadata, outputMessage);
String authorizationServerMetadataResponse = outputMessage.getBodyAsString();
assertThat(authorizationServerMetadataResponse).contains("\"issuer\":\"https://example.com/issuer1\"");
assertThat(authorizationServerMetadataResponse).contains("\"authorization_endpoint\":\"https://example.com/issuer1/oauth2/authorize\"");
assertThat(authorizationServerMetadataResponse).contains("\"token_endpoint\":\"https://example.com/issuer1/oauth2/token\"");
assertThat(authorizationServerMetadataResponse).contains("\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\"]");
assertThat(authorizationServerMetadataResponse).contains("\"jwks_uri\":\"https://example.com/issuer1/oauth2/jwks\"");
assertThat(authorizationServerMetadataResponse).contains("\"scopes_supported\":[\"openid\"]");
assertThat(authorizationServerMetadataResponse).contains("\"response_types_supported\":[\"code\"]");
assertThat(authorizationServerMetadataResponse).contains("\"grant_types_supported\":[\"authorization_code\",\"client_credentials\"]");
assertThat(authorizationServerMetadataResponse).contains("\"revocation_endpoint\":\"https://example.com/issuer1/oauth2/revoke\"");
assertThat(authorizationServerMetadataResponse).contains("\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\"]");
assertThat(authorizationServerMetadataResponse).contains("\"introspection_endpoint\":\"https://example.com/issuer1/oauth2/introspect\"");
assertThat(authorizationServerMetadataResponse).contains("\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\"]");
assertThat(authorizationServerMetadataResponse).contains("\"code_challenge_methods_supported\":[\"plain\",\"S256\"]");
assertThat(authorizationServerMetadataResponse).contains("\"custom_claim\":\"value\"");
assertThat(authorizationServerMetadataResponse).contains("\"custom_collection_claim\":[\"value1\",\"value2\"]");
}
@Test
public void writeInternalWhenWriteFailsThenThrowException() {
String errorMessage = "this is not a valid converter";
Converter<OAuth2AuthorizationServerMetadata, Map<String, Object>> failingConverter =
source -> {
throw new RuntimeException(errorMessage);
};
this.messageConverter.setAuthorizationServerMetadataParametersConverter(failingConverter);
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
OAuth2AuthorizationServerMetadata authorizationServerMetadata =
OAuth2AuthorizationServerMetadata.builder()
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.responseType("code")
.build();
assertThatExceptionOfType(HttpMessageNotWritableException.class)
.isThrownBy(() -> this.messageConverter.writeInternal(authorizationServerMetadata, outputMessage))
.withMessageContaining("An error occurred writing the OAuth 2.0 Authorization Server Metadata")
.withMessageContaining(errorMessage);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 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.
@@ -15,14 +15,14 @@
*/
package org.springframework.security.oauth2.core.oidc;
import org.junit.Test;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -38,7 +38,7 @@ public class OidcProviderConfigurationTests {
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.jwkSetUrl("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.subjectType("public")
@@ -50,7 +50,7 @@ public class OidcProviderConfigurationTests {
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.jwkSetUrl("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.grantType("authorization_code")
@@ -64,7 +64,7 @@ public class OidcProviderConfigurationTests {
assertThat(providerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(providerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(providerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(providerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getJwkSetUrl()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getScopes()).containsExactly("openid");
assertThat(providerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(providerConfiguration.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "client_credentials");
@@ -80,7 +80,7 @@ public class OidcProviderConfigurationTests {
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.jwkSetUrl("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.subjectType("public")
@@ -90,7 +90,7 @@ public class OidcProviderConfigurationTests {
assertThat(providerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(providerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(providerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(providerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getJwkSetUrl()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getScopes()).containsExactly("openid");
assertThat(providerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(providerConfiguration.getGrantTypes()).isNull();
@@ -117,7 +117,7 @@ public class OidcProviderConfigurationTests {
assertThat(providerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(providerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(providerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(providerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getJwkSetUrl()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getScopes()).containsExactly("openid");
assertThat(providerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(providerConfiguration.getGrantTypes()).isNull();
@@ -145,7 +145,7 @@ public class OidcProviderConfigurationTests {
assertThat(providerConfiguration.getIssuer()).isEqualTo(url("https://example.com/issuer1"));
assertThat(providerConfiguration.getAuthorizationEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/authorize"));
assertThat(providerConfiguration.getTokenEndpoint()).isEqualTo(url("https://example.com/issuer1/oauth2/token"));
assertThat(providerConfiguration.getJwkSetUri()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getJwkSetUrl()).isEqualTo(url("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getScopes()).containsExactly("openid");
assertThat(providerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(providerConfiguration.getGrantTypes()).isNull();
@@ -178,7 +178,7 @@ public class OidcProviderConfigurationTests {
OidcProviderConfiguration second = this.minimalConfigurationBuilder
.claims((claims) ->
{
Set<String> newGrantTypes = new LinkedHashSet<>();
List<String> newGrantTypes = new ArrayList<>();
newGrantTypes.add("authorization_code");
newGrantTypes.add("custom_grant");
claims.put(OidcProviderMetadataClaimNames.GRANT_TYPES_SUPPORTED, newGrantTypes);
@@ -190,17 +190,6 @@ public class OidcProviderConfigurationTests {
assertThat(second.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "custom_grant");
}
@Test
public void buildWhenEmptyClaimsThenOmitted() {
OidcProviderConfiguration providerConfiguration = this.minimalConfigurationBuilder
.claim("some-claim", Collections.emptyList())
.claims(claims -> claims.put(OidcProviderMetadataClaimNames.GRANT_TYPES_SUPPORTED, Collections.emptyList()))
.build();
assertThat(providerConfiguration.getClaimAsStringList("some-claim")).isNull();
assertThat(providerConfiguration.getClaimAsStringList(OidcProviderMetadataClaimNames.GRANT_TYPES_SUPPORTED)).isNull();
}
@Test
public void buildWhenMissingIssuerThenThrowIllegalArgumentException() {
OidcProviderConfiguration.Builder builder = this.minimalConfigurationBuilder
@@ -505,9 +494,9 @@ public class OidcProviderConfigurationTests {
public void claimsWhenAddingClaimThenPresent() {
OidcProviderConfiguration configuration =
this.minimalConfigurationBuilder
.claims((claims) -> claims.put(OidcProviderMetadataClaimNames.GRANT_TYPES_SUPPORTED, "authorization_code"))
.claim("claim-name", "claim-value")
.build();
assertThat(configuration.getGrantTypes()).containsExactly("authorization_code");
assertThat(configuration.containsClaim("claim-name")).isTrue();
}
private static URL url(String urlString) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 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.
@@ -15,7 +15,12 @@
*/
package org.springframework.security.oauth2.core.oidc.http.converter;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
@@ -24,10 +29,6 @@ import org.springframework.mock.http.MockHttpOutputMessage;
import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.security.oauth2.core.oidc.OidcProviderConfiguration;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -75,7 +76,7 @@ public class OidcProviderConfigurationHttpMessageConverterTests {
assertThat(providerConfiguration.getIssuer()).isEqualTo(new URL("https://example.com/issuer1"));
assertThat(providerConfiguration.getAuthorizationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/authorize"));
assertThat(providerConfiguration.getTokenEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/token"));
assertThat(providerConfiguration.getJwkSetUri()).isEqualTo(new URL("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getJwkSetUrl()).isEqualTo(new URL("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(providerConfiguration.getSubjectTypes()).containsExactly("public");
assertThat(providerConfiguration.getIdTokenSigningAlgorithms()).containsExactly("RS256");
@@ -109,7 +110,7 @@ public class OidcProviderConfigurationHttpMessageConverterTests {
assertThat(providerConfiguration.getIssuer()).isEqualTo(new URL("https://example.com/issuer1"));
assertThat(providerConfiguration.getAuthorizationEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/authorize"));
assertThat(providerConfiguration.getTokenEndpoint()).isEqualTo(new URL("https://example.com/issuer1/oauth2/token"));
assertThat(providerConfiguration.getJwkSetUri()).isEqualTo(new URL("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getJwkSetUrl()).isEqualTo(new URL("https://example.com/issuer1/oauth2/jwks"));
assertThat(providerConfiguration.getScopes()).containsExactly("openid");
assertThat(providerConfiguration.getResponseTypes()).containsExactly("code");
assertThat(providerConfiguration.getGrantTypes()).containsExactlyInAnyOrder("authorization_code", "client_credentials");
@@ -152,7 +153,7 @@ public class OidcProviderConfigurationHttpMessageConverterTests {
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.jwkSetUrl("https://example.com/issuer1/oauth2/jwks")
.scope("openid")
.responseType("code")
.grantType("authorization_code")
@@ -196,7 +197,7 @@ public class OidcProviderConfigurationHttpMessageConverterTests {
.issuer("https://example.com/issuer1")
.authorizationEndpoint("https://example.com/issuer1/oauth2/authorize")
.tokenEndpoint("https://example.com/issuer1/oauth2/token")
.jwkSetUri("https://example.com/issuer1/oauth2/jwks")
.jwkSetUrl("https://example.com/issuer1/oauth2/jwks")
.responseType("code")
.subjectType("public")
.idTokenSigningAlgorithm("RS256")

View File

@@ -18,7 +18,7 @@ package org.springframework.security.oauth2.server.authorization.config;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link ProviderSettings}.
@@ -78,48 +78,48 @@ public class ProviderSettingsTests {
@Test
public void issuerWhenNullThenThrowIllegalArgumentException() {
ProviderSettings settings = new ProviderSettings();
assertThatIllegalArgumentException()
.isThrownBy(() -> settings.issuer(null))
.withMessage("value cannot be null");
assertThatThrownBy(() -> settings.issuer(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("value cannot be null");
}
@Test
public void authorizationEndpointWhenNullThenThrowIllegalArgumentException() {
ProviderSettings settings = new ProviderSettings();
assertThatIllegalArgumentException()
.isThrownBy(() -> settings.authorizationEndpoint(null))
.withMessage("value cannot be null");
assertThatThrownBy(() -> settings.authorizationEndpoint(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("value cannot be null");
}
@Test
public void tokenEndpointWhenNullThenThrowIllegalArgumentException() {
ProviderSettings settings = new ProviderSettings();
assertThatIllegalArgumentException()
.isThrownBy(() -> settings.tokenEndpoint(null))
.withMessage("value cannot be null");
assertThatThrownBy(() -> settings.tokenEndpoint(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("value cannot be null");
}
@Test
public void tokenRevocationEndpointWhenNullThenThrowIllegalArgumentException() {
ProviderSettings settings = new ProviderSettings();
assertThatIllegalArgumentException()
.isThrownBy(() -> settings.tokenRevocationEndpoint(null))
.withMessage("value cannot be null");
assertThatThrownBy(() -> settings.tokenRevocationEndpoint(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("value cannot be null");
}
@Test
public void tokenIntrospectionEndpointWhenNullThenThrowIllegalArgumentException() {
ProviderSettings settings = new ProviderSettings();
assertThatIllegalArgumentException()
.isThrownBy(() -> settings.tokenIntrospectionEndpoint(null))
.withMessage("value cannot be null");
assertThatThrownBy(() -> settings.tokenIntrospectionEndpoint(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("value cannot be null");
}
@Test
public void jwksEndpointWhenNullThenThrowIllegalArgumentException() {
ProviderSettings settings = new ProviderSettings();
assertThatIllegalArgumentException()
.isThrownBy(() -> settings.jwkSetEndpoint(null))
.withMessage("value cannot be null");
assertThatThrownBy(() -> settings.jwkSetEndpoint(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("value cannot be null");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 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.
@@ -16,16 +16,17 @@
package org.springframework.security.oauth2.server.authorization.web;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any;
@@ -34,23 +35,23 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
/**
* Tests for {@link OAuth2AuthorizationServerConfigurationEndpointFilter}.
* Tests for {@link OAuth2AuthorizationServerMetadataEndpointFilter}.
*
* @author Daniel Garnier-Moiroux
*/
public class OAuth2AuthorizationServerConfigurationEndpointFilterTests {
public class OAuth2AuthorizationServerMetadataEndpointFilterTests {
@Test
public void constructorWhenProviderSettingsNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new OAuth2AuthorizationServerConfigurationEndpointFilter(null))
.isThrownBy(() -> new OAuth2AuthorizationServerMetadataEndpointFilter(null))
.withMessage("providerSettings cannot be null");
}
@Test
public void doFilterWhenNotAuthorizationServerConfigurationRequestThenNotProcessed() throws Exception {
OAuth2AuthorizationServerConfigurationEndpointFilter filter =
new OAuth2AuthorizationServerConfigurationEndpointFilter(new ProviderSettings().issuer("https://example.com"));
public void doFilterWhenNotAuthorizationServerMetadataRequestThenNotProcessed() throws Exception {
OAuth2AuthorizationServerMetadataEndpointFilter filter =
new OAuth2AuthorizationServerMetadataEndpointFilter(new ProviderSettings().issuer("https://example.com"));
String requestUri = "/path";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
@@ -64,11 +65,11 @@ public class OAuth2AuthorizationServerConfigurationEndpointFilterTests {
}
@Test
public void doFilterWhenAuthorizationServerConfigurationRequestPostThenNotProcessed() throws Exception {
OAuth2AuthorizationServerConfigurationEndpointFilter filter =
new OAuth2AuthorizationServerConfigurationEndpointFilter(new ProviderSettings().issuer("https://example.com"));
public void doFilterWhenAuthorizationServerMetadataRequestPostThenNotProcessed() throws Exception {
OAuth2AuthorizationServerMetadataEndpointFilter filter =
new OAuth2AuthorizationServerMetadataEndpointFilter(new ProviderSettings().issuer("https://example.com"));
String requestUri = OAuth2AuthorizationServerConfigurationEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_CONFIGURATION_ENDPOINT_URI;
String requestUri = OAuth2AuthorizationServerMetadataEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
request.setServletPath(requestUri);
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -80,22 +81,24 @@ public class OAuth2AuthorizationServerConfigurationEndpointFilterTests {
}
@Test
public void doFilterWhenAuthorizationServerConfigurationRequestThenAuthorizationServerConfigurationResponse() throws Exception {
public void doFilterWhenAuthorizationServerMetadataRequestThenMetadataResponse() throws Exception {
String authorizationEndpoint = "/oauth2/v1/authorize";
String tokenEndpoint = "/oauth2/v1/token";
String tokenRevocationEndpoint = "/oauth2/v1/revoke";
String jwkSetEndpoint = "/oauth2/v1/jwks";
String tokenRevocationEndpoint = "/oauth2/v1/revoke";
String tokenIntrospectionEndpoint = "/oauth2/v1/introspect";
ProviderSettings providerSettings = new ProviderSettings()
.issuer("https://example.com/issuer1")
.authorizationEndpoint(authorizationEndpoint)
.tokenEndpoint(tokenEndpoint)
.jwkSetEndpoint(jwkSetEndpoint)
.tokenRevocationEndpoint(tokenRevocationEndpoint)
.jwkSetEndpoint(jwkSetEndpoint);
OAuth2AuthorizationServerConfigurationEndpointFilter filter =
new OAuth2AuthorizationServerConfigurationEndpointFilter(providerSettings);
.tokenIntrospectionEndpoint(tokenIntrospectionEndpoint);
OAuth2AuthorizationServerMetadataEndpointFilter filter =
new OAuth2AuthorizationServerMetadataEndpointFilter(providerSettings);
String requestUri = OAuth2AuthorizationServerConfigurationEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_CONFIGURATION_ENDPOINT_URI;
String requestUri = OAuth2AuthorizationServerMetadataEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -106,28 +109,29 @@ public class OAuth2AuthorizationServerConfigurationEndpointFilterTests {
verifyNoInteractions(filterChain);
assertThat(response.getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE);
String serverConfigurationResponse = response.getContentAsString();
assertThat(serverConfigurationResponse).contains("\"issuer\":\"https://example.com/issuer1\"");
assertThat(serverConfigurationResponse).contains("\"authorization_endpoint\":\"https://example.com/issuer1/oauth2/v1/authorize\"");
assertThat(serverConfigurationResponse).contains("\"token_endpoint\":\"https://example.com/issuer1/oauth2/v1/token\"");
assertThat(serverConfigurationResponse).contains("\"revocation_endpoint\":\"https://example.com/issuer1/oauth2/v1/revoke\"");
assertThat(serverConfigurationResponse).contains("\"jwks_uri\":\"https://example.com/issuer1/oauth2/v1/jwks\"");
assertThat(serverConfigurationResponse).contains("\"scopes_supported\":[\"openid\"]");
assertThat(serverConfigurationResponse).contains("\"response_types_supported\":[\"code\"]");
assertThat(serverConfigurationResponse).contains("\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\"]");
assertThat(serverConfigurationResponse).contains("\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\"]");
assertThat(serverConfigurationResponse).contains("\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\"]");
assertThat(serverConfigurationResponse).contains("\"code_challenge_methods_supported\":[\"plain\",\"S256\"]");
String authorizationServerMetadataResponse = response.getContentAsString();
assertThat(authorizationServerMetadataResponse).contains("\"issuer\":\"https://example.com/issuer1\"");
assertThat(authorizationServerMetadataResponse).contains("\"authorization_endpoint\":\"https://example.com/issuer1/oauth2/v1/authorize\"");
assertThat(authorizationServerMetadataResponse).contains("\"token_endpoint\":\"https://example.com/issuer1/oauth2/v1/token\"");
assertThat(authorizationServerMetadataResponse).contains("\"token_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\"]");
assertThat(authorizationServerMetadataResponse).contains("\"jwks_uri\":\"https://example.com/issuer1/oauth2/v1/jwks\"");
assertThat(authorizationServerMetadataResponse).contains("\"response_types_supported\":[\"code\"]");
assertThat(authorizationServerMetadataResponse).contains("\"grant_types_supported\":[\"authorization_code\",\"client_credentials\",\"refresh_token\"]");
assertThat(authorizationServerMetadataResponse).contains("\"revocation_endpoint\":\"https://example.com/issuer1/oauth2/v1/revoke\"");
assertThat(authorizationServerMetadataResponse).contains("\"revocation_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\"]");
assertThat(authorizationServerMetadataResponse).contains("\"introspection_endpoint\":\"https://example.com/issuer1/oauth2/v1/introspect\"");
assertThat(authorizationServerMetadataResponse).contains("\"introspection_endpoint_auth_methods_supported\":[\"client_secret_basic\",\"client_secret_post\"]");
assertThat(authorizationServerMetadataResponse).contains("\"code_challenge_methods_supported\":[\"plain\",\"S256\"]");
}
@Test
public void doFilterWhenProviderSettingsWithInvalidIssuerThenThrowIllegalArgumentException() {
ProviderSettings providerSettings = new ProviderSettings()
.issuer("https://this is an invalid URL");
OAuth2AuthorizationServerConfigurationEndpointFilter filter =
new OAuth2AuthorizationServerConfigurationEndpointFilter(providerSettings);
OAuth2AuthorizationServerMetadataEndpointFilter filter =
new OAuth2AuthorizationServerMetadataEndpointFilter(providerSettings);
String requestUri = OAuth2AuthorizationServerConfigurationEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_CONFIGURATION_ENDPOINT_URI;
String requestUri = OAuth2AuthorizationServerMetadataEndpointFilter.DEFAULT_OAUTH2_AUTHORIZATION_SERVER_METADATA_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -138,4 +142,5 @@ public class OAuth2AuthorizationServerConfigurationEndpointFilterTests {
.isThrownBy(() -> filter.doFilter(request, response, filterChain))
.withMessage("issuer must be a valid URL");
}
}