Fix expected @Transient Authentication at provider configuration endpoint

Closes gh-632
This commit is contained in:
Joe Grandja
2022-03-22 13:45:57 -04:00
parent c2db8926df
commit ccf4a2de6e
3 changed files with 81 additions and 25 deletions

View File

@@ -16,7 +16,9 @@
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.AsyncContext;
@@ -270,16 +272,9 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
}
SecurityContextRepository securityContextRepositoryTransientNotSaved = new SecurityContextRepository() {
// OAuth2ClientAuthenticationToken is @Transient and is accepted by
// OAuth2TokenEndpointFilter, OAuth2TokenIntrospectionEndpointFilter and OAuth2TokenRevocationEndpointFilter
private final RequestMatcher clientAuthenticationRequestMatcher = new OrRequestMatcher(
getRequestMatcher(OAuth2TokenEndpointConfigurer.class),
getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class),
OAuth2AuthorizationServerConfigurer.this.tokenIntrospectionEndpointMatcher);
// JwtAuthenticationToken is @Transient and is accepted by
// OidcUserInfoEndpointFilter and OidcClientRegistrationEndpointFilter
private final RequestMatcher jwtAuthenticationRequestMatcher = getRequestMatcher(OidcConfigurer.class);
private final RequestMatcher clientAuthenticationRequestMatcher = initClientAuthenticationRequestMatcher();
private final RequestMatcher jwtAuthenticationRequestMatcher = initJwtAuthenticationRequestMatcher();
@Override
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
@@ -348,6 +343,35 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
return AnnotationUtils.getAnnotation(authentication.getClass(), Transient.class) != null;
}
private RequestMatcher initClientAuthenticationRequestMatcher() {
// OAuth2ClientAuthenticationToken is @Transient and is accepted by
// OAuth2TokenEndpointFilter, OAuth2TokenIntrospectionEndpointFilter and OAuth2TokenRevocationEndpointFilter
List<RequestMatcher> requestMatchers = new ArrayList<>();
requestMatchers.add(getRequestMatcher(OAuth2TokenEndpointConfigurer.class));
requestMatchers.add(getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class));
requestMatchers.add(OAuth2AuthorizationServerConfigurer.this.tokenIntrospectionEndpointMatcher);
return new OrRequestMatcher(requestMatchers);
}
private RequestMatcher initJwtAuthenticationRequestMatcher() {
// JwtAuthenticationToken is @Transient and is accepted by
// OidcUserInfoEndpointFilter and OidcClientRegistrationEndpointFilter
List<RequestMatcher> requestMatchers = new ArrayList<>();
requestMatchers.add(
getConfigurer(OidcConfigurer.class)
.getConfigurer(OidcUserInfoEndpointConfigurer.class).getRequestMatcher()
);
OidcClientRegistrationEndpointConfigurer clientRegistrationEndpointConfigurer =
getConfigurer(OidcConfigurer.class)
.getConfigurer(OidcClientRegistrationEndpointConfigurer.class);
if (clientRegistrationEndpointConfigurer != null) {
requestMatchers.add(clientRegistrationEndpointConfigurer.getRequestMatcher());
}
return new OrRequestMatcher(requestMatchers);
}
};
builder.setSharedObject(SecurityContextRepository.class, securityContextRepositoryTransientNotSaved);

View File

@@ -16,7 +16,9 @@
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
@@ -40,8 +42,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
* @see OidcProviderConfigurationEndpointFilter
*/
public final class OidcConfigurer extends AbstractOAuth2Configurer {
private final OidcUserInfoEndpointConfigurer userInfoEndpointConfigurer;
private OidcClientRegistrationEndpointConfigurer clientRegistrationEndpointConfigurer;
private final Map<Class<? extends AbstractOAuth2Configurer>, AbstractOAuth2Configurer> configurers = new LinkedHashMap<>();
private RequestMatcher requestMatcher;
/**
@@ -49,7 +50,7 @@ public final class OidcConfigurer extends AbstractOAuth2Configurer {
*/
OidcConfigurer(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
this.userInfoEndpointConfigurer = new OidcUserInfoEndpointConfigurer(objectPostProcessor);
addConfigurer(OidcUserInfoEndpointConfigurer.class, new OidcUserInfoEndpointConfigurer(objectPostProcessor));
}
/**
@@ -59,10 +60,14 @@ public final class OidcConfigurer extends AbstractOAuth2Configurer {
* @return the {@link OidcConfigurer} for further configuration
*/
public OidcConfigurer clientRegistrationEndpoint(Customizer<OidcClientRegistrationEndpointConfigurer> clientRegistrationEndpointCustomizer) {
if (this.clientRegistrationEndpointConfigurer == null) {
this.clientRegistrationEndpointConfigurer = new OidcClientRegistrationEndpointConfigurer(getObjectPostProcessor());
OidcClientRegistrationEndpointConfigurer clientRegistrationEndpointConfigurer =
getConfigurer(OidcClientRegistrationEndpointConfigurer.class);
if (clientRegistrationEndpointConfigurer == null) {
addConfigurer(OidcClientRegistrationEndpointConfigurer.class,
new OidcClientRegistrationEndpointConfigurer(getObjectPostProcessor()));
clientRegistrationEndpointConfigurer = getConfigurer(OidcClientRegistrationEndpointConfigurer.class);
}
clientRegistrationEndpointCustomizer.customize(this.clientRegistrationEndpointConfigurer);
clientRegistrationEndpointCustomizer.customize(clientRegistrationEndpointConfigurer);
return this;
}
@@ -73,32 +78,40 @@ public final class OidcConfigurer extends AbstractOAuth2Configurer {
* @return the {@link OidcConfigurer} for further configuration
*/
public OidcConfigurer userInfoEndpoint(Customizer<OidcUserInfoEndpointConfigurer> userInfoEndpointCustomizer) {
userInfoEndpointCustomizer.customize(this.userInfoEndpointConfigurer);
userInfoEndpointCustomizer.customize(getConfigurer(OidcUserInfoEndpointConfigurer.class));
return this;
}
@Override
<B extends HttpSecurityBuilder<B>> void init(B builder) {
this.userInfoEndpointConfigurer.init(builder);
if (this.clientRegistrationEndpointConfigurer != null) {
this.clientRegistrationEndpointConfigurer.init(builder);
OidcUserInfoEndpointConfigurer userInfoEndpointConfigurer =
getConfigurer(OidcUserInfoEndpointConfigurer.class);
userInfoEndpointConfigurer.init(builder);
OidcClientRegistrationEndpointConfigurer clientRegistrationEndpointConfigurer =
getConfigurer(OidcClientRegistrationEndpointConfigurer.class);
if (clientRegistrationEndpointConfigurer != null) {
clientRegistrationEndpointConfigurer.init(builder);
}
List<RequestMatcher> requestMatchers = new ArrayList<>();
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());
requestMatchers.add(userInfoEndpointConfigurer.getRequestMatcher());
if (clientRegistrationEndpointConfigurer != null) {
requestMatchers.add(clientRegistrationEndpointConfigurer.getRequestMatcher());
}
this.requestMatcher = new OrRequestMatcher(requestMatchers);
}
@Override
<B extends HttpSecurityBuilder<B>> void configure(B builder) {
this.userInfoEndpointConfigurer.configure(builder);
if (this.clientRegistrationEndpointConfigurer != null) {
this.clientRegistrationEndpointConfigurer.configure(builder);
OidcUserInfoEndpointConfigurer userInfoEndpointConfigurer =
getConfigurer(OidcUserInfoEndpointConfigurer.class);
userInfoEndpointConfigurer.configure(builder);
OidcClientRegistrationEndpointConfigurer clientRegistrationEndpointConfigurer =
getConfigurer(OidcClientRegistrationEndpointConfigurer.class);
if (clientRegistrationEndpointConfigurer != null) {
clientRegistrationEndpointConfigurer.configure(builder);
}
ProviderSettings providerSettings = OAuth2ConfigurerUtils.getProviderSettings(builder);
@@ -112,4 +125,13 @@ public final class OidcConfigurer extends AbstractOAuth2Configurer {
return this.requestMatcher;
}
@SuppressWarnings("unchecked")
<T> T getConfigurer(Class<T> type) {
return (T) this.configurers.get(type);
}
private <T extends AbstractOAuth2Configurer> void addConfigurer(Class<T> configurerType, T configurer) {
this.configurers.put(configurerType, configurer);
}
}

View File

@@ -186,6 +186,16 @@ public class OidcTests {
.andExpect(jsonPath("issuer").value(ISSUER_URL));
}
// gh-632
@Test
public void requestWhenConfigurationRequestAndUserAuthenticatedThenReturnConfigurationResponse() throws Exception {
this.spring.register(AuthorizationServerConfiguration.class).autowire();
this.mvc.perform(get(DEFAULT_OIDC_PROVIDER_CONFIGURATION_ENDPOINT_URI)
.with(user("user")))
.andExpect(status().is2xxSuccessful());
}
@Test
public void loadContextWhenIssuerNotValidUrlThenThrowException() {
assertThatThrownBy(