From d4357197c9673eb1c040938859c726beb3e4337c Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Thu, 11 Nov 2021 10:02:45 -0500 Subject: [PATCH] Polish gh-470 --- .../OAuth2AuthorizationConsentContext.java | 212 ------------------ ...tionCodeRequestAuthenticationProvider.java | 36 +-- ...orizationConsentAuthenticationContext.java | 146 ++++++++++++ .../OAuth2AuthorizationCodeGrantTests.java | 22 +- ...Auth2AuthorizationConsentContextTests.java | 91 -------- ...odeRequestAuthenticationProviderTests.java | 22 +- ...tionConsentAuthenticationContextTests.java | 124 ++++++++++ 7 files changed, 311 insertions(+), 342 deletions(-) delete mode 100644 oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContext.java create mode 100644 oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContext.java delete mode 100644 oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContextTests.java create mode 100644 oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContextTests.java diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContext.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContext.java deleted file mode 100644 index e5586e10..00000000 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContext.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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.server.authorization; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; - -import org.springframework.lang.Nullable; -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.core.context.Context; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; -import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; -import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; - -/** - * A context that holds an {@link OAuth2AuthorizationConsent.Builder} and (optionally) additional information - * and is used when customizing the building of {@link OAuth2AuthorizationConsent}. - * - * @author Steve Riesenberg - * @since 0.2.1 - * @see Context - */ -public final class OAuth2AuthorizationConsentContext implements Context { - private final Map context; - - /** - * Constructs an {@code OAuth2AuthorizationConsentContext} using the provided parameters. - * - * @param context a {@code Map} of additional context information - */ - private OAuth2AuthorizationConsentContext(@Nullable Map context) { - this.context = new HashMap<>(); - if (!CollectionUtils.isEmpty(context)) { - this.context.putAll(context); - } - } - - /** - * Returns the {@link OAuth2AuthorizationConsent.Builder authorization consent builder}. - * - * @return the {@link OAuth2AuthorizationConsent.Builder} - */ - public OAuth2AuthorizationConsent.Builder getAuthorizationConsentBuilder() { - return get(OAuth2AuthorizationConsent.Builder.class); - } - - /** - * Returns the {@link Authentication} representing the {@code Principal} resource owner (or client). - * - * @param the type of the {@code Authentication} - * @return the {@link Authentication} representing the {@code Principal} resource owner (or client) - */ - @Nullable - public T getPrincipal() { - return get(Builder.PRINCIPAL_AUTHENTICATION_KEY); - } - - /** - * Returns the {@link RegisteredClient registered client}. - * - * @return the {@link RegisteredClient}, or {@code null} if not available - */ - @Nullable - public RegisteredClient getRegisteredClient() { - return get(RegisteredClient.class); - } - - /** - * Returns the {@link OAuth2Authorization authorization}. - * - * @return the {@link OAuth2Authorization}, or {@code null} if not available - */ - @Nullable - public OAuth2Authorization getAuthorization() { - return get(OAuth2Authorization.class); - } - - /** - * Returns the {@link OAuth2AuthorizationRequest authorization request}. - * - * @return the {@link OAuth2AuthorizationRequest}, or {@code null} if not available - */ - @Nullable - public OAuth2AuthorizationRequest getAuthorizationRequest() { - return get(OAuth2AuthorizationRequest.class); - } - - @SuppressWarnings("unchecked") - @Override - public V get(Object key) { - return (V) this.context.get(key); - } - - @Override - public boolean hasKey(Object key) { - return this.context.containsKey(key); - } - - /** - * Constructs a new {@link Builder} with the provided {@link OAuth2AuthorizationConsent.Builder}. - * - * @param authorizationConsentBuilder the {@link OAuth2AuthorizationConsent.Builder} to initialize the builder - * @return the {@link Builder} - */ - public static OAuth2AuthorizationConsentContext.Builder with(OAuth2AuthorizationConsent.Builder authorizationConsentBuilder) { - return new Builder(authorizationConsentBuilder); - } - - /** - * A builder for {@link OAuth2AuthorizationConsentContext}. - */ - public static final class Builder { - private static final String PRINCIPAL_AUTHENTICATION_KEY = - Authentication.class.getName().concat(".PRINCIPAL"); - private final Map context = new HashMap<>(); - - private Builder(OAuth2AuthorizationConsent.Builder authorizationConsentBuilder) { - Assert.notNull(authorizationConsentBuilder, "authorizationConsentBuilder cannot be null"); - put(OAuth2AuthorizationConsent.Builder.class, authorizationConsentBuilder); - } - - /** - * Sets the {@link Authentication} representing the {@code Principal} resource owner (or client). - * - * @param principal the {@link Authentication} representing the {@code Principal} resource owner (or client) - * @return the {@link Builder} for further configuration - */ - public Builder principal(Authentication principal) { - return put(PRINCIPAL_AUTHENTICATION_KEY, principal); - } - - /** - * Sets the {@link RegisteredClient registered client}. - * - * @param registeredClient the {@link RegisteredClient} - * @return the {@link Builder} for further configuration - */ - public Builder registeredClient(RegisteredClient registeredClient) { - return put(RegisteredClient.class, registeredClient); - } - - /** - * Sets the {@link OAuth2Authorization authorization}. - * - * @param authorization the {@link OAuth2Authorization} - * @return the {@link Builder} for further configuration - */ - public Builder authorization(OAuth2Authorization authorization) { - return put(OAuth2Authorization.class, authorization); - } - - /** - * Sets the {@link OAuth2AuthorizationRequest authorization request}. - * - * @param authorizationRequest the {@link OAuth2AuthorizationRequest} - * @return the {@link Builder} for further configuration - */ - public Builder authorizationRequest(OAuth2AuthorizationRequest authorizationRequest) { - return put(OAuth2AuthorizationRequest.class, authorizationRequest); - } - - /** - * Associates an attribute. - * - * @param key the key for the attribute - * @param value the value of the attribute - * @return the {@link OAuth2TokenContext.AbstractBuilder} for further configuration - */ - public Builder put(Object key, Object value) { - Assert.notNull(key, "key cannot be null"); - Assert.notNull(value, "value cannot be null"); - this.context.put(key, value); - return this; - } - - /** - * A {@code Consumer} of the attributes {@code Map} - * allowing the ability to add, replace, or remove. - * - * @param contextConsumer a {@link Consumer} of the attributes {@code Map} - * @return the {@link Builder} for further configuration - */ - public Builder context(Consumer> contextConsumer) { - contextConsumer.accept(this.context); - return this; - } - - /** - * Builds a new {@link OAuth2AuthorizationConsentContext}. - * - * @return the {@link OAuth2AuthorizationConsentContext} - */ - public OAuth2AuthorizationConsentContext build() { - return new OAuth2AuthorizationConsentContext(this.context); - } - } -} diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java index ce7d83cd..d5d9930d 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java @@ -24,12 +24,12 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.config.Customizer; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.crypto.keygen.Base64StringKeyGenerator; @@ -47,7 +47,6 @@ import org.springframework.security.oauth2.core.endpoint.PkceParameterNames; import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentContext; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; @@ -62,6 +61,7 @@ import org.springframework.web.util.UriComponentsBuilder; * used in the Authorization Code Grant. * * @author Joe Grandja + * @author Steve Riesenberg * @since 0.1.2 * @see OAuth2AuthorizationCodeRequestAuthenticationToken * @see OAuth2AuthorizationCodeAuthenticationProvider @@ -84,7 +84,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen private final OAuth2AuthorizationConsentService authorizationConsentService; private Supplier authorizationCodeGenerator = DEFAULT_AUTHORIZATION_CODE_GENERATOR::generateKey; private Function authenticationValidatorResolver = DEFAULT_AUTHENTICATION_VALIDATOR_RESOLVER; - private Customizer authorizationConsentCustomizer; + private Consumer authorizationConsentCustomizer; /** * Constructs an {@code OAuth2AuthorizationCodeRequestAuthenticationProvider} using the provided parameters. @@ -149,25 +149,26 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen } /** - * Sets the {@link Customizer} providing access to the {@link OAuth2AuthorizationConsentContext} containing an - * {@link OAuth2AuthorizationConsent.Builder}. + * Sets the {@code Consumer} providing access to the {@link OAuth2AuthorizationConsentAuthenticationContext} + * containing an {@link OAuth2AuthorizationConsent.Builder} and additional context information. * *

* The following context attributes are available: *

    *
  • The {@link OAuth2AuthorizationConsent.Builder} used to build the authorization consent - * prior to {@link OAuth2AuthorizationConsentService#save(OAuth2AuthorizationConsent)}
  • - *
  • The {@link Authentication authentication principal} of type - * {@link OAuth2AuthorizationCodeRequestAuthenticationToken}
  • + * prior to {@link OAuth2AuthorizationConsentService#save(OAuth2AuthorizationConsent)}. + *
  • The {@link Authentication} of type + * {@link OAuth2AuthorizationCodeRequestAuthenticationToken}.
  • + *
  • The {@link RegisteredClient} associated with the authorization request.
  • *
  • The {@link OAuth2Authorization} associated with the state token presented in the * authorization consent request.
  • - *
  • The {@link OAuth2AuthorizationRequest} requiring the resource owner's consent.
  • + *
  • The {@link OAuth2AuthorizationRequest} associated with the authorization consent request.
  • *
* - * @param authorizationConsentCustomizer the {@link Customizer} providing access to the - * {@link OAuth2AuthorizationConsentContext} containing an {@link OAuth2AuthorizationConsent.Builder} + * @param authorizationConsentCustomizer the {@code Consumer} providing access to the + * {@link OAuth2AuthorizationConsentAuthenticationContext} containing an {@link OAuth2AuthorizationConsent.Builder} */ - public void setAuthorizationConsentCustomizer(Customizer authorizationConsentCustomizer) { + public void setAuthorizationConsentCustomizer(Consumer authorizationConsentCustomizer) { Assert.notNull(authorizationConsentCustomizer, "authorizationConsentCustomizer cannot be null"); this.authorizationConsentCustomizer = authorizationConsentCustomizer; } @@ -328,8 +329,8 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen Set currentAuthorizedScopes = currentAuthorizationConsent != null ? currentAuthorizationConsent.getScopes() : Collections.emptySet(); - if (authorizedScopes.isEmpty() && currentAuthorizedScopes.isEmpty() - && authorizationCodeRequestAuthentication.getAdditionalParameters().isEmpty()) { + if (authorizedScopes.isEmpty() && currentAuthorizedScopes.isEmpty() && + authorizationCodeRequestAuthentication.getAdditionalParameters().isEmpty()) { // Authorization consent denied this.authorizationService.remove(authorization); throwError(OAuth2ErrorCodes.ACCESS_DENIED, OAuth2ParameterNames.CLIENT_ID, @@ -360,15 +361,14 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen if (this.authorizationConsentCustomizer != null) { // @formatter:off - OAuth2AuthorizationConsentContext authorizationConsentContext = - OAuth2AuthorizationConsentContext.with(authorizationConsentBuilder) - .principal(authorizationCodeRequestAuthentication) + OAuth2AuthorizationConsentAuthenticationContext authorizationConsentAuthenticationContext = + OAuth2AuthorizationConsentAuthenticationContext.with(authorizationCodeRequestAuthentication, authorizationConsentBuilder) .registeredClient(registeredClient) .authorization(authorization) .authorizationRequest(authorizationRequest) .build(); // @formatter:on - this.authorizationConsentCustomizer.customize(authorizationConsentContext); + this.authorizationConsentCustomizer.accept(authorizationConsentAuthenticationContext); } OAuth2AuthorizationConsent authorizationConsent = authorizationConsentBuilder.build(); diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContext.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContext.java new file mode 100644 index 00000000..b7d0b477 --- /dev/null +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContext.java @@ -0,0 +1,146 @@ +/* + * 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.server.authorization.authentication; + +import java.util.Map; + +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.core.authentication.OAuth2AuthenticationContext; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.util.Assert; + +/** + * An {@link OAuth2AuthenticationContext} that holds an {@link OAuth2AuthorizationConsent.Builder} and additional information + * and is used when customizing the building of the {@link OAuth2AuthorizationConsent}. + * + * @author Steve Riesenberg + * @author Joe Grandja + * @since 0.2.1 + * @see OAuth2AuthenticationContext + * @see OAuth2AuthorizationConsent + */ +public final class OAuth2AuthorizationConsentAuthenticationContext extends OAuth2AuthenticationContext { + + private OAuth2AuthorizationConsentAuthenticationContext(Map context) { + super(context); + } + + /** + * Returns the {@link OAuth2AuthorizationConsent.Builder authorization consent builder}. + * + * @return the {@link OAuth2AuthorizationConsent.Builder} + */ + public OAuth2AuthorizationConsent.Builder getAuthorizationConsent() { + return get(OAuth2AuthorizationConsent.Builder.class); + } + + /** + * Returns the {@link RegisteredClient registered client}. + * + * @return the {@link RegisteredClient} + */ + public RegisteredClient getRegisteredClient() { + return get(RegisteredClient.class); + } + + /** + * Returns the {@link OAuth2Authorization authorization}. + * + * @return the {@link OAuth2Authorization} + */ + public OAuth2Authorization getAuthorization() { + return get(OAuth2Authorization.class); + } + + /** + * Returns the {@link OAuth2AuthorizationRequest authorization request}. + * + * @return the {@link OAuth2AuthorizationRequest} + */ + public OAuth2AuthorizationRequest getAuthorizationRequest() { + return get(OAuth2AuthorizationRequest.class); + } + + /** + * Constructs a new {@link Builder} with the provided {@link Authentication} and {@link OAuth2AuthorizationConsent.Builder}. + * + * @param authentication the {@link Authentication} + * @param authorizationConsentBuilder the {@link OAuth2AuthorizationConsent.Builder} + * @return the {@link Builder} + */ + public static Builder with(Authentication authentication, OAuth2AuthorizationConsent.Builder authorizationConsentBuilder) { + return new Builder(authentication, authorizationConsentBuilder); + } + + /** + * A builder for {@link OAuth2AuthorizationConsentAuthenticationContext}. + */ + public static final class Builder extends AbstractBuilder { + + private Builder(Authentication authentication, OAuth2AuthorizationConsent.Builder authorizationConsentBuilder) { + super(authentication); + Assert.notNull(authorizationConsentBuilder, "authorizationConsentBuilder cannot be null"); + put(OAuth2AuthorizationConsent.Builder.class, authorizationConsentBuilder); + } + + /** + * Sets the {@link RegisteredClient registered client}. + * + * @param registeredClient the {@link RegisteredClient} + * @return the {@link Builder} for further configuration + */ + public Builder registeredClient(RegisteredClient registeredClient) { + return put(RegisteredClient.class, registeredClient); + } + + /** + * Sets the {@link OAuth2Authorization authorization}. + * + * @param authorization the {@link OAuth2Authorization} + * @return the {@link Builder} for further configuration + */ + public Builder authorization(OAuth2Authorization authorization) { + return put(OAuth2Authorization.class, authorization); + } + + /** + * Sets the {@link OAuth2AuthorizationRequest authorization request}. + * + * @param authorizationRequest the {@link OAuth2AuthorizationRequest} + * @return the {@link Builder} for further configuration + */ + public Builder authorizationRequest(OAuth2AuthorizationRequest authorizationRequest) { + return put(OAuth2AuthorizationRequest.class, authorizationRequest); + } + + /** + * Builds a new {@link OAuth2AuthorizationConsentAuthenticationContext}. + * + * @return the {@link OAuth2AuthorizationConsentAuthenticationContext} + */ + public OAuth2AuthorizationConsentAuthenticationContext build() { + Assert.notNull(get(RegisteredClient.class), "registeredClient cannot be null"); + Assert.notNull(get(OAuth2Authorization.class), "authorization cannot be null"); + Assert.notNull(get(OAuth2AuthorizationRequest.class), "authorizationRequest cannot be null"); + return new OAuth2AuthorizationConsentAuthenticationContext(getContext()); + } + + } + +} diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java index 50c16272..ae5b7ee6 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java @@ -29,6 +29,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.source.JWKSource; @@ -55,7 +56,6 @@ import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; @@ -83,13 +83,13 @@ import org.springframework.security.oauth2.server.authorization.JdbcOAuth2Author import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentContext; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationProvider; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken; +import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationConsentAuthenticationContext; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository.RegisteredClientParametersMapper; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; @@ -131,6 +131,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Joe Grandja * @author Daniel Garnier-Moiroux * @author Dmitriy Dubson + * @author Steve Riesenberg */ public class OAuth2AuthorizationCodeGrantTests { private static final String DEFAULT_AUTHORIZATION_ENDPOINT_URI = "/oauth2/authorize"; @@ -582,8 +583,6 @@ public class OAuth2AuthorizationCodeGrantTests { .andExpect(jsonPath("$.refresh_token").isNotEmpty()) .andExpect(jsonPath("$.scope").doesNotExist()) .andReturn(); - - String json = mvcResult.getResponse().getContentAsString(); } @Test @@ -822,7 +821,7 @@ public class OAuth2AuthorizationCodeGrantTests { return context -> { if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(context.getAuthorizationGrantType()) && OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) { - OAuth2AuthorizationConsent authorizationConsent = authorizationConsentService.findById( + OAuth2AuthorizationConsent authorizationConsent = this.authorizationConsentService.findById( context.getRegisteredClient().getId(), context.getPrincipal().getName()); Set authorities = new HashSet<>(); @@ -840,21 +839,22 @@ public class OAuth2AuthorizationCodeGrantTests { this.registeredClientRepository, this.authorizationService, this.authorizationConsentService); - authorizationCodeRequestAuthenticationProvider.setAuthorizationConsentCustomizer(new ConsentCustomizer()); + authorizationCodeRequestAuthenticationProvider.setAuthorizationConsentCustomizer(new AuthorizationConsentCustomizer()); return authorizationCodeRequestAuthenticationProvider; } - static class ConsentCustomizer implements Customizer { + static class AuthorizationConsentCustomizer implements Consumer { + @Override - public void customize(OAuth2AuthorizationConsentContext authorizationConsentContext) { + public void accept(OAuth2AuthorizationConsentAuthenticationContext authorizationConsentAuthenticationContext) { OAuth2AuthorizationConsent.Builder authorizationConsentBuilder = - authorizationConsentContext.getAuthorizationConsentBuilder(); + authorizationConsentAuthenticationContext.getAuthorizationConsent(); OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication = - authorizationConsentContext.getPrincipal(); + authorizationConsentAuthenticationContext.getAuthentication(); Map additionalParameters = authorizationCodeRequestAuthentication.getAdditionalParameters(); - RegisteredClient registeredClient = authorizationConsentContext.getRegisteredClient(); + RegisteredClient registeredClient = authorizationConsentAuthenticationContext.getRegisteredClient(); ClientSettings clientSettings = registeredClient.getClientSettings(); Set requestedAuthorities = authorities((String) additionalParameters.get("authority")); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContextTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContextTests.java deleted file mode 100644 index d964e96e..00000000 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/OAuth2AuthorizationConsentContextTests.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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.server.authorization; - -import org.junit.Test; - -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; -import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken; -import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; -import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * Tests for {@link OAuth2AuthorizationConsentContext}. - * - * @author Steve Riesenberg - */ -public class OAuth2AuthorizationConsentContextTests { - - @Test - public void withWhenAuthorizationConsentBuilderNullThenIllegalArgumentException() { - assertThatThrownBy(() -> OAuth2AuthorizationConsentContext.with(null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("authorizationConsentBuilder cannot be null"); - } - - @Test - public void setWhenValueNullThenThrowIllegalArgumentException() { - OAuth2AuthorizationConsentContext.Builder builder = OAuth2AuthorizationConsentContext - .with(OAuth2AuthorizationConsent.withId("some-client", "some-principal")); - assertThatThrownBy(() -> builder.principal(null)) - .isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> builder.registeredClient(null)) - .isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> builder.authorization(null)) - .isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> builder.authorizationRequest(null)) - .isInstanceOf(IllegalArgumentException.class); - assertThatThrownBy(() -> builder.put(null, "")) - .isInstanceOf(IllegalArgumentException.class); - } - - @Test - public void buildWhenAllValuesProvidedThenAllValuesAreSet() { - OAuth2AuthorizationConsent.Builder authorizationConsentBuilder = OAuth2AuthorizationConsent - .withId("some-client", "some-principal"); - TestingAuthenticationToken principal = new TestingAuthenticationToken("principal", "password"); - OAuth2AuthorizationCodeRequestAuthenticationToken authentication = - OAuth2AuthorizationCodeRequestAuthenticationToken.with("test-client", principal) - .authorizationUri("https://provider.com/oauth2/authorize") - .build(); - RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); - OAuth2Authorization authorization = TestOAuth2Authorizations.authorization().build(); - OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute( - OAuth2AuthorizationRequest.class.getName()); - - OAuth2AuthorizationConsentContext context = OAuth2AuthorizationConsentContext - .with(authorizationConsentBuilder) - .principal(authentication) - .registeredClient(registeredClient) - .authorization(authorization) - .authorizationRequest(authorizationRequest) - .put("custom-key-1", "custom-value-1") - .context(ctx -> ctx.put("custom-key-2", "custom-value-2")) - .build(); - - assertThat(context.getAuthorizationConsentBuilder()).isEqualTo(authorizationConsentBuilder); - assertThat(context.getPrincipal()).isEqualTo(authentication); - assertThat(context.getRegisteredClient()).isEqualTo(registeredClient); - assertThat(context.getAuthorization()).isEqualTo(authorization); - assertThat(context.getAuthorizationRequest()).isEqualTo(authorizationRequest); - assertThat(context.get("custom-key-1")).isEqualTo("custom-value-1"); - assertThat(context.get("custom-key-2")).isEqualTo("custom-value-2"); - } -} \ No newline at end of file diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java index 0caac28f..dc1a73bc 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -29,7 +30,6 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.config.Customizer; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.OAuth2AuthorizationCode; @@ -44,7 +44,6 @@ import org.springframework.security.oauth2.core.endpoint.PkceParameterNames; import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentContext; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; @@ -68,6 +67,7 @@ import static org.mockito.Mockito.when; * Tests for {@link OAuth2AuthorizationCodeRequestAuthenticationProvider}. * * @author Joe Grandja + * @author Steve Riesenberg */ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests { private static final OAuth2TokenType STATE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.STATE); @@ -804,7 +804,7 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests { .thenReturn(authorization); @SuppressWarnings("unchecked") - Customizer authorizationConsentCustomizer = mock(Customizer.class); + Consumer authorizationConsentCustomizer = mock(Consumer.class); this.authenticationProvider.setAuthorizationConsentCustomizer(authorizationConsentCustomizer); OAuth2AuthorizationCodeRequestAuthenticationToken authenticationResult = @@ -812,14 +812,16 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests { assertAuthorizationConsentRequestWithAuthorizationCodeResult(registeredClient, authorization, authenticationResult); - ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(OAuth2AuthorizationConsentContext.class); - verify(authorizationConsentCustomizer).customize(contextCaptor.capture()); + ArgumentCaptor authenticationContextCaptor = + ArgumentCaptor.forClass(OAuth2AuthorizationConsentAuthenticationContext.class); + verify(authorizationConsentCustomizer).accept(authenticationContextCaptor.capture()); - OAuth2AuthorizationConsentContext context = contextCaptor.getValue(); - assertThat((Authentication) context.getPrincipal()).isEqualTo(authentication); - assertThat(context.get(OAuth2AuthorizationConsent.Builder.class)).isInstanceOf(OAuth2AuthorizationConsent.Builder.class); - assertThat(context.get(OAuth2Authorization.class)).isInstanceOf(OAuth2Authorization.class); - assertThat(context.get(OAuth2AuthorizationRequest.class)).isInstanceOf(OAuth2AuthorizationRequest.class); + OAuth2AuthorizationConsentAuthenticationContext authenticationContext = authenticationContextCaptor.getValue(); + assertThat(authenticationContext.getAuthentication()).isEqualTo(authentication); + assertThat(authenticationContext.getAuthorizationConsent()).isNotNull(); + assertThat(authenticationContext.getRegisteredClient()).isEqualTo(registeredClient); + assertThat(authenticationContext.getAuthorization()).isEqualTo(authorization); + assertThat(authenticationContext.getAuthorizationRequest()).isEqualTo(authorizationRequest); } private void assertAuthorizationConsentRequestWithAuthorizationCodeResult( diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContextTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContextTests.java new file mode 100644 index 00000000..c1594c06 --- /dev/null +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationConsentAuthenticationContextTests.java @@ -0,0 +1,124 @@ +/* + * 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.server.authorization.authentication; + +import java.security.Principal; + +import org.junit.Test; + +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; +import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; +import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; +import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * Tests for {@link OAuth2AuthorizationConsentAuthenticationContext}. + * + * @author Steve Riesenberg + * @author Joe Grandja + */ +public class OAuth2AuthorizationConsentAuthenticationContextTests { + private final RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); + private final OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(this.registeredClient).build(); + private final Authentication principal = this.authorization.getAttribute(Principal.class.getName()); + private final OAuth2AuthorizationRequest authorizationRequest = this.authorization.getAttribute( + OAuth2AuthorizationRequest.class.getName()); + private final OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication = + OAuth2AuthorizationCodeRequestAuthenticationToken.with(this.registeredClient.getClientId(), this.principal) + .authorizationUri(this.authorizationRequest.getAuthorizationUri()) + .build(); + private final OAuth2AuthorizationConsent.Builder authorizationConsentBuilder = + OAuth2AuthorizationConsent.withId(this.authorization.getRegisteredClientId(), this.authorization.getPrincipalName()); + + @Test + public void withWhenAuthenticationNullThenThrowIllegalArgumentException() { + assertThatThrownBy(() -> OAuth2AuthorizationConsentAuthenticationContext.with(null, this.authorizationConsentBuilder)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("authentication cannot be null"); + } + + @Test + public void withWhenAuthorizationConsentBuilderNullThenThrowIllegalArgumentException() { + assertThatThrownBy(() -> OAuth2AuthorizationConsentAuthenticationContext.with(this.authorizationCodeRequestAuthentication, null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("authorizationConsentBuilder cannot be null"); + } + + @Test + public void setWhenValueNullThenThrowIllegalArgumentException() { + OAuth2AuthorizationConsentAuthenticationContext.Builder builder = + OAuth2AuthorizationConsentAuthenticationContext.with(this.authorizationCodeRequestAuthentication, this.authorizationConsentBuilder); + + assertThatThrownBy(() -> builder.registeredClient(null)) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> builder.authorization(null)) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> builder.authorizationRequest(null)) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> builder.put(null, "")) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void buildWhenRequiredValueNullThenThrowIllegalArgumentException() { + OAuth2AuthorizationConsentAuthenticationContext.Builder builder = + OAuth2AuthorizationConsentAuthenticationContext.with(this.authorizationCodeRequestAuthentication, this.authorizationConsentBuilder); + + assertThatThrownBy(builder::build) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("registeredClient cannot be null"); + builder.registeredClient(this.registeredClient); + + assertThatThrownBy(builder::build) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("authorization cannot be null"); + builder.authorization(this.authorization); + + assertThatThrownBy(builder::build) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("authorizationRequest cannot be null"); + builder.authorizationRequest(this.authorizationRequest); + + builder.build(); + } + + @Test + public void buildWhenAllValuesProvidedThenAllValuesAreSet() { + OAuth2AuthorizationConsentAuthenticationContext context = + OAuth2AuthorizationConsentAuthenticationContext.with(this.authorizationCodeRequestAuthentication, this.authorizationConsentBuilder) + .registeredClient(this.registeredClient) + .authorization(this.authorization) + .authorizationRequest(this.authorizationRequest) + .put("custom-key-1", "custom-value-1") + .context(ctx -> ctx.put("custom-key-2", "custom-value-2")) + .build(); + + assertThat(context.getAuthentication()).isEqualTo(this.authorizationCodeRequestAuthentication); + assertThat(context.getAuthorizationConsent()).isEqualTo(this.authorizationConsentBuilder); + assertThat(context.getRegisteredClient()).isEqualTo(this.registeredClient); + assertThat(context.getAuthorization()).isEqualTo(this.authorization); + assertThat(context.getAuthorizationRequest()).isEqualTo(this.authorizationRequest); + assertThat(context.get("custom-key-1")).isEqualTo("custom-value-1"); + assertThat(context.get("custom-key-2")).isEqualTo("custom-value-2"); + } + +}