diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeAuthenticationFilterConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeAuthenticationFilterConfigurer.java index 03efd12564..02d9530267 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeAuthenticationFilterConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeAuthenticationFilterConfigurer.java @@ -38,6 +38,7 @@ import org.springframework.security.oauth2.core.provider.DefaultProviderMetadata import org.springframework.security.oauth2.core.provider.ProviderMetadata; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.security.web.util.matcher.RequestVariablesExtractor; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.util.UriComponentsBuilder; @@ -51,9 +52,10 @@ import java.util.Map; /** * @author Joe Grandja */ -final class AuthorizationCodeAuthenticationFilterConfigurer> extends - AbstractAuthenticationFilterConfigurer, AuthorizationCodeAuthenticationProcessingFilter> { +final class AuthorizationCodeAuthenticationFilterConfigurer, R extends RequestMatcher & RequestVariablesExtractor> extends + AbstractAuthenticationFilterConfigurer, AuthorizationCodeAuthenticationProcessingFilter> { + private R authorizationResponseMatcher; private AuthorizationGrantTokenExchanger authorizationCodeTokenExchanger; private OAuth2UserService userInfoService; private Map> customUserTypes = new HashMap<>(); @@ -64,14 +66,13 @@ final class AuthorizationCodeAuthenticationFilterConfigurer clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) { - Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); - Assert.notEmpty(clientRegistrationRepository.getRegistrations(), "clientRegistrationRepository cannot be empty"); - this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository); + AuthorizationCodeAuthenticationFilterConfigurer authorizationResponseMatcher(R authorizationResponseMatcher) { + Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null"); + this.authorizationResponseMatcher = authorizationResponseMatcher; return this; } - AuthorizationCodeAuthenticationFilterConfigurer authorizationCodeTokenExchanger( + AuthorizationCodeAuthenticationFilterConfigurer authorizationCodeTokenExchanger( AuthorizationGrantTokenExchanger authorizationCodeTokenExchanger) { Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null"); @@ -79,32 +80,39 @@ final class AuthorizationCodeAuthenticationFilterConfigurer userInfoService(OAuth2UserService userInfoService) { + AuthorizationCodeAuthenticationFilterConfigurer userInfoService(OAuth2UserService userInfoService) { Assert.notNull(userInfoService, "userInfoService cannot be null"); this.userInfoService = userInfoService; return this; } - AuthorizationCodeAuthenticationFilterConfigurer customUserType(Class customUserType, URI userInfoUri) { + AuthorizationCodeAuthenticationFilterConfigurer customUserType(Class customUserType, URI userInfoUri) { Assert.notNull(customUserType, "customUserType cannot be null"); Assert.notNull(userInfoUri, "userInfoUri cannot be null"); this.customUserTypes.put(userInfoUri, customUserType); return this; } - AuthorizationCodeAuthenticationFilterConfigurer userNameAttributeName(String userNameAttributeName, URI userInfoUri) { + AuthorizationCodeAuthenticationFilterConfigurer userNameAttributeName(String userNameAttributeName, URI userInfoUri) { Assert.hasText(userNameAttributeName, "userNameAttributeName cannot be empty"); Assert.notNull(userInfoUri, "userInfoUri cannot be null"); this.userNameAttributeNames.put(userInfoUri, userNameAttributeName); return this; } - AuthorizationCodeAuthenticationFilterConfigurer userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) { + AuthorizationCodeAuthenticationFilterConfigurer userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) { Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null"); this.userAuthoritiesMapper = userAuthoritiesMapper; return this; } + AuthorizationCodeAuthenticationFilterConfigurer clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) { + Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); + Assert.notEmpty(clientRegistrationRepository.getRegistrations(), "clientRegistrationRepository cannot be empty"); + this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository); + return this; + } + String getLoginUrl() { return super.getLoginPage(); } @@ -128,13 +136,17 @@ final class AuthorizationCodeAuthenticationFilterConfigurer getAuthorizationCodeTokenExchanger(H http) { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeRequestRedirectFilterConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeRequestRedirectFilterConfigurer.java index ec506f0de1..a83e2dc297 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeRequestRedirectFilterConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeRequestRedirectFilterConfigurer.java @@ -21,34 +21,49 @@ import org.springframework.security.oauth2.client.authentication.AuthorizationCo import org.springframework.security.oauth2.client.authentication.AuthorizationRequestUriBuilder; import org.springframework.security.oauth2.client.authentication.DefaultAuthorizationRequestUriBuilder; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.security.web.util.matcher.RequestVariablesExtractor; import org.springframework.util.Assert; /** * @author Joe Grandja */ -final class AuthorizationCodeRequestRedirectFilterConfigurer> extends - AbstractHttpConfigurer, B> { +final class AuthorizationCodeRequestRedirectFilterConfigurer, R extends RequestMatcher & RequestVariablesExtractor> extends + AbstractHttpConfigurer, H> { + private R authorizationRequestMatcher; private AuthorizationRequestUriBuilder authorizationRequestBuilder; - AuthorizationCodeRequestRedirectFilterConfigurer clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) { + AuthorizationCodeRequestRedirectFilterConfigurer authorizationRequestMatcher(R authorizationRequestMatcher) { + Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null"); + this.authorizationRequestMatcher = authorizationRequestMatcher; + return this; + } + + AuthorizationCodeRequestRedirectFilterConfigurer authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) { + Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null"); + this.authorizationRequestBuilder = authorizationRequestBuilder; + return this; + } + + AuthorizationCodeRequestRedirectFilterConfigurer clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) { Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); Assert.notEmpty(clientRegistrationRepository.getRegistrations(), "clientRegistrationRepository cannot be empty"); this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository); return this; } - AuthorizationCodeRequestRedirectFilterConfigurer authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) { - Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null"); - this.authorizationRequestBuilder = authorizationRequestBuilder; - return this; + R getAuthorizationRequestMatcher() { + return this.authorizationRequestMatcher; } @Override - public void configure(B http) throws Exception { + public void configure(H http) throws Exception { AuthorizationCodeRequestRedirectFilter filter = new AuthorizationCodeRequestRedirectFilter( - OAuth2LoginConfigurer.getClientRegistrationRepository(this.getBuilder()), - this.getAuthorizationRequestBuilder()); + OAuth2LoginConfigurer.getClientRegistrationRepository(this.getBuilder()), this.getAuthorizationRequestBuilder()); + if (this.authorizationRequestMatcher != null) { + filter.setAuthorizationRequestMatcher(this.authorizationRequestMatcher); + } http.addFilter(this.postProcess(filter)); } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 8cd66b79c4..36fc41e89c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -29,6 +29,9 @@ import org.springframework.security.oauth2.client.registration.InMemoryClientReg import org.springframework.security.oauth2.client.user.OAuth2UserService; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.security.web.util.matcher.RequestVariablesExtractor; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -37,41 +40,41 @@ import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; +import static org.springframework.security.oauth2.client.authentication.AuthorizationCodeRequestRedirectFilter.CLIENT_ALIAS_URI_VARIABLE_NAME; + /** * @author Joe Grandja */ -public final class OAuth2LoginConfigurer> extends - AbstractHttpConfigurer, B> { +public final class OAuth2LoginConfigurer> extends + AbstractHttpConfigurer, H> { - private final AuthorizationCodeRequestRedirectFilterConfigurer authorizationCodeRequestRedirectFilterConfigurer; - private final AuthorizationCodeAuthenticationFilterConfigurer authorizationCodeAuthenticationFilterConfigurer; + private final AuthorizationCodeRequestRedirectFilterConfigurer authorizationCodeRequestRedirectFilterConfigurer; + private final AuthorizationCodeAuthenticationFilterConfigurer authorizationCodeAuthenticationFilterConfigurer; + private final AuthorizationEndpointConfig authorizationEndpoint; + private final RedirectionEndpointConfig redirectionEndpoint; private final UserInfoEndpointConfig userInfoEndpointConfig; public OAuth2LoginConfigurer() { this.authorizationCodeRequestRedirectFilterConfigurer = new AuthorizationCodeRequestRedirectFilterConfigurer<>(); this.authorizationCodeAuthenticationFilterConfigurer = new AuthorizationCodeAuthenticationFilterConfigurer<>(); + this.authorizationEndpoint = new AuthorizationEndpointConfig(); + this.redirectionEndpoint = new RedirectionEndpointConfig(); this.userInfoEndpointConfig = new UserInfoEndpointConfig(); } - public OAuth2LoginConfigurer clients(ClientRegistration... clientRegistrations) { + public OAuth2LoginConfigurer clients(ClientRegistration... clientRegistrations) { Assert.notEmpty(clientRegistrations, "clientRegistrations cannot be empty"); - return clients(new InMemoryClientRegistrationRepository(Arrays.asList(clientRegistrations))); + return this.clients(new InMemoryClientRegistrationRepository(Arrays.asList(clientRegistrations))); } - public OAuth2LoginConfigurer clients(ClientRegistrationRepository clientRegistrationRepository) { + public OAuth2LoginConfigurer clients(ClientRegistrationRepository clientRegistrationRepository) { Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); Assert.notEmpty(clientRegistrationRepository.getRegistrations(), "clientRegistrationRepository cannot be empty"); this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository); return this; } - public OAuth2LoginConfigurer authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) { - Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null"); - this.authorizationCodeRequestRedirectFilterConfigurer.authorizationRequestBuilder(authorizationRequestBuilder); - return this; - } - - public OAuth2LoginConfigurer authorizationCodeTokenExchanger( + public OAuth2LoginConfigurer authorizationCodeTokenExchanger( AuthorizationGrantTokenExchanger authorizationCodeTokenExchanger) { Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null"); @@ -79,12 +82,58 @@ public final class OAuth2LoginConfigurer> exten return this; } - public OAuth2LoginConfigurer userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) { + public OAuth2LoginConfigurer userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) { Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null"); this.authorizationCodeAuthenticationFilterConfigurer.userAuthoritiesMapper(userAuthoritiesMapper); return this; } + public AuthorizationEndpointConfig authorizationEndpoint() { + return this.authorizationEndpoint; + } + + public class AuthorizationEndpointConfig { + + private AuthorizationEndpointConfig() { + } + + public AuthorizationEndpointConfig authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) { + Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null"); + OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.authorizationRequestBuilder(authorizationRequestBuilder); + return this; + } + + public AuthorizationEndpointConfig requestMatcher(R authorizationRequestMatcher) { + Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null"); + OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.authorizationRequestMatcher(authorizationRequestMatcher); + return this; + } + + public OAuth2LoginConfigurer and() { + return OAuth2LoginConfigurer.this; + } + } + + public RedirectionEndpointConfig redirectionEndpoint() { + return this.redirectionEndpoint; + } + + public class RedirectionEndpointConfig { + + private RedirectionEndpointConfig() { + } + + public RedirectionEndpointConfig requestMatcher(R authorizationResponseMatcher) { + Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null"); + OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.authorizationResponseMatcher(authorizationResponseMatcher); + return this; + } + + public OAuth2LoginConfigurer and() { + return OAuth2LoginConfigurer.this; + } + } + public UserInfoEndpointConfig userInfoEndpoint() { return this.userInfoEndpointConfig; } @@ -94,33 +143,33 @@ public final class OAuth2LoginConfigurer> exten private UserInfoEndpointConfig() { } - public OAuth2LoginConfigurer userInfoService(OAuth2UserService userInfoService) { + public UserInfoEndpointConfig userInfoService(OAuth2UserService userInfoService) { Assert.notNull(userInfoService, "userInfoService cannot be null"); OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.userInfoService(userInfoService); - return this.and(); + return this; } - public OAuth2LoginConfigurer customUserType(Class customUserType, URI userInfoUri) { + public UserInfoEndpointConfig customUserType(Class customUserType, URI userInfoUri) { Assert.notNull(customUserType, "customUserType cannot be null"); Assert.notNull(userInfoUri, "userInfoUri cannot be null"); OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.customUserType(customUserType, userInfoUri); - return this.and(); + return this; } - public OAuth2LoginConfigurer userNameAttributeName(String userNameAttributeName, URI userInfoUri) { + public UserInfoEndpointConfig userNameAttributeName(String userNameAttributeName, URI userInfoUri) { Assert.hasText(userNameAttributeName, "userNameAttributeName cannot be empty"); Assert.notNull(userInfoUri, "userInfoUri cannot be null"); OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.userNameAttributeName(userNameAttributeName, userInfoUri); - return this.and(); + return this; } - public OAuth2LoginConfigurer and() { + public OAuth2LoginConfigurer and() { return OAuth2LoginConfigurer.this; } } @Override - public void init(B http) throws Exception { + public void init(H http) throws Exception { this.authorizationCodeRequestRedirectFilterConfigurer.setBuilder(http); this.authorizationCodeAuthenticationFilterConfigurer.setBuilder(http); @@ -130,12 +179,12 @@ public final class OAuth2LoginConfigurer> exten } @Override - public void configure(B http) throws Exception { + public void configure(H http) throws Exception { this.authorizationCodeRequestRedirectFilterConfigurer.configure(http); this.authorizationCodeAuthenticationFilterConfigurer.configure(http); } - static > ClientRegistrationRepository getClientRegistrationRepository(B http) { + static > ClientRegistrationRepository getClientRegistrationRepository(H http) { ClientRegistrationRepository clientRegistrationRepository = http.getSharedObject(ClientRegistrationRepository.class); if (clientRegistrationRepository == null) { clientRegistrationRepository = getDefaultClientRegistrationRepository(http); @@ -144,17 +193,33 @@ public final class OAuth2LoginConfigurer> exten return clientRegistrationRepository; } - private static > ClientRegistrationRepository getDefaultClientRegistrationRepository(B http) { + private static > ClientRegistrationRepository getDefaultClientRegistrationRepository(H http) { return http.getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class); } - private void initDefaultLoginFilter(B http) { + private void initDefaultLoginFilter(H http) { DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class); if (loginPageGeneratingFilter != null && !this.authorizationCodeAuthenticationFilterConfigurer.isCustomLoginPage()) { ClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(this.getBuilder()); if (!CollectionUtils.isEmpty(clientRegistrationRepository.getRegistrations())) { + String authorizationRequestBaseUri; + RequestMatcher authorizationRequestMatcher = OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.getAuthorizationRequestMatcher(); + if (authorizationRequestMatcher != null && AntPathRequestMatcher.class.isAssignableFrom(authorizationRequestMatcher.getClass())) { + String authorizationRequestPattern = ((AntPathRequestMatcher)authorizationRequestMatcher).getPattern(); + String clientAliasTemplateVariable = "{" + CLIENT_ALIAS_URI_VARIABLE_NAME + "}"; + if (authorizationRequestPattern.endsWith(clientAliasTemplateVariable)) { + authorizationRequestBaseUri = authorizationRequestPattern.substring( + 0, authorizationRequestPattern.length() - clientAliasTemplateVariable.length() - 1); + } else { + authorizationRequestBaseUri = authorizationRequestPattern; + } + } else { + authorizationRequestBaseUri = AuthorizationCodeRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; + } + Map oauth2AuthenticationUrlToClientName = clientRegistrationRepository.getRegistrations().stream() - .collect(Collectors.toMap(e -> AuthorizationCodeRequestRedirectFilter.AUTHORIZATION_BASE_URI + "/" + e.getClientAlias(), + .collect(Collectors.toMap( + e -> authorizationRequestBaseUri + "/" + e.getClientAlias(), e -> e.getClientName())); loginPageGeneratingFilter.setOauth2LoginEnabled(true); loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(oauth2AuthenticationUrlToClientName); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProcessingFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProcessingFilter.java index 3554725a57..b063ab57b5 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProcessingFilter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProcessingFilter.java @@ -30,6 +30,7 @@ import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.security.web.util.matcher.RequestVariablesExtractor; import org.springframework.util.Assert; import javax.servlet.ServletException; @@ -99,21 +100,21 @@ import java.io.IOException; * @see Section 4.1.2 Authorization Response */ public class AuthorizationCodeAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { - public static final String AUTHORIZE_BASE_URI = "/oauth2/authorize/code"; - private static final String CLIENT_ALIAS_VARIABLE_NAME = "clientAlias"; - private static final String AUTHORIZE_URI = AUTHORIZE_BASE_URI + "/{" + CLIENT_ALIAS_VARIABLE_NAME + "}"; + public static final String DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI = "/oauth2/authorize/code"; + public static final String CLIENT_ALIAS_URI_VARIABLE_NAME = "clientAlias"; + public static final String DEFAULT_AUTHORIZATION_RESPONSE_URI = DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI + "/{" + CLIENT_ALIAS_URI_VARIABLE_NAME + "}"; private static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found"; private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter"; private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter"; private final ErrorResponseAttributesConverter errorResponseConverter = new ErrorResponseAttributesConverter(); private final AuthorizationCodeAuthorizationResponseAttributesConverter authorizationCodeResponseConverter = new AuthorizationCodeAuthorizationResponseAttributesConverter(); - private final RequestMatcher authorizeRequestMatcher = new AntPathRequestMatcher(AUTHORIZE_URI); + private RequestMatcher authorizationResponseMatcher = new AntPathRequestMatcher(DEFAULT_AUTHORIZATION_RESPONSE_URI); private ClientRegistrationRepository clientRegistrationRepository; private AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository(); public AuthorizationCodeAuthenticationProcessingFilter() { - super(AUTHORIZE_URI); + super(DEFAULT_AUTHORIZATION_RESPONSE_URI); } @Override @@ -157,8 +158,14 @@ public class AuthorizationCodeAuthenticationProcessingFilter extends AbstractAut return authenticated; } - public RequestMatcher getAuthorizeRequestMatcher() { - return this.authorizeRequestMatcher; + public RequestMatcher getAuthorizationResponseMatcher() { + return this.authorizationResponseMatcher; + } + + public final void setAuthorizationResponseMatcher(T authorizationResponseMatcher) { + Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null"); + this.authorizationResponseMatcher = authorizationResponseMatcher; + this.setRequiresAuthenticationRequestMatcher(authorizationResponseMatcher); } protected ClientRegistrationRepository getClientRegistrationRepository() { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeRequestRedirectFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeRequestRedirectFilter.java index b8b0cea523..312920b0dc 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeRequestRedirectFilter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeRequestRedirectFilter.java @@ -22,6 +22,8 @@ import org.springframework.security.oauth2.core.endpoint.AuthorizationRequestAtt import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.RedirectStrategy; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.security.web.util.matcher.RequestVariablesExtractor; import org.springframework.util.Assert; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.util.UriComponentsBuilder; @@ -35,8 +37,6 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; -import static org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProcessingFilter.AUTHORIZE_BASE_URI; - /** * This Filter initiates the authorization code grant flow by redirecting * the end-user's user-agent to the authorization server's Authorization Endpoint. @@ -60,10 +60,10 @@ import static org.springframework.security.oauth2.client.authentication.Authoriz * @see Section 4.1.1 Authorization Request */ public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter { - public static final String AUTHORIZATION_BASE_URI = "/oauth2/authorization/code"; - private static final String CLIENT_ALIAS_VARIABLE_NAME = "clientAlias"; - private static final String AUTHORIZATION_URI = AUTHORIZATION_BASE_URI + "/{" + CLIENT_ALIAS_VARIABLE_NAME + "}"; - private final AntPathRequestMatcher authorizationRequestMatcher; + public static final String DEFAULT_AUTHORIZATION_REQUEST_BASE_URI = "/oauth2/authorization/code"; + public static final String CLIENT_ALIAS_URI_VARIABLE_NAME = "clientAlias"; + public static final String DEFAULT_AUTHORIZATION_REQUEST_URI = DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{" + CLIENT_ALIAS_URI_VARIABLE_NAME + "}"; + private RequestMatcher authorizationRequestMatcher; private final ClientRegistrationRepository clientRegistrationRepository; private final AuthorizationRequestUriBuilder authorizationUriBuilder; private final RedirectStrategy authorizationRedirectStrategy = new DefaultRedirectStrategy(); @@ -75,11 +75,16 @@ public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); Assert.notNull(authorizationUriBuilder, "authorizationUriBuilder cannot be null"); - this.authorizationRequestMatcher = new AntPathRequestMatcher(AUTHORIZATION_URI); + this.authorizationRequestMatcher = new AntPathRequestMatcher(DEFAULT_AUTHORIZATION_REQUEST_URI); this.clientRegistrationRepository = clientRegistrationRepository; this.authorizationUriBuilder = authorizationUriBuilder; } + public final void setAuthorizationRequestMatcher(T authorizationRequestMatcher) { + Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null"); + this.authorizationRequestMatcher = authorizationRequestMatcher; + } + public final void setAuthorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) { Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null"); this.authorizationRequestRepository = authorizationRequestRepository; @@ -108,8 +113,8 @@ public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter protected void sendRedirectForAuthorizationCode(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - String clientAlias = this.authorizationRequestMatcher - .extractUriTemplateVariables(request).get(CLIENT_ALIAS_VARIABLE_NAME); + String clientAlias = ((RequestVariablesExtractor)this.authorizationRequestMatcher) + .extractUriTemplateVariables(request).get(CLIENT_ALIAS_URI_VARIABLE_NAME); ClientRegistration clientRegistration = this.clientRegistrationRepository.getRegistrationByClientAlias(clientAlias); if (clientRegistration == null) { throw new IllegalArgumentException("Invalid Client Identifier (Alias): " + clientAlias); @@ -146,7 +151,6 @@ public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter uriVariables.put("scheme", request.getScheme()); uriVariables.put("serverName", request.getServerName()); uriVariables.put("serverPort", String.valueOf(request.getServerPort())); - uriVariables.put("baseAuthorizeUri", AUTHORIZE_BASE_URI); uriVariables.put("clientAlias", clientRegistration.getClientAlias()); return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUri()) diff --git a/samples/boot/oauth2login/src/main/resources/META-INF/oauth2-clients-defaults.yml b/samples/boot/oauth2login/src/main/resources/META-INF/oauth2-clients-defaults.yml index 369ed40808..4707ee4a01 100644 --- a/samples/boot/oauth2login/src/main/resources/META-INF/oauth2-clients-defaults.yml +++ b/samples/boot/oauth2login/src/main/resources/META-INF/oauth2-clients-defaults.yml @@ -4,7 +4,7 @@ security: google: client-authentication-method: basic authorized-grant-type: authorization_code - redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}" + redirect-uri: "{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}" scopes: openid, profile, email, address, phone authorization-uri: "https://accounts.google.com/o/oauth2/auth" token-uri: "https://accounts.google.com/o/oauth2/token" @@ -15,7 +15,7 @@ security: github: client-authentication-method: basic authorized-grant-type: authorization_code - redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}" + redirect-uri: "{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}" scopes: user authorization-uri: "https://github.com/login/oauth/authorize" token-uri: "https://github.com/login/oauth/access_token" @@ -26,7 +26,7 @@ security: facebook: client-authentication-method: post authorized-grant-type: authorization_code - redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}" + redirect-uri: "{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}" scopes: public_profile, email authorization-uri: "https://www.facebook.com/v2.8/dialog/oauth" token-uri: "https://graph.facebook.com/v2.8/oauth/access_token" @@ -37,7 +37,7 @@ security: okta: client-authentication-method: basic authorized-grant-type: authorization_code - redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}" + redirect-uri: "{scheme}://{serverName}:{serverPort}/oauth2/authorize/code/{clientAlias}" scopes: openid, profile, email, address, phone client-name: Okta client-alias: okta