Polish OAuth Security Configurers

This commit is contained in:
Joe Grandja 2017-10-09 23:35:35 -04:00
parent 97c938e7f3
commit 6b16fa0d8c
6 changed files with 397 additions and 366 deletions

View File

@ -1,203 +0,0 @@
/*
* Copyright 2012-2017 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
*
* http://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.config.annotation.web.configurers.oauth2.client;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProvider;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticator;
import org.springframework.security.oauth2.client.authentication.AuthorizationGrantAuthenticator;
import org.springframework.security.oauth2.client.authentication.DelegatingAuthorizationGrantAuthenticator;
import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationProvider;
import org.springframework.security.oauth2.client.authentication.jwt.JwtDecoderRegistry;
import org.springframework.security.oauth2.client.authentication.jwt.nimbus.NimbusJwtDecoderRegistry;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
import org.springframework.security.oauth2.client.user.CustomUserTypesOAuth2UserService;
import org.springframework.security.oauth2.client.user.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.user.DelegatingOAuth2UserService;
import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.client.web.AuthorizationCodeAuthenticationFilter;
import org.springframework.security.oauth2.client.web.AuthorizationGrantTokenExchanger;
import org.springframework.security.oauth2.client.web.nimbus.NimbusAuthorizationCodeTokenExchanger;
import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.oidc.client.authentication.OidcAuthorizationCodeAuthenticator;
import org.springframework.security.oauth2.oidc.client.user.OidcUserService;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Joe Grandja
*/
final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecurityBuilder<H>, R extends RequestMatcher> extends
AbstractAuthenticationFilterConfigurer<H, AuthorizationCodeAuthenticationFilterConfigurer<H, R>, AuthorizationCodeAuthenticationFilter> {
private R authorizationResponseMatcher;
private AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> authorizationCodeAuthenticator;
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
private SecurityTokenRepository<AccessToken> accessTokenRepository;
private JwtDecoderRegistry jwtDecoderRegistry;
private OAuth2UserService userInfoService;
private Map<URI, Class<? extends OAuth2User>> customUserTypes = new HashMap<>();
private GrantedAuthoritiesMapper userAuthoritiesMapper;
AuthorizationCodeAuthenticationFilterConfigurer() {
super(new AuthorizationCodeAuthenticationFilter(), null);
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> authorizationResponseMatcher(R authorizationResponseMatcher) {
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null");
this.authorizationResponseMatcher = authorizationResponseMatcher;
return this;
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> authorizationCodeTokenExchanger(
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger) {
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
return this;
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> accessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
Assert.notNull(accessTokenRepository, "accessTokenRepository cannot be null");
this.accessTokenRepository = accessTokenRepository;
return this;
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> jwtDecoderRegistry(JwtDecoderRegistry jwtDecoderRegistry) {
Assert.notNull(jwtDecoderRegistry, "jwtDecoderRegistry cannot be null");
this.jwtDecoderRegistry = jwtDecoderRegistry;
return this;
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> userInfoService(OAuth2UserService userInfoService) {
Assert.notNull(userInfoService, "userInfoService cannot be null");
this.userInfoService = userInfoService;
return this;
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> customUserType(Class<? extends OAuth2User> 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<H, R> userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) {
Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null");
this.userAuthoritiesMapper = userAuthoritiesMapper;
return this;
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
return this;
}
String getLoginUrl() {
return super.getLoginPage();
}
String getLoginFailureUrl() {
return super.getFailureUrl();
}
@Override
public void init(H http) throws Exception {
AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider =
new AuthorizationCodeAuthenticationProvider(this.getAuthorizationCodeAuthenticator());
if (this.accessTokenRepository != null) {
authorizationCodeAuthenticationProvider.setAccessTokenRepository(this.accessTokenRepository);
}
authorizationCodeAuthenticationProvider = this.postProcess(authorizationCodeAuthenticationProvider);
http.authenticationProvider(authorizationCodeAuthenticationProvider);
OAuth2UserAuthenticationProvider oauth2UserAuthenticationProvider =
new OAuth2UserAuthenticationProvider(this.getUserInfoService());
if (this.userAuthoritiesMapper != null) {
oauth2UserAuthenticationProvider.setAuthoritiesMapper(this.userAuthoritiesMapper);
}
oauth2UserAuthenticationProvider = this.postProcess(oauth2UserAuthenticationProvider);
http.authenticationProvider(oauth2UserAuthenticationProvider);
super.init(http);
}
@Override
public void configure(H http) throws Exception {
AuthorizationCodeAuthenticationFilter authFilter = this.getAuthenticationFilter();
if (this.authorizationResponseMatcher != null) {
authFilter.setAuthorizationResponseMatcher(this.authorizationResponseMatcher);
}
authFilter.setClientRegistrationRepository(OAuth2LoginConfigurer.getClientRegistrationRepository(this.getBuilder()));
super.configure(http);
}
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return (this.authorizationResponseMatcher != null ?
this.authorizationResponseMatcher : this.getAuthenticationFilter().getAuthorizationResponseMatcher());
}
private AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> getAuthorizationCodeAuthenticator() {
if (this.authorizationCodeAuthenticator == null) {
List<AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken>> authenticators = new ArrayList<>();
authenticators.add(new AuthorizationCodeAuthenticator(this.getAuthorizationCodeTokenExchanger()));
authenticators.add(new OidcAuthorizationCodeAuthenticator(
this.getAuthorizationCodeTokenExchanger(), this.getJwtDecoderRegistry()));
this.authorizationCodeAuthenticator = new DelegatingAuthorizationGrantAuthenticator<>(authenticators);;
}
return this.authorizationCodeAuthenticator;
}
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> getAuthorizationCodeTokenExchanger() {
if (this.authorizationCodeTokenExchanger == null) {
this.authorizationCodeTokenExchanger = new NimbusAuthorizationCodeTokenExchanger();
}
return this.authorizationCodeTokenExchanger;
}
private JwtDecoderRegistry getJwtDecoderRegistry() {
if (this.jwtDecoderRegistry == null) {
this.jwtDecoderRegistry = new NimbusJwtDecoderRegistry();
}
return this.jwtDecoderRegistry;
}
private OAuth2UserService getUserInfoService() {
if (this.userInfoService == null) {
List<OAuth2UserService> oauth2UserServices = new ArrayList<>();
oauth2UserServices.add(new DefaultOAuth2UserService());
oauth2UserServices.add(new OidcUserService());
if (!this.customUserTypes.isEmpty()) {
oauth2UserServices.add(new CustomUserTypesOAuth2UserService(this.customUserTypes));
}
this.userInfoService = new DelegatingOAuth2UserService(oauth2UserServices);
}
return this.userInfoService;
}
}

View File

@ -0,0 +1,290 @@
/*
* Copyright 2012-2017 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
*
* http://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.config.annotation.web.configurers.oauth2.client;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProvider;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticator;
import org.springframework.security.oauth2.client.authentication.AuthorizationGrantAuthenticator;
import org.springframework.security.oauth2.client.authentication.DelegatingAuthorizationGrantAuthenticator;
import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationProvider;
import org.springframework.security.oauth2.client.authentication.jwt.JwtDecoderRegistry;
import org.springframework.security.oauth2.client.authentication.jwt.nimbus.NimbusJwtDecoderRegistry;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
import org.springframework.security.oauth2.client.user.CustomUserTypesOAuth2UserService;
import org.springframework.security.oauth2.client.user.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.user.DelegatingOAuth2UserService;
import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.client.web.AuthorizationCodeAuthenticationFilter;
import org.springframework.security.oauth2.client.web.AuthorizationCodeRequestRedirectFilter;
import org.springframework.security.oauth2.client.web.AuthorizationGrantTokenExchanger;
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
import org.springframework.security.oauth2.client.web.AuthorizationRequestUriBuilder;
import org.springframework.security.oauth2.client.web.nimbus.NimbusAuthorizationCodeTokenExchanger;
import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.oidc.client.authentication.OidcAuthorizationCodeAuthenticator;
import org.springframework.security.oauth2.oidc.client.user.OidcUserService;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A security configurer for the Authorization Code Grant type.
*
* @author Joe Grandja
* @since 5.0
*/
public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>> extends
AbstractHttpConfigurer<AuthorizationCodeGrantConfigurer<B>, B> {
// ***** Authorization Request members
private AuthorizationCodeRequestRedirectFilter authorizationRequestFilter;
private RequestMatcher authorizationRequestMatcher;
private AuthorizationRequestUriBuilder authorizationRequestBuilder;
private AuthorizationRequestRepository authorizationRequestRepository;
// ***** Authorization Response members
private AuthorizationCodeAuthenticationFilter authorizationResponseFilter;
private RequestMatcher authorizationResponseMatcher;
private AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> authorizationCodeAuthenticator;
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
private SecurityTokenRepository<AccessToken> accessTokenRepository;
private JwtDecoderRegistry jwtDecoderRegistry;
private OAuth2UserService userService;
private Map<URI, Class<? extends OAuth2User>> customUserTypes = new HashMap<>();
private GrantedAuthoritiesMapper userAuthoritiesMapper;
public AuthorizationCodeGrantConfigurer<B> authorizationRequestMatcher(RequestMatcher authorizationRequestMatcher) {
Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null");
this.authorizationRequestMatcher = authorizationRequestMatcher;
return this;
}
public AuthorizationCodeGrantConfigurer<B> authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
this.authorizationRequestBuilder = authorizationRequestBuilder;
return this;
}
public AuthorizationCodeGrantConfigurer<B> authorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) {
Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null");
this.authorizationRequestRepository = authorizationRequestRepository;
return this;
}
public AuthorizationCodeGrantConfigurer<B> authorizationResponseMatcher(RequestMatcher authorizationResponseMatcher) {
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null");
this.authorizationResponseMatcher = authorizationResponseMatcher;
return this;
}
public AuthorizationCodeGrantConfigurer<B> authorizationCodeAuthenticator(
AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> authorizationCodeAuthenticator) {
Assert.notNull(authorizationCodeAuthenticator, "authorizationCodeAuthenticator cannot be null");
this.authorizationCodeAuthenticator = authorizationCodeAuthenticator;
return this;
}
public AuthorizationCodeGrantConfigurer<B> authorizationCodeTokenExchanger(
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger) {
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
return this;
}
public AuthorizationCodeGrantConfigurer<B> accessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
Assert.notNull(accessTokenRepository, "accessTokenRepository cannot be null");
this.accessTokenRepository = accessTokenRepository;
return this;
}
public AuthorizationCodeGrantConfigurer<B> jwtDecoderRegistry(JwtDecoderRegistry jwtDecoderRegistry) {
Assert.notNull(jwtDecoderRegistry, "jwtDecoderRegistry cannot be null");
this.jwtDecoderRegistry = jwtDecoderRegistry;
return this;
}
public AuthorizationCodeGrantConfigurer<B> userService(OAuth2UserService userService) {
Assert.notNull(userService, "userService cannot be null");
this.userService = userService;
return this;
}
public AuthorizationCodeGrantConfigurer<B> customUserType(Class<? extends OAuth2User> customUserType, URI userInfoUri) {
Assert.notNull(customUserType, "customUserType cannot be null");
Assert.notNull(userInfoUri, "userInfoUri cannot be null");
this.customUserTypes.put(userInfoUri, customUserType);
return this;
}
public AuthorizationCodeGrantConfigurer<B> userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) {
Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null");
this.userAuthoritiesMapper = userAuthoritiesMapper;
return this;
}
public AuthorizationCodeGrantConfigurer<B> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
return this;
}
@Override
public final void init(B http) throws Exception {
// *****************************************
// ***** Initialize AuthenticationProvider's
//
// -> AuthorizationCodeAuthenticationProvider
AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider =
new AuthorizationCodeAuthenticationProvider(this.getAuthorizationCodeAuthenticator());
if (this.accessTokenRepository != null) {
authorizationCodeAuthenticationProvider.setAccessTokenRepository(this.accessTokenRepository);
}
http.authenticationProvider(this.postProcess(authorizationCodeAuthenticationProvider));
// -> OAuth2UserAuthenticationProvider
OAuth2UserAuthenticationProvider oauth2UserAuthenticationProvider =
new OAuth2UserAuthenticationProvider(this.getUserService());
if (this.userAuthoritiesMapper != null) {
oauth2UserAuthenticationProvider.setAuthoritiesMapper(this.userAuthoritiesMapper);
}
http.authenticationProvider(this.postProcess(oauth2UserAuthenticationProvider));
// *************************
// ***** Initialize Filter's
//
// -> AuthorizationCodeRequestRedirectFilter
this.authorizationRequestFilter = new AuthorizationCodeRequestRedirectFilter(
this.getClientRegistrationRepository());
if (this.authorizationRequestMatcher != null) {
this.authorizationRequestFilter.setAuthorizationRequestMatcher(this.authorizationRequestMatcher);
}
if (this.authorizationRequestBuilder != null) {
this.authorizationRequestFilter.setAuthorizationUriBuilder(this.authorizationRequestBuilder);
}
if (this.authorizationRequestRepository != null) {
this.authorizationRequestFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
}
// -> AuthorizationCodeAuthenticationFilter
this.authorizationResponseFilter = new AuthorizationCodeAuthenticationFilter();
this.authorizationResponseFilter.setClientRegistrationRepository(this.getClientRegistrationRepository());
if (this.authorizationResponseMatcher != null) {
this.authorizationResponseFilter.setAuthorizationResponseMatcher(this.authorizationResponseMatcher);
}
if (this.authorizationRequestRepository != null) {
this.authorizationResponseFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
}
}
@Override
public void configure(B http) throws Exception {
http.addFilter(this.postProcess(this.authorizationRequestFilter));
this.authorizationResponseFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);
if (sessionAuthenticationStrategy != null) {
this.authorizationResponseFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
http.addFilter(this.postProcess(this.authorizationResponseFilter));
}
AuthorizationCodeRequestRedirectFilter getAuthorizationRequestFilter() {
return this.authorizationRequestFilter;
}
RequestMatcher getAuthorizationRequestMatcher() {
return this.authorizationRequestMatcher;
}
AuthorizationCodeAuthenticationFilter getAuthorizationResponseFilter() {
return this.authorizationResponseFilter;
}
RequestMatcher getAuthorizationResponseMatcher() {
return this.authorizationResponseMatcher;
}
AuthorizationRequestRepository getAuthorizationRequestRepository() {
return this.authorizationRequestRepository;
}
private AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> getAuthorizationCodeAuthenticator() {
if (this.authorizationCodeAuthenticator == null) {
List<AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken>> authenticators = new ArrayList<>();
authenticators.add(new AuthorizationCodeAuthenticator(this.getAuthorizationCodeTokenExchanger()));
authenticators.add(new OidcAuthorizationCodeAuthenticator(
this.getAuthorizationCodeTokenExchanger(), this.getJwtDecoderRegistry()));
this.authorizationCodeAuthenticator = new DelegatingAuthorizationGrantAuthenticator<>(authenticators);;
}
return this.authorizationCodeAuthenticator;
}
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> getAuthorizationCodeTokenExchanger() {
if (this.authorizationCodeTokenExchanger == null) {
this.authorizationCodeTokenExchanger = new NimbusAuthorizationCodeTokenExchanger();
}
return this.authorizationCodeTokenExchanger;
}
private JwtDecoderRegistry getJwtDecoderRegistry() {
if (this.jwtDecoderRegistry == null) {
this.jwtDecoderRegistry = new NimbusJwtDecoderRegistry();
}
return this.jwtDecoderRegistry;
}
private OAuth2UserService getUserService() {
if (this.userService == null) {
List<OAuth2UserService> userServices = new ArrayList<>();
userServices.add(new DefaultOAuth2UserService());
userServices.add(new OidcUserService());
if (!this.customUserTypes.isEmpty()) {
userServices.add(new CustomUserTypesOAuth2UserService(this.customUserTypes));
}
this.userService = new DelegatingOAuth2UserService(userServices);
}
return this.userService;
}
private ClientRegistrationRepository getClientRegistrationRepository() {
ClientRegistrationRepository clientRegistrationRepository = this.getBuilder().getSharedObject(ClientRegistrationRepository.class);
if (clientRegistrationRepository == null) {
clientRegistrationRepository = this.getClientRegistrationRepositoryBean();
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
}
return clientRegistrationRepository;
}
private ClientRegistrationRepository getClientRegistrationRepositoryBean() {
return this.getBuilder().getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class);
}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright 2012-2017 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
*
* http://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.config.annotation.web.configurers.oauth2.client;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.AuthorizationCodeRequestRedirectFilter;
import org.springframework.security.oauth2.client.web.AuthorizationRequestUriBuilder;
import org.springframework.security.oauth2.client.web.DefaultAuthorizationRequestUriBuilder;
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<H extends HttpSecurityBuilder<H>, R extends RequestMatcher & RequestVariablesExtractor> extends
AbstractHttpConfigurer<AuthorizationCodeRequestRedirectFilterConfigurer<H, R>, H> {
private R authorizationRequestMatcher;
private AuthorizationRequestUriBuilder authorizationRequestBuilder;
AuthorizationCodeRequestRedirectFilterConfigurer<H, R> authorizationRequestMatcher(R authorizationRequestMatcher) {
Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null");
this.authorizationRequestMatcher = authorizationRequestMatcher;
return this;
}
AuthorizationCodeRequestRedirectFilterConfigurer<H, R> authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
this.authorizationRequestBuilder = authorizationRequestBuilder;
return this;
}
AuthorizationCodeRequestRedirectFilterConfigurer<H, R> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
return this;
}
R getAuthorizationRequestMatcher() {
return this.authorizationRequestMatcher;
}
@Override
public void configure(H http) throws Exception {
AuthorizationCodeRequestRedirectFilter filter = new AuthorizationCodeRequestRedirectFilter(
OAuth2LoginConfigurer.getClientRegistrationRepository(this.getBuilder()));
if (this.authorizationRequestMatcher != null) {
filter.setAuthorizationRequestMatcher(this.authorizationRequestMatcher);
}
if (this.authorizationRequestBuilder != null) {
filter.setAuthorizationUriBuilder(this.authorizationRequestBuilder);
}
http.addFilter(this.postProcess(filter));
}
private AuthorizationRequestUriBuilder getAuthorizationRequestBuilder() {
if (this.authorizationRequestBuilder == null) {
this.authorizationRequestBuilder = new DefaultAuthorizationRequestUriBuilder();
}
return this.authorizationRequestBuilder;
}
}

View File

@ -18,86 +18,64 @@ package org.springframework.security.config.annotation.web.configurers.oauth2.cl
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.AuthorizationGrantAuthenticator;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.client.web.AuthorizationCodeAuthenticationFilter;
import org.springframework.security.oauth2.client.web.AuthorizationCodeRequestRedirectFilter;
import org.springframework.security.oauth2.client.web.AuthorizationGrantTokenExchanger;
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
import org.springframework.security.oauth2.client.web.AuthorizationRequestUriBuilder;
import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
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 java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import static org.springframework.security.oauth2.client.web.AuthorizationCodeRequestRedirectFilter.REGISTRATION_ID_URI_VARIABLE_NAME;
/**
* A security configurer for OAuth 2.0 / OpenID Connect 1.0 login.
*
* @author Joe Grandja
* @since 5.0
*/
public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<OAuth2LoginConfigurer<H>, H> {
public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> extends
AbstractAuthenticationFilterConfigurer<B, OAuth2LoginConfigurer<B>, AuthorizationCodeAuthenticationFilter> {
private final AuthorizationCodeRequestRedirectFilterConfigurer authorizationCodeRequestRedirectFilterConfigurer;
private final AuthorizationCodeAuthenticationFilterConfigurer authorizationCodeAuthenticationFilterConfigurer;
private final AuthorizationEndpointConfig authorizationEndpointConfig;
private final TokenEndpointConfig tokenEndpointConfig;
private final RedirectionEndpointConfig redirectionEndpointConfig;
private final UserInfoEndpointConfig userInfoEndpointConfig;
private final AuthorizationCodeGrantConfigurer<B> authorizationCodeGrantConfigurer = new AuthorizationCodeGrantLoginConfigurer();
private final AuthorizationEndpointConfig authorizationEndpointConfig = new AuthorizationEndpointConfig();
private final TokenEndpointConfig tokenEndpointConfig = new TokenEndpointConfig();
private final RedirectionEndpointConfig redirectionEndpointConfig = new RedirectionEndpointConfig();
private final UserInfoEndpointConfig userInfoEndpointConfig = new UserInfoEndpointConfig();
public OAuth2LoginConfigurer() {
this.authorizationCodeRequestRedirectFilterConfigurer = new AuthorizationCodeRequestRedirectFilterConfigurer<>();
this.authorizationCodeAuthenticationFilterConfigurer = new AuthorizationCodeAuthenticationFilterConfigurer<>();
this.authorizationEndpointConfig = new AuthorizationEndpointConfig();
this.tokenEndpointConfig = new TokenEndpointConfig();
this.redirectionEndpointConfig = new RedirectionEndpointConfig();
this.userInfoEndpointConfig = new UserInfoEndpointConfig();
super(new AuthorizationCodeAuthenticationFilter(), null);
}
public OAuth2LoginConfigurer<H> clients(ClientRegistration... clientRegistrations) {
public OAuth2LoginConfigurer<B> clients(ClientRegistration... clientRegistrations) {
Assert.notEmpty(clientRegistrations, "clientRegistrations cannot be empty");
return this.clients(new InMemoryClientRegistrationRepository(Arrays.asList(clientRegistrations)));
}
public OAuth2LoginConfigurer<H> clients(ClientRegistrationRepository clientRegistrationRepository) {
public OAuth2LoginConfigurer<B> clients(ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
return this;
}
public OAuth2LoginConfigurer<H> userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) {
Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null");
this.authorizationCodeAuthenticationFilterConfigurer.userAuthoritiesMapper(userAuthoritiesMapper);
return this;
}
public OAuth2LoginConfigurer<H> successHandler(AuthenticationSuccessHandler authenticationSuccessHandler) {
Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null");
this.authorizationCodeAuthenticationFilterConfigurer.successHandler(authenticationSuccessHandler);
return this;
}
public OAuth2LoginConfigurer<H> failureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null");
this.authorizationCodeAuthenticationFilterConfigurer.failureHandler(authenticationFailureHandler);
return this;
}
public AuthorizationEndpointConfig authorizationEndpoint() {
return this.authorizationEndpointConfig;
}
@ -107,19 +85,25 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
private AuthorizationEndpointConfig() {
}
public AuthorizationEndpointConfig requestMatcher(RequestMatcher authorizationRequestMatcher) {
Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null");
authorizationCodeGrantConfigurer.authorizationRequestMatcher(authorizationRequestMatcher);
return this;
}
public AuthorizationEndpointConfig authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.authorizationRequestBuilder(authorizationRequestBuilder);
authorizationCodeGrantConfigurer.authorizationRequestBuilder(authorizationRequestBuilder);
return this;
}
public <R extends RequestMatcher & RequestVariablesExtractor> AuthorizationEndpointConfig requestMatcher(R authorizationRequestMatcher) {
Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.authorizationRequestMatcher(authorizationRequestMatcher);
public AuthorizationEndpointConfig authorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) {
Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null");
authorizationCodeGrantConfigurer.authorizationRequestRepository(authorizationRequestRepository);
return this;
}
public OAuth2LoginConfigurer<H> and() {
public OAuth2LoginConfigurer<B> and() {
return OAuth2LoginConfigurer.this;
}
}
@ -133,21 +117,29 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
private TokenEndpointConfig() {
}
public TokenEndpointConfig authorizationCodeAuthenticator(
AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> authorizationCodeAuthenticator) {
Assert.notNull(authorizationCodeAuthenticator, "authorizationCodeAuthenticator cannot be null");
authorizationCodeGrantConfigurer.authorizationCodeAuthenticator(authorizationCodeAuthenticator);
return this;
}
public TokenEndpointConfig authorizationCodeTokenExchanger(
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger) {
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.authorizationCodeTokenExchanger(authorizationCodeTokenExchanger);
authorizationCodeGrantConfigurer.authorizationCodeTokenExchanger(authorizationCodeTokenExchanger);
return this;
}
public TokenEndpointConfig accessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
Assert.notNull(accessTokenRepository, "accessTokenRepository cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.accessTokenRepository(accessTokenRepository);
authorizationCodeGrantConfigurer.accessTokenRepository(accessTokenRepository);
return this;
}
public OAuth2LoginConfigurer<H> and() {
public OAuth2LoginConfigurer<B> and() {
return OAuth2LoginConfigurer.this;
}
}
@ -161,13 +153,13 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
private RedirectionEndpointConfig() {
}
public <R extends RequestMatcher> RedirectionEndpointConfig requestMatcher(R authorizationResponseMatcher) {
public RedirectionEndpointConfig requestMatcher(RequestMatcher authorizationResponseMatcher) {
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.authorizationResponseMatcher(authorizationResponseMatcher);
authorizationCodeGrantConfigurer.authorizationResponseMatcher(authorizationResponseMatcher);
return this;
}
public OAuth2LoginConfigurer<H> and() {
public OAuth2LoginConfigurer<B> and() {
return OAuth2LoginConfigurer.this;
}
}
@ -181,73 +173,82 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
private UserInfoEndpointConfig() {
}
public UserInfoEndpointConfig userInfoService(OAuth2UserService userInfoService) {
Assert.notNull(userInfoService, "userInfoService cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.userInfoService(userInfoService);
public UserInfoEndpointConfig userService(OAuth2UserService userService) {
Assert.notNull(userService, "userService cannot be null");
authorizationCodeGrantConfigurer.userService(userService);
return this;
}
public UserInfoEndpointConfig customUserType(Class<? extends OAuth2User> customUserType, URI userInfoUri) {
Assert.notNull(customUserType, "customUserType cannot be null");
Assert.notNull(userInfoUri, "userInfoUri cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.customUserType(customUserType, userInfoUri);
authorizationCodeGrantConfigurer.customUserType(customUserType, userInfoUri);
return this;
}
public OAuth2LoginConfigurer<H> and() {
public UserInfoEndpointConfig userAuthoritiesMapper(GrantedAuthoritiesMapper userAuthoritiesMapper) {
Assert.notNull(userAuthoritiesMapper, "userAuthoritiesMapper cannot be null");
authorizationCodeGrantConfigurer.userAuthoritiesMapper(userAuthoritiesMapper);
return this;
}
public OAuth2LoginConfigurer<B> and() {
return OAuth2LoginConfigurer.this;
}
}
@Override
public void init(H http) throws Exception {
this.authorizationCodeRequestRedirectFilterConfigurer.setBuilder(http);
this.authorizationCodeAuthenticationFilterConfigurer.setBuilder(http);
this.authorizationCodeRequestRedirectFilterConfigurer.init(http);
this.authorizationCodeAuthenticationFilterConfigurer.init(http);
public void init(B http) throws Exception {
super.init(http);
this.authorizationCodeGrantConfigurer.setBuilder(http);
this.authorizationCodeGrantConfigurer.init(http);
this.initDefaultLoginFilter(http);
}
@Override
public void configure(H http) throws Exception {
this.authorizationCodeRequestRedirectFilterConfigurer.configure(http);
this.authorizationCodeAuthenticationFilterConfigurer.configure(http);
public void configure(B http) throws Exception {
this.authorizationCodeGrantConfigurer.configure(http);
super.configure(http);
}
static <H extends HttpSecurityBuilder<H>> ClientRegistrationRepository getClientRegistrationRepository(H http) {
ClientRegistrationRepository clientRegistrationRepository = http.getSharedObject(ClientRegistrationRepository.class);
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return (this.authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher() != null ?
this.authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher() :
this.getAuthenticationFilter().getAuthorizationResponseMatcher());
}
private ClientRegistrationRepository getClientRegistrationRepository() {
ClientRegistrationRepository clientRegistrationRepository = this.getBuilder().getSharedObject(ClientRegistrationRepository.class);
if (clientRegistrationRepository == null) {
clientRegistrationRepository = getDefaultClientRegistrationRepository(http);
http.setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
clientRegistrationRepository = this.getClientRegistrationRepositoryBean();
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
}
return clientRegistrationRepository;
}
private static <H extends HttpSecurityBuilder<H>> ClientRegistrationRepository getDefaultClientRegistrationRepository(H http) {
return http.getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class);
private ClientRegistrationRepository getClientRegistrationRepositoryBean() {
return this.getBuilder().getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class);
}
private void initDefaultLoginFilter(H http) {
private void initDefaultLoginFilter(B http) {
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if (loginPageGeneratingFilter == null || this.authorizationCodeAuthenticationFilterConfigurer.isCustomLoginPage()) {
if (loginPageGeneratingFilter == null || this.isCustomLoginPage()) {
return;
}
Iterable<ClientRegistration> clientRegistrations = null;
ClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(http);
ClientRegistrationRepository clientRegistrationRepository = this.getClientRegistrationRepository();
ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository).as(Iterable.class);
if (type != ResolvableType.NONE) {
if (Stream.of(type.resolveGenerics()).anyMatch(ClientRegistration.class::isAssignableFrom)) {
clientRegistrations = (Iterable<ClientRegistration>) clientRegistrationRepository;
}
if (type != ResolvableType.NONE && ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
clientRegistrations = (Iterable<ClientRegistration>) clientRegistrationRepository;
}
if (clientRegistrations == null) {
return;
}
String authorizationRequestBaseUri;
RequestMatcher authorizationRequestMatcher = OAuth2LoginConfigurer.this.authorizationCodeRequestRedirectFilterConfigurer.getAuthorizationRequestMatcher();
RequestMatcher authorizationRequestMatcher = authorizationCodeGrantConfigurer.getAuthorizationRequestMatcher();
if (authorizationRequestMatcher != null && AntPathRequestMatcher.class.isAssignableFrom(authorizationRequestMatcher.getClass())) {
String authorizationRequestPattern = ((AntPathRequestMatcher)authorizationRequestMatcher).getPattern();
String registrationIdTemplateVariable = "{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}";
@ -261,12 +262,31 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
authorizationRequestBaseUri = AuthorizationCodeRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI;
}
Map<String, String> oauth2AuthenticationUrlToClientName = new HashMap<>();
clientRegistrations.forEach(registration -> oauth2AuthenticationUrlToClientName.put(
Map<String, String> authenticationUrlToClientName = new HashMap<>();
clientRegistrations.forEach(registration -> authenticationUrlToClientName.put(
authorizationRequestBaseUri + "/" + registration.getRegistrationId(), registration.getClientName()));
loginPageGeneratingFilter.setOauth2LoginEnabled(true);
loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(oauth2AuthenticationUrlToClientName);
loginPageGeneratingFilter.setLoginPageUrl(this.authorizationCodeAuthenticationFilterConfigurer.getLoginUrl());
loginPageGeneratingFilter.setFailureUrl(this.authorizationCodeAuthenticationFilterConfigurer.getLoginFailureUrl());
loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(authenticationUrlToClientName);
loginPageGeneratingFilter.setLoginPageUrl(this.getLoginPage());
loginPageGeneratingFilter.setFailureUrl(this.getFailureUrl());
}
private class AuthorizationCodeGrantLoginConfigurer extends AuthorizationCodeGrantConfigurer<B> {
@Override
public void configure(B http) throws Exception {
http.addFilter(OAuth2LoginConfigurer.this.postProcess(this.getAuthorizationRequestFilter()));
AuthorizationCodeAuthenticationFilter authorizationResponseFilter = getAuthenticationFilter();
authorizationResponseFilter.setClientRegistrationRepository(getClientRegistrationRepository());
if (authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher() != null) {
authorizationResponseFilter.setAuthorizationResponseMatcher(
authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher());
}
if (authorizationCodeGrantConfigurer.getAuthorizationRequestRepository() != null) {
authorizationResponseFilter.setAuthorizationRequestRepository(
authorizationCodeGrantConfigurer.getAuthorizationRequestRepository());
}
}
}
}

View File

@ -77,8 +77,10 @@ public class AuthorizationCodeRequestRedirectFilter extends OncePerRequestFilter
this.clientRegistrationRepository = clientRegistrationRepository;
}
public final <T extends RequestMatcher & RequestVariablesExtractor> void setAuthorizationRequestMatcher(T authorizationRequestMatcher) {
public final void setAuthorizationRequestMatcher(RequestMatcher authorizationRequestMatcher) {
Assert.notNull(authorizationRequestMatcher, "authorizationRequestMatcher cannot be null");
Assert.isInstanceOf(RequestVariablesExtractor.class, authorizationRequestMatcher,
"authorizationRequestMatcher must also be a " + RequestVariablesExtractor.class.getName());
this.authorizationRequestMatcher = authorizationRequestMatcher;
}

View File

@ -351,7 +351,7 @@ public class OAuth2LoginApplicationTests {
.authorizationCodeTokenExchanger(this.mockAuthorizationCodeTokenExchanger())
.and()
.userInfoEndpoint()
.userInfoService(this.mockUserInfoService());
.userService(this.mockUserInfoService());
}
// @formatter:on