Skip to content

Add ability to disable an endpoint #1924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,14 @@
*/
package org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers;

import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.nimbusds.jose.jwk.source.JWKSource;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.GenericApplicationListenerAdapter;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.session.SessionRegistry;
Expand All @@ -48,14 +39,19 @@
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.context.SecurityContextHolderFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;

import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* An {@link AbstractHttpConfigurer} for OAuth 2.0 Authorization Server support.
*
Expand Down Expand Up @@ -170,6 +166,11 @@ public OAuth2AuthorizationServerConfigurer clientAuthentication(
return this;
}

public OAuth2AuthorizationServerConfigurer disableClientAuthentication() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in this comment:

I also think we should come up with a solution that allows other endpoints to be disabled if needed. I don't think a "flag" setting on all the configurers makes sense.

I consider disableClientAuthentication(), disableAuthorizationServerMetadataEndpoint(), disableAuthorizationEndpoint(), etc. to be a similar solution as proposed in the previous PR but with an "explicit" flag through the introduction of the disable** public methods.

As mentioned, this is still not ideal as it introduces too many new public API's and I would prefer a solution that is more isolated.

I have been thinking about this for a while and may have a solution to address this but unfortunately I don't have the time at the moment as I have a couple of other features I've been working on that are priority for the upcoming release.

I'm going to close this PR but if you have other ideas please comment in gh-1882 before submitting another PR.

removeConfigurer(OAuth2ClientAuthenticationConfigurer.class);
return this;
}

/**
* Configures the OAuth 2.0 Authorization Server Metadata Endpoint.
* @param authorizationServerMetadataEndpointCustomizer the {@link Customizer}
Expand All @@ -184,6 +185,11 @@ public OAuth2AuthorizationServerConfigurer authorizationServerMetadataEndpoint(
return this;
}

public OAuth2AuthorizationServerConfigurer disableAuthorizationServerMetadataEndpoint() {
removeConfigurer(OAuth2AuthorizationServerMetadataEndpointConfigurer.class);
return this;
}

/**
* Configures the OAuth 2.0 Authorization Endpoint.
* @param authorizationEndpointCustomizer the {@link Customizer} providing access to
Expand All @@ -196,6 +202,11 @@ public OAuth2AuthorizationServerConfigurer authorizationEndpoint(
return this;
}

public OAuth2AuthorizationServerConfigurer disableAuthorizationEndpoint() {
removeConfigurer(OAuth2AuthorizationEndpointConfigurer.class);
return this;
}

/**
* Configures the OAuth 2.0 Token Endpoint.
* @param tokenEndpointCustomizer the {@link Customizer} providing access to the
Expand All @@ -208,6 +219,13 @@ public OAuth2AuthorizationServerConfigurer tokenEndpoint(
return this;
}

public OAuth2AuthorizationServerConfigurer disableTokenEndpoint() {
removeConfigurer(OAuth2TokenEndpointConfigurer.class);
getConfigurer(OAuth2ClientAuthenticationConfigurer.class)
.removeEndPointUriSettingName(OAuth2TokenEndpointConfigurer.class);
return this;
}

/**
* Configures the OAuth 2.0 Token Introspection Endpoint.
* @param tokenIntrospectionEndpointCustomizer the {@link Customizer} providing access
Expand All @@ -221,6 +239,13 @@ public OAuth2AuthorizationServerConfigurer tokenIntrospectionEndpoint(
return this;
}

public OAuth2AuthorizationServerConfigurer disableTokenIntrospectionEndpoint() {
removeConfigurer(OAuth2TokenIntrospectionEndpointConfigurer.class);
getConfigurer(OAuth2ClientAuthenticationConfigurer.class)
.removeEndPointUriSettingName(OAuth2TokenIntrospectionEndpointConfigurer.class);
return this;
}

/**
* Configures the OAuth 2.0 Token Revocation Endpoint.
* @param tokenRevocationEndpointCustomizer the {@link Customizer} providing access to
Expand All @@ -234,6 +259,13 @@ public OAuth2AuthorizationServerConfigurer tokenRevocationEndpoint(
return this;
}

public OAuth2AuthorizationServerConfigurer disableTokenRevocationEndpoint() {
removeConfigurer(OAuth2TokenRevocationEndpointConfigurer.class);
getConfigurer(OAuth2ClientAuthenticationConfigurer.class)
.removeEndPointUriSettingName(OAuth2TokenRevocationEndpointConfigurer.class);
return this;
}

/**
* Configures the OAuth 2.0 Device Authorization Endpoint.
* @param deviceAuthorizationEndpointCustomizer the {@link Customizer} providing
Expand All @@ -248,6 +280,13 @@ public OAuth2AuthorizationServerConfigurer deviceAuthorizationEndpoint(
return this;
}

public OAuth2AuthorizationServerConfigurer disableDeviceAuthorizationEndpoint() {
removeConfigurer(OAuth2DeviceAuthorizationEndpointConfigurer.class);
getConfigurer(OAuth2ClientAuthenticationConfigurer.class)
.removeEndPointUriSettingName(OAuth2DeviceAuthorizationEndpointConfigurer.class);
return this;
}

/**
* Configures the OAuth 2.0 Device Verification Endpoint.
* @param deviceVerificationEndpointCustomizer the {@link Customizer} providing access
Expand All @@ -261,6 +300,11 @@ public OAuth2AuthorizationServerConfigurer deviceVerificationEndpoint(
return this;
}

public OAuth2AuthorizationServerConfigurer disableDeviceVerificationEndpoint() {
removeConfigurer(OAuth2DeviceVerificationEndpointConfigurer.class);
return this;
}

/**
* Configures OpenID Connect 1.0 support (disabled by default).
* @param oidcCustomizer the {@link Customizer} providing access to the
Expand Down Expand Up @@ -335,22 +379,13 @@ public void init(HttpSecurity httpSecurity) throws Exception {
configurer.init(httpSecurity);
requestMatchers.add(configurer.getRequestMatcher());
});
// TODO: ability to disable jwk set uri
String jwkSetEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils.withMultipleIssuersPattern(authorizationServerSettings.getJwkSetEndpoint())
: authorizationServerSettings.getJwkSetEndpoint();
requestMatchers.add(new AntPathRequestMatcher(jwkSetEndpointUri, HttpMethod.GET.name()));
this.endpointsMatcher = new OrRequestMatcher(requestMatchers);

ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling = httpSecurity
.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionHandling != null) {
exceptionHandling.defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
new OrRequestMatcher(getRequestMatcher(OAuth2TokenEndpointConfigurer.class),
getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class),
getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class),
getRequestMatcher(OAuth2DeviceAuthorizationEndpointConfigurer.class)));
}

httpSecurity.csrf((csrf) -> csrf.ignoringRequestMatchers(this.endpointsMatcher));

OidcConfigurer oidcConfigurer = getConfigurer(OidcConfigurer.class);
Expand Down Expand Up @@ -422,6 +457,10 @@ private <T extends AbstractOAuth2Configurer> void addConfigurer(Class<T> configu
this.configurers.put(configurerType, configurer);
}

private void removeConfigurer(Class<?> type) {
this.configurers.remove(type);
}

private <T extends AbstractOAuth2Configurer> RequestMatcher getRequestMatcher(Class<T> configurerType) {
T configurer = getConfigurer(configurerType);
return (configurer != null) ? configurer.getRequestMatcher() : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,38 @@
*/
package org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.authentication.ClientSecretAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.authentication.JwtClientAssertionAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.authentication.PublicClientAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.authentication.X509ClientCertificateAuthenticationProvider;
import org.springframework.security.oauth2.server.authorization.authentication.*;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ConfigurationSettingNames;
import org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter;
import org.springframework.security.oauth2.server.authorization.web.authentication.ClientSecretBasicAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.ClientSecretPostAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.JwtClientAssertionAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.PublicClientAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.X509ClientCertificateAuthenticationConverter;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.oauth2.server.authorization.web.authentication.*;
import org.springframework.security.web.authentication.DelegatingAuthenticationConverter;
import org.springframework.security.web.authentication.*;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
* Configurer for OAuth 2.0 Client Authentication.
*
Expand All @@ -63,6 +57,8 @@
*/
public final class OAuth2ClientAuthenticationConfigurer extends AbstractOAuth2Configurer {

private final Map<Class<? extends AbstractOAuth2Configurer>, String> endPointUriSettingNames = createEndPointUriSettingNames();

private RequestMatcher requestMatcher;

private final List<AuthenticationConverter> authenticationConverters = new ArrayList<>();
Expand Down Expand Up @@ -180,26 +176,31 @@ public OAuth2ClientAuthenticationConfigurer errorResponseHandler(
@Override
void init(HttpSecurity httpSecurity) {
AuthorizationServerSettings authorizationServerSettings = OAuth2ConfigurerUtils
.getAuthorizationServerSettings(httpSecurity);
String tokenEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils.withMultipleIssuersPattern(authorizationServerSettings.getTokenEndpoint())
: authorizationServerSettings.getTokenEndpoint();
String tokenIntrospectionEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getTokenIntrospectionEndpoint())
: authorizationServerSettings.getTokenIntrospectionEndpoint();
String tokenRevocationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getTokenRevocationEndpoint())
: authorizationServerSettings.getTokenRevocationEndpoint();
String deviceAuthorizationEndpointUri = authorizationServerSettings.isMultipleIssuersAllowed()
? OAuth2ConfigurerUtils
.withMultipleIssuersPattern(authorizationServerSettings.getDeviceAuthorizationEndpoint())
: authorizationServerSettings.getDeviceAuthorizationEndpoint();
this.requestMatcher = new OrRequestMatcher(new AntPathRequestMatcher(tokenEndpointUri, HttpMethod.POST.name()),
new AntPathRequestMatcher(tokenIntrospectionEndpointUri, HttpMethod.POST.name()),
new AntPathRequestMatcher(tokenRevocationEndpointUri, HttpMethod.POST.name()),
new AntPathRequestMatcher(deviceAuthorizationEndpointUri, HttpMethod.POST.name()));
.getAuthorizationServerSettings(httpSecurity);

List<RequestMatcher> requestMatchers = new ArrayList<>();
this.endPointUriSettingNames.values().forEach((settingName) ->
requestMatchers.add(
new AntPathRequestMatcher(
authorizationServerSettings.isMultipleIssuersAllowed() ?
OAuth2ConfigurerUtils.withMultipleIssuersPattern(authorizationServerSettings.getSetting(settingName)) :
authorizationServerSettings.getSetting(settingName),
HttpMethod.POST.name()
)
)
);

this.requestMatcher = new OrRequestMatcher(requestMatchers);

ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling = httpSecurity
.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionHandling != null) {
exceptionHandling.defaultAuthenticationEntryPointFor(
new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
this.requestMatcher
);
}

List<AuthenticationProvider> authenticationProviders = createDefaultAuthenticationProviders(httpSecurity);
if (!this.authenticationProviders.isEmpty()) {
authenticationProviders.addAll(0, this.authenticationProviders);
Expand Down Expand Up @@ -278,4 +279,17 @@ private static List<AuthenticationProvider> createDefaultAuthenticationProviders
return authenticationProviders;
}

private Map<Class<? extends AbstractOAuth2Configurer>, String> createEndPointUriSettingNames() {
Map<Class<? extends AbstractOAuth2Configurer>, String> endPointUriSettingNames = new LinkedHashMap<>();
endPointUriSettingNames.put(OAuth2TokenEndpointConfigurer.class, ConfigurationSettingNames.AuthorizationServer.TOKEN_ENDPOINT);
endPointUriSettingNames.put(OAuth2TokenIntrospectionEndpointConfigurer.class, ConfigurationSettingNames.AuthorizationServer.TOKEN_INTROSPECTION_ENDPOINT);
endPointUriSettingNames.put(OAuth2TokenRevocationEndpointConfigurer.class, ConfigurationSettingNames.AuthorizationServer.TOKEN_REVOCATION_ENDPOINT);
endPointUriSettingNames.put(OAuth2DeviceAuthorizationEndpointConfigurer.class, ConfigurationSettingNames.AuthorizationServer.DEVICE_AUTHORIZATION_ENDPOINT);

return endPointUriSettingNames;
}

public void removeEndPointUriSettingName(Class<?> type) {
this.endPointUriSettingNames.remove(type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@
*/
package org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
Expand All @@ -30,6 +25,11 @@
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
* Configurer for OpenID Connect 1.0 support.
*
Expand Down Expand Up @@ -73,6 +73,11 @@ public OidcConfigurer providerConfigurationEndpoint(
return this;
}

public OidcConfigurer disableProviderConfigurationEndpoint() {
removeConfigurer(OidcProviderConfigurationEndpointConfigurer.class);
return this;
}

/**
* Configures the OpenID Connect 1.0 RP-Initiated Logout Endpoint.
* @param logoutEndpointCustomizer the {@link Customizer} providing access to the
Expand All @@ -85,6 +90,11 @@ public OidcConfigurer logoutEndpoint(Customizer<OidcLogoutEndpointConfigurer> lo
return this;
}

public OidcConfigurer disableLogoutEndpoint() {
removeConfigurer(OidcLogoutEndpointConfigurer.class);
return this;
}

/**
* Configures the OpenID Connect Dynamic Client Registration 1.0 Endpoint.
* @param clientRegistrationEndpointCustomizer the {@link Customizer} providing access
Expand Down Expand Up @@ -115,6 +125,11 @@ public OidcConfigurer userInfoEndpoint(Customizer<OidcUserInfoEndpointConfigurer
return this;
}

public OidcConfigurer disableUserInfoEndpoint() {
removeConfigurer(OidcUserInfoEndpointConfigurer.class);
return this;
}

@Override
void init(HttpSecurity httpSecurity) {
List<RequestMatcher> requestMatchers = new ArrayList<>();
Expand Down Expand Up @@ -165,4 +180,7 @@ private <T extends AbstractOAuth2Configurer> void addConfigurer(Class<T> configu
this.configurers.put(configurerType, configurer);
}

private void removeConfigurer(Class<?> configurerType) {
this.configurers.remove(configurerType);
}
}