Skip to content

Commit

Permalink
Introduce ProviderContext
Browse files Browse the repository at this point in the history
Closes gh-479
  • Loading branch information
jgrandja committed Jan 17, 2022
1 parent 1370f7e commit d302444
Show file tree
Hide file tree
Showing 19 changed files with 459 additions and 77 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* 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.
Expand Down Expand Up @@ -46,12 +46,14 @@
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.ProviderContextFilter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.context.HttpRequestResponseHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
Expand Down Expand Up @@ -341,6 +343,9 @@ public void configure(B builder) {
ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);

ProviderContextFilter providerContextFilter = new ProviderContextFilter(providerSettings);
builder.addFilterAfter(postProcess(providerContextFilter), SecurityContextPersistenceFilter.class);

OAuth2TokenIntrospectionEndpointFilter tokenIntrospectionEndpointFilter =
new OAuth2TokenIntrospectionEndpointFilter(
authenticationManager,
Expand All @@ -353,11 +358,9 @@ public void configure(B builder) {
providerSettings.getJwkSetEndpoint());
builder.addFilterBefore(postProcess(jwkSetEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);

if (providerSettings.getIssuer() != null) {
OAuth2AuthorizationServerMetadataEndpointFilter authorizationServerMetadataEndpointFilter =
new OAuth2AuthorizationServerMetadataEndpointFilter(providerSettings);
builder.addFilterBefore(postProcess(authorizationServerMetadataEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
}
OAuth2AuthorizationServerMetadataEndpointFilter authorizationServerMetadataEndpointFilter =
new OAuth2AuthorizationServerMetadataEndpointFilter(providerSettings);
builder.addFilterBefore(postProcess(authorizationServerMetadataEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
}

private Map<Class<? extends AbstractOAuth2Configurer>, AbstractOAuth2Configurer> createConfigurers() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* 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.
Expand Down Expand Up @@ -122,10 +122,7 @@ static <B extends HttpSecurityBuilder<B>> OAuth2TokenCustomizer<JwtEncodingConte
static <B extends HttpSecurityBuilder<B>> ProviderSettings getProviderSettings(B builder) {
ProviderSettings providerSettings = builder.getSharedObject(ProviderSettings.class);
if (providerSettings == null) {
providerSettings = getOptionalBean(builder, ProviderSettings.class);
if (providerSettings == null) {
providerSettings = ProviderSettings.builder().build();
}
providerSettings = getBean(builder, ProviderSettings.class);
builder.setSharedObject(ProviderSettings.class, providerSettings);
}
return providerSettings;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* 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.
Expand Down Expand Up @@ -85,16 +85,13 @@ <B extends HttpSecurityBuilder<B>> void init(B builder) {
}

List<RequestMatcher> requestMatchers = new ArrayList<>();
ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
if (providerSettings.getIssuer() != null) {
requestMatchers.add(new AntPathRequestMatcher(
"/.well-known/openid-configuration", HttpMethod.GET.name()));
}
requestMatchers.add(new AntPathRequestMatcher(
"/.well-known/openid-configuration", HttpMethod.GET.name()));
requestMatchers.add(this.userInfoEndpointConfigurer.getRequestMatcher());
if (this.clientRegistrationEndpointConfigurer != null) {
requestMatchers.add(this.clientRegistrationEndpointConfigurer.getRequestMatcher());
}
this.requestMatcher = requestMatchers.size() > 1 ? new OrRequestMatcher(requestMatchers) : requestMatchers.get(0);
this.requestMatcher = new OrRequestMatcher(requestMatchers);
}

@Override
Expand All @@ -105,11 +102,9 @@ <B extends HttpSecurityBuilder<B>> void configure(B builder) {
}

ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
if (providerSettings.getIssuer() != null) {
OidcProviderConfigurationEndpointFilter oidcProviderConfigurationEndpointFilter =
new OidcProviderConfigurationEndpointFilter(providerSettings);
builder.addFilterBefore(postProcess(oidcProviderConfigurationEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
}
OidcProviderConfigurationEndpointFilter oidcProviderConfigurationEndpointFilter =
new OidcProviderConfigurationEndpointFilter(providerSettings);
builder.addFilterBefore(postProcess(oidcProviderConfigurationEndpointFilter), AbstractPreAuthenticatedProcessingFilter.class);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* 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.
Expand All @@ -26,7 +26,6 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
Expand Down Expand Up @@ -55,6 +54,7 @@
import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.oauth2.server.authorization.context.ProviderContextHolder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

Expand Down Expand Up @@ -87,7 +87,6 @@ public final class OAuth2AuthorizationCodeAuthenticationProvider implements Auth
private final JwtEncoder jwtEncoder;
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
private Supplier<String> refreshTokenGenerator = DEFAULT_REFRESH_TOKEN_GENERATOR::generateKey;
private ProviderSettings providerSettings;

/**
* Constructs an {@code OAuth2AuthorizationCodeAuthenticationProvider} using the provided parameters.
Expand Down Expand Up @@ -124,9 +123,8 @@ public void setRefreshTokenGenerator(Supplier<String> refreshTokenGenerator) {
this.refreshTokenGenerator = refreshTokenGenerator;
}

@Autowired
@Deprecated
protected void setProviderSettings(ProviderSettings providerSettings) {
this.providerSettings = providerSettings;
}

@Override
Expand Down Expand Up @@ -167,7 +165,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
}

String issuer = this.providerSettings != null ? this.providerSettings.getIssuer() : null;
String issuer = ProviderContextHolder.getProviderContext().getIssuer();
Set<String> authorizedScopes = authorization.getAttribute(
OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* 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.
Expand All @@ -19,7 +19,6 @@
import java.util.Set;
import java.util.function.Consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
Expand All @@ -38,6 +37,7 @@
import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.oauth2.server.authorization.context.ProviderContextHolder;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

Expand All @@ -62,7 +62,6 @@ public final class OAuth2ClientCredentialsAuthenticationProvider implements Auth
private final OAuth2AuthorizationService authorizationService;
private final JwtEncoder jwtEncoder;
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
private ProviderSettings providerSettings;

/**
* Constructs an {@code OAuth2ClientCredentialsAuthenticationProvider} using the provided parameters.
Expand Down Expand Up @@ -90,9 +89,8 @@ public void setJwtCustomizer(OAuth2TokenCustomizer<JwtEncodingContext> jwtCustom
this.jwtCustomizer = jwtCustomizer;
}

@Autowired
@Deprecated
protected void setProviderSettings(ProviderSettings providerSettings) {
this.providerSettings = providerSettings;
}

@Override
Expand All @@ -118,7 +116,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
authorizedScopes = new LinkedHashSet<>(clientCredentialsAuthentication.getScopes());
}

String issuer = this.providerSettings != null ? this.providerSettings.getIssuer() : null;
String issuer = ProviderContextHolder.getProviderContext().getIssuer();

JoseHeader.Builder headersBuilder = JwtUtils.headers();
JwtClaimsSet.Builder claimsBuilder = JwtUtils.accessTokenClaims(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2021 the original author or authors.
* 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.
Expand All @@ -26,7 +26,6 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
Expand All @@ -52,6 +51,7 @@
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
import org.springframework.security.oauth2.server.authorization.context.ProviderContextHolder;
import org.springframework.util.Assert;

import static org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthenticationProviderUtils.getAuthenticatedClientElseThrowInvalidClient;
Expand Down Expand Up @@ -80,7 +80,6 @@ public final class OAuth2RefreshTokenAuthenticationProvider implements Authentic
private final JwtEncoder jwtEncoder;
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
private Supplier<String> refreshTokenGenerator = DEFAULT_REFRESH_TOKEN_GENERATOR::generateKey;
private ProviderSettings providerSettings;

/**
* Constructs an {@code OAuth2RefreshTokenAuthenticationProvider} using the provided parameters.
Expand Down Expand Up @@ -118,9 +117,8 @@ public void setRefreshTokenGenerator(Supplier<String> refreshTokenGenerator) {
this.refreshTokenGenerator = refreshTokenGenerator;
}

@Autowired
@Deprecated
protected void setProviderSettings(ProviderSettings providerSettings) {
this.providerSettings = providerSettings;
}

@Override
Expand Down Expand Up @@ -166,7 +164,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
scopes = authorizedScopes;
}

String issuer = this.providerSettings != null ? this.providerSettings.getIssuer() : null;
String issuer = ProviderContextHolder.getProviderContext().getIssuer();

JoseHeader.Builder headersBuilder = JwtUtils.headers();
JwtClaimsSet.Builder claimsBuilder = JwtUtils.accessTokenClaims(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* 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.context;

import java.util.function.Supplier;

import org.springframework.lang.Nullable;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.util.Assert;

/**
* A context that holds information of the Provider.
*
* @author Joe Grandja
* @since 0.2.2
* @see ProviderSettings
* @see ProviderContextHolder
*/
public final class ProviderContext {
private final ProviderSettings providerSettings;
private final Supplier<String> issuerSupplier;

/**
* Constructs a {@code ProviderContext} using the provided parameters.
*
* @param providerSettings the provider settings
* @param issuerSupplier a {@code Supplier} for the {@code URL} of the Provider's issuer identifier
*/
public ProviderContext(ProviderSettings providerSettings, @Nullable Supplier<String> issuerSupplier) {
Assert.notNull(providerSettings, "providerSettings cannot be null");
this.providerSettings = providerSettings;
this.issuerSupplier = issuerSupplier;
}

/**
* Returns the {@link ProviderSettings}.
*
* @return the {@link ProviderSettings}
*/
public ProviderSettings getProviderSettings() {
return this.providerSettings;
}

/**
* Returns the {@code URL} of the Provider's issuer identifier.
* The issuer identifier is resolved from the constructor parameter {@code Supplier<String>}
* or if not provided then defaults to {@link ProviderSettings#getIssuer()}.
*
* @return the {@code URL} of the Provider's issuer identifier
*/
public String getIssuer() {
return this.issuerSupplier != null ?
this.issuerSupplier.get() :
getProviderSettings().getIssuer();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.context;

import org.springframework.security.oauth2.server.authorization.web.ProviderContextFilter;

/**
* A holder of {@link ProviderContext} that associates it with the current thread using a {@code ThreadLocal}.
*
* @author Joe Grandja
* @since 0.2.2
* @see ProviderContext
* @see ProviderContextFilter
*/
public final class ProviderContextHolder {
private static final ThreadLocal<ProviderContext> holder = new ThreadLocal<>();

private ProviderContextHolder() {
}

/**
* Returns the {@link ProviderContext} bound to the current thread.
*
* @return the {@link ProviderContext}
*/
public static ProviderContext getProviderContext() {
return holder.get();
}

/**
* Bind the given {@link ProviderContext} to the current thread.
*
* @param providerContext the {@link ProviderContext}
*/
public static void setProviderContext(ProviderContext providerContext) {
if (providerContext == null) {
resetProviderContext();
} else {
holder.set(providerContext);
}
}

/**
* Reset the {@link ProviderContext} bound to the current thread.
*/
public static void resetProviderContext() {
holder.remove();
}

}

0 comments on commit d302444

Please sign in to comment.