diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthenticationContext.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthenticationContext.java index e61ac092..58c3cbbe 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthenticationContext.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthenticationContext.java @@ -15,54 +15,24 @@ */ package org.springframework.security.oauth2.server.authorization.authentication; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; -import org.springframework.lang.Nullable; +import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.server.authorization.context.Context; import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; /** - * A context that holds an {@link Authentication} and (optionally) additional information. + * A context that holds an {@link Authentication} and (optionally) additional information + * and is used in an {@link AuthenticationProvider}. * * @author Joe Grandja * @since 0.2.0 * @see Context */ -public class OAuth2AuthenticationContext implements Context { - private final Map context; - - /** - * Constructs an {@code OAuth2AuthenticationContext} using the provided parameters. - * - * @param authentication the {@code Authentication} - * @param context a {@code Map} of additional context information - */ - public OAuth2AuthenticationContext(Authentication authentication, @Nullable Map context) { - Assert.notNull(authentication, "authentication cannot be null"); - Map ctx = new HashMap<>(); - if (!CollectionUtils.isEmpty(context)) { - ctx.putAll(context); - } - ctx.put(Authentication.class, authentication); - this.context = Collections.unmodifiableMap(ctx); - } - - /** - * Constructs an {@code OAuth2AuthenticationContext} using the provided parameters. - * - * @param context a {@code Map} of context information, must contain the {@code Authentication} - * @since 0.2.1 - */ - public OAuth2AuthenticationContext(Map context) { - Assert.notEmpty(context, "context cannot be empty"); - Assert.notNull(context.get(Authentication.class), "authentication cannot be null"); - this.context = Collections.unmodifiableMap(new HashMap<>(context)); - } +public interface OAuth2AuthenticationContext extends Context { /** * Returns the {@link Authentication} associated to the context. @@ -71,23 +41,10 @@ public class OAuth2AuthenticationContext implements Context { * @return the {@link Authentication} */ @SuppressWarnings("unchecked") - public T getAuthentication() { + default T getAuthentication() { return (T) get(Authentication.class); } - @SuppressWarnings("unchecked") - @Nullable - @Override - public V get(Object key) { - return hasKey(key) ? (V) this.context.get(key) : null; - } - - @Override - public boolean hasKey(Object key) { - Assert.notNull(key, "key cannot be null"); - return this.context.containsKey(key); - } - /** * A builder for subclasses of {@link OAuth2AuthenticationContext}. * @@ -95,7 +52,7 @@ public class OAuth2AuthenticationContext implements Context { * @param the type of the builder * @since 0.2.1 */ - protected static abstract class AbstractBuilder> { + abstract class AbstractBuilder> { private final Map context = new HashMap<>(); protected AbstractBuilder(Authentication authentication) { diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationContext.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationContext.java new file mode 100644 index 00000000..73d902f3 --- /dev/null +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationContext.java @@ -0,0 +1,105 @@ +/* + * Copyright 2020-2022 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.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.lang.Nullable; +import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.util.Assert; + +/** + * An {@link OAuth2AuthenticationContext} that holds an {@link OAuth2AuthorizationCodeRequestAuthenticationToken} and additional information + * and is used when validating the OAuth 2.0 Authorization Request used in the Authorization Code Grant. + * + * @author Joe Grandja + * @since 0.4.0 + * @see OAuth2AuthenticationContext + * @see OAuth2AuthorizationCodeRequestAuthenticationProvider + */ +public final class OAuth2AuthorizationCodeRequestAuthenticationContext implements OAuth2AuthenticationContext { + private final Map context; + + private OAuth2AuthorizationCodeRequestAuthenticationContext(Map context) { + this.context = Collections.unmodifiableMap(new HashMap<>(context)); + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public V get(Object key) { + return hasKey(key) ? (V) this.context.get(key) : null; + } + + @Override + public boolean hasKey(Object key) { + Assert.notNull(key, "key cannot be null"); + return this.context.containsKey(key); + } + + /** + * Returns the {@link RegisteredClient registered client}. + * + * @return the {@link RegisteredClient} + */ + public RegisteredClient getRegisteredClient() { + return get(RegisteredClient.class); + } + + /** + * Constructs a new {@link Builder} with the provided {@link OAuth2AuthorizationCodeRequestAuthenticationToken}. + * + * @param authentication the {@link OAuth2AuthorizationCodeRequestAuthenticationToken} + * @return the {@link Builder} + */ + public static Builder with(OAuth2AuthorizationCodeRequestAuthenticationToken authentication) { + return new Builder(authentication); + } + + /** + * A builder for {@link OAuth2AuthorizationCodeRequestAuthenticationContext}. + */ + public static final class Builder extends AbstractBuilder { + + private Builder(OAuth2AuthorizationCodeRequestAuthenticationToken authentication) { + super(authentication); + } + + /** + * 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); + } + + /** + * Builds a new {@link OAuth2AuthorizationCodeRequestAuthenticationContext}. + * + * @return the {@link OAuth2AuthorizationCodeRequestAuthenticationContext} + */ + public OAuth2AuthorizationCodeRequestAuthenticationContext build() { + Assert.notNull(get(RegisteredClient.class), "registeredClient cannot be null"); + return new OAuth2AuthorizationCodeRequestAuthenticationContext(getContext()); + } + + } + +} 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 f549c2b2..dadeb212 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 @@ -186,10 +186,10 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen authorizationCodeRequestAuthentication, null); } - Map context = new HashMap<>(); - context.put(RegisteredClient.class, registeredClient); - OAuth2AuthenticationContext authenticationContext = new OAuth2AuthenticationContext( - authorizationCodeRequestAuthentication, context); + OAuth2AuthenticationContext authenticationContext = + OAuth2AuthorizationCodeRequestAuthenticationContext.with(authorizationCodeRequestAuthentication) + .registeredClient(registeredClient) + .build(); OAuth2AuthenticationValidator redirectUriValidator = resolveAuthenticationValidator(OAuth2ParameterNames.REDIRECT_URI); redirectUriValidator.validate(authenticationContext); 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 index 20bc9393..e9986e60 100644 --- 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 @@ -15,8 +15,12 @@ */ package org.springframework.security.oauth2.server.authorization.authentication; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; +import org.springframework.lang.Nullable; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent; @@ -32,11 +36,26 @@ import org.springframework.util.Assert; * @since 0.2.1 * @see OAuth2AuthenticationContext * @see OAuth2AuthorizationConsent + * @see OAuth2AuthorizationCodeRequestAuthenticationProvider#setAuthorizationConsentCustomizer(Consumer) */ -public final class OAuth2AuthorizationConsentAuthenticationContext extends OAuth2AuthenticationContext { +public final class OAuth2AuthorizationConsentAuthenticationContext implements OAuth2AuthenticationContext { + private final Map context; private OAuth2AuthorizationConsentAuthenticationContext(Map context) { - super(context); + this.context = Collections.unmodifiableMap(new HashMap<>(context)); + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public V get(Object key) { + return hasKey(key) ? (V) this.context.get(key) : null; + } + + @Override + public boolean hasKey(Object key) { + Assert.notNull(key, "key cannot be null"); + return this.context.containsKey(key); } /** diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcUserInfoAuthenticationContext.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcUserInfoAuthenticationContext.java index 92f0d164..28cd32a6 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcUserInfoAuthenticationContext.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcUserInfoAuthenticationContext.java @@ -15,9 +15,12 @@ */ package org.springframework.security.oauth2.server.authorization.oidc.authentication; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.function.Function; +import org.springframework.lang.Nullable; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.oidc.OidcUserInfo; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; @@ -31,12 +34,27 @@ import org.springframework.util.Assert; * @author Joe Grandja * @since 0.2.1 * @see OAuth2AuthenticationContext + * @see OidcUserInfo * @see OidcUserInfoAuthenticationProvider#setUserInfoMapper(Function) */ -public final class OidcUserInfoAuthenticationContext extends OAuth2AuthenticationContext { +public final class OidcUserInfoAuthenticationContext implements OAuth2AuthenticationContext { + private final Map context; private OidcUserInfoAuthenticationContext(Map context) { - super(context); + this.context = Collections.unmodifiableMap(new HashMap<>(context)); + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public V get(Object key) { + return hasKey(key) ? (V) this.context.get(key) : null; + } + + @Override + public boolean hasKey(Object key) { + Assert.notNull(key, "key cannot be null"); + return this.context.containsKey(key); } /**