Make OAuth2AuthenticationContext an interface

Closes gh-890
This commit is contained in:
Joe Grandja
2022-09-09 17:33:46 -04:00
parent 2cc603c7e7
commit 1db05991af
5 changed files with 156 additions and 57 deletions

View File

@@ -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<Object, Object> 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<Object, Object> context) {
Assert.notNull(authentication, "authentication cannot be null");
Map<Object, Object> 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<Object, Object> 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 extends Authentication> T getAuthentication() {
default <T extends Authentication> T getAuthentication() {
return (T) get(Authentication.class);
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> 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 <B> the type of the builder
* @since 0.2.1
*/
protected static abstract class AbstractBuilder<T extends OAuth2AuthenticationContext, B extends AbstractBuilder<T, B>> {
abstract class AbstractBuilder<T extends OAuth2AuthenticationContext, B extends AbstractBuilder<T, B>> {
private final Map<Object, Object> context = new HashMap<>();
protected AbstractBuilder(Authentication authentication) {

View File

@@ -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<Object, Object> context;
private OAuth2AuthorizationCodeRequestAuthenticationContext(Map<Object, Object> context) {
this.context = Collections.unmodifiableMap(new HashMap<>(context));
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> 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<OAuth2AuthorizationCodeRequestAuthenticationContext, Builder> {
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());
}
}
}

View File

@@ -186,10 +186,10 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
authorizationCodeRequestAuthentication, null);
}
Map<Object, Object> 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);

View File

@@ -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<Object, Object> context;
private OAuth2AuthorizationConsentAuthenticationContext(Map<Object, Object> context) {
super(context);
this.context = Collections.unmodifiableMap(new HashMap<>(context));
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> 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);
}
/**

View File

@@ -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<Object, Object> context;
private OidcUserInfoAuthenticationContext(Map<Object, Object> context) {
super(context);
this.context = Collections.unmodifiableMap(new HashMap<>(context));
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> 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);
}
/**