parent
0fb32a052e
commit
049080290e
|
@ -29,7 +29,6 @@ import org.springframework.security.oauth2.client.authentication.jwt.NimbusJwtDe
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.CustomUserTypesOAuth2UserService;
|
import org.springframework.security.oauth2.client.authentication.userinfo.CustomUserTypesOAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.DefaultOAuth2UserService;
|
import org.springframework.security.oauth2.client.authentication.userinfo.DefaultOAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.DelegatingOAuth2UserService;
|
import org.springframework.security.oauth2.client.authentication.userinfo.DelegatingOAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserAuthenticationProvider;
|
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserService;
|
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||||
|
@ -42,7 +41,6 @@ import org.springframework.security.oauth2.core.AccessToken;
|
||||||
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequestUriBuilder;
|
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequestUriBuilder;
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.security.oauth2.oidc.client.authentication.OidcAuthorizationCodeAuthenticationProvider;
|
import org.springframework.security.oauth2.oidc.client.authentication.OidcAuthorizationCodeAuthenticationProvider;
|
||||||
import org.springframework.security.oauth2.oidc.client.authentication.userinfo.OidcUserAuthenticationProvider;
|
|
||||||
import org.springframework.security.oauth2.oidc.client.authentication.userinfo.OidcUserService;
|
import org.springframework.security.oauth2.oidc.client.authentication.userinfo.OidcUserService;
|
||||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
@ -232,58 +230,53 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
|
||||||
authorizationCodeTokenExchanger = new NimbusAuthorizationCodeTokenExchanger();
|
authorizationCodeTokenExchanger = new NimbusAuthorizationCodeTokenExchanger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OAuth2UserService oauth2UserService = this.userInfoEndpointConfig.userService;
|
||||||
|
if (oauth2UserService == null) {
|
||||||
|
if (!this.userInfoEndpointConfig.customUserTypes.isEmpty()) {
|
||||||
|
List<OAuth2UserService> userServices = new ArrayList<>();
|
||||||
|
userServices.add(new CustomUserTypesOAuth2UserService(this.userInfoEndpointConfig.customUserTypes));
|
||||||
|
userServices.add(new DefaultOAuth2UserService());
|
||||||
|
oauth2UserService = new DelegatingOAuth2UserService(userServices);
|
||||||
|
} else {
|
||||||
|
oauth2UserService = new DefaultOAuth2UserService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JwtDecoderRegistry jwtDecoderRegistry = this.tokenEndpointConfig.jwtDecoderRegistry;
|
JwtDecoderRegistry jwtDecoderRegistry = this.tokenEndpointConfig.jwtDecoderRegistry;
|
||||||
if (jwtDecoderRegistry == null) {
|
if (jwtDecoderRegistry == null) {
|
||||||
jwtDecoderRegistry = new NimbusJwtDecoderRegistry();
|
jwtDecoderRegistry = new NimbusJwtDecoderRegistry();
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthorizationCodeAuthenticationProvider oauth2AuthorizationCodeAuthenticationProvider =
|
AuthorizationCodeAuthenticationProvider oauth2AuthorizationCodeAuthenticationProvider =
|
||||||
new AuthorizationCodeAuthenticationProvider(authorizationCodeTokenExchanger);
|
new AuthorizationCodeAuthenticationProvider(authorizationCodeTokenExchanger, oauth2UserService);
|
||||||
if (this.tokenEndpointConfig.accessTokenRepository != null) {
|
if (this.tokenEndpointConfig.accessTokenRepository != null) {
|
||||||
oauth2AuthorizationCodeAuthenticationProvider.setAccessTokenRepository(
|
oauth2AuthorizationCodeAuthenticationProvider.setAccessTokenRepository(
|
||||||
this.tokenEndpointConfig.accessTokenRepository);
|
this.tokenEndpointConfig.accessTokenRepository);
|
||||||
}
|
}
|
||||||
|
if (this.userInfoEndpointConfig.userAuthoritiesMapper != null) {
|
||||||
|
oauth2AuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(
|
||||||
|
this.userInfoEndpointConfig.userAuthoritiesMapper);
|
||||||
|
}
|
||||||
http.authenticationProvider(this.postProcess(oauth2AuthorizationCodeAuthenticationProvider));
|
http.authenticationProvider(this.postProcess(oauth2AuthorizationCodeAuthenticationProvider));
|
||||||
|
|
||||||
|
OAuth2UserService oidcUserService = this.userInfoEndpointConfig.userService;
|
||||||
|
if (oidcUserService == null) {
|
||||||
|
oidcUserService = new OidcUserService();
|
||||||
|
}
|
||||||
|
|
||||||
OidcAuthorizationCodeAuthenticationProvider oidcAuthorizationCodeAuthenticationProvider =
|
OidcAuthorizationCodeAuthenticationProvider oidcAuthorizationCodeAuthenticationProvider =
|
||||||
new OidcAuthorizationCodeAuthenticationProvider(authorizationCodeTokenExchanger, jwtDecoderRegistry);
|
new OidcAuthorizationCodeAuthenticationProvider(
|
||||||
|
authorizationCodeTokenExchanger, oidcUserService, jwtDecoderRegistry);
|
||||||
if (this.tokenEndpointConfig.accessTokenRepository != null) {
|
if (this.tokenEndpointConfig.accessTokenRepository != null) {
|
||||||
oidcAuthorizationCodeAuthenticationProvider.setAccessTokenRepository(
|
oidcAuthorizationCodeAuthenticationProvider.setAccessTokenRepository(
|
||||||
this.tokenEndpointConfig.accessTokenRepository);
|
this.tokenEndpointConfig.accessTokenRepository);
|
||||||
}
|
}
|
||||||
|
if (this.userInfoEndpointConfig.userAuthoritiesMapper != null) {
|
||||||
|
oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(
|
||||||
|
this.userInfoEndpointConfig.userAuthoritiesMapper);
|
||||||
|
}
|
||||||
http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider));
|
http.authenticationProvider(this.postProcess(oidcAuthorizationCodeAuthenticationProvider));
|
||||||
|
|
||||||
OAuth2UserService userService = this.userInfoEndpointConfig.userService;
|
|
||||||
if (userService == null) {
|
|
||||||
if (!this.userInfoEndpointConfig.customUserTypes.isEmpty()) {
|
|
||||||
List<OAuth2UserService> userServices = new ArrayList<>();
|
|
||||||
userServices.add(new CustomUserTypesOAuth2UserService(this.userInfoEndpointConfig.customUserTypes));
|
|
||||||
userServices.add(new DefaultOAuth2UserService());
|
|
||||||
userService = new DelegatingOAuth2UserService(userServices);
|
|
||||||
} else {
|
|
||||||
userService = new DefaultOAuth2UserService();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2UserAuthenticationProvider oauth2UserAuthenticationProvider =
|
|
||||||
new OAuth2UserAuthenticationProvider(userService);
|
|
||||||
if (this.userInfoEndpointConfig.userAuthoritiesMapper != null) {
|
|
||||||
oauth2UserAuthenticationProvider.setAuthoritiesMapper(this.userInfoEndpointConfig.userAuthoritiesMapper);
|
|
||||||
}
|
|
||||||
http.authenticationProvider(this.postProcess(oauth2UserAuthenticationProvider));
|
|
||||||
|
|
||||||
userService = this.userInfoEndpointConfig.userService;
|
|
||||||
if (userService == null) {
|
|
||||||
userService = new OidcUserService();
|
|
||||||
}
|
|
||||||
|
|
||||||
OidcUserAuthenticationProvider oidcUserAuthenticationProvider =
|
|
||||||
new OidcUserAuthenticationProvider(userService);
|
|
||||||
if (this.userInfoEndpointConfig.userAuthoritiesMapper != null) {
|
|
||||||
oidcUserAuthenticationProvider.setAuthoritiesMapper(this.userInfoEndpointConfig.userAuthoritiesMapper);
|
|
||||||
}
|
|
||||||
http.authenticationProvider(this.postProcess(oidcUserAuthenticationProvider));
|
|
||||||
|
|
||||||
this.initDefaultLoginFilter(http);
|
this.initDefaultLoginFilter(http);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,10 @@ package org.springframework.security.oauth2.client.authentication;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||||
|
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2AuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.token.InMemoryAccessTokenRepository;
|
import org.springframework.security.oauth2.client.token.InMemoryAccessTokenRepository;
|
||||||
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
|
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
|
||||||
import org.springframework.security.oauth2.core.AccessToken;
|
import org.springframework.security.oauth2.core.AccessToken;
|
||||||
|
@ -25,8 +29,11 @@ import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.core.endpoint.AuthorizationResponse;
|
import org.springframework.security.oauth2.core.endpoint.AuthorizationResponse;
|
||||||
import org.springframework.security.oauth2.core.endpoint.TokenResponse;
|
import org.springframework.security.oauth2.core.endpoint.TokenResponse;
|
||||||
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of an {@link AuthenticationProvider}
|
* An implementation of an {@link AuthenticationProvider}
|
||||||
* for the <i>OAuth 2.0 Authorization Code Grant Flow</i>.
|
* for the <i>OAuth 2.0 Authorization Code Grant Flow</i>.
|
||||||
|
@ -34,12 +41,19 @@ import org.springframework.util.Assert;
|
||||||
* This {@link AuthenticationProvider} is responsible for authenticating
|
* This {@link AuthenticationProvider} is responsible for authenticating
|
||||||
* an <i>authorization code</i> credential with the authorization server's <i>Token Endpoint</i>
|
* an <i>authorization code</i> credential with the authorization server's <i>Token Endpoint</i>
|
||||||
* and if valid, exchanging it for an <i>access token</i> credential.
|
* and if valid, exchanging it for an <i>access token</i> credential.
|
||||||
|
* <p>
|
||||||
|
* It will also obtain the user attributes of the <i>End-User</i> (resource owner)
|
||||||
|
* from the <i>UserInfo Endpoint</i> using an {@link OAuth2UserService}
|
||||||
|
* which will create a <code>Principal</code> in the form of an {@link OAuth2User}.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see AuthorizationCodeAuthenticationToken
|
* @see AuthorizationCodeAuthenticationToken
|
||||||
* @see OAuth2ClientAuthenticationToken
|
|
||||||
* @see SecurityTokenRepository
|
* @see SecurityTokenRepository
|
||||||
|
* @see OAuth2AuthenticationToken
|
||||||
|
* @see OAuth2ClientAuthenticationToken
|
||||||
|
* @see OAuth2UserService
|
||||||
|
* @see OAuth2User
|
||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant Flow</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant Flow</a>
|
||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.3">Section 4.1.3 Access Token Request</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.3">Section 4.1.3 Access Token Request</a>
|
||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.4">Section 4.1.4 Access Token Response</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.4">Section 4.1.4 Access Token Response</a>
|
||||||
|
@ -48,13 +62,18 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr
|
||||||
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
|
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 static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
|
||||||
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
||||||
|
private final OAuth2UserService userService;
|
||||||
private SecurityTokenRepository<AccessToken> accessTokenRepository = new InMemoryAccessTokenRepository();
|
private SecurityTokenRepository<AccessToken> accessTokenRepository = new InMemoryAccessTokenRepository();
|
||||||
|
private GrantedAuthoritiesMapper authoritiesMapper = (authorities -> authorities);
|
||||||
|
|
||||||
public AuthorizationCodeAuthenticationProvider(
|
public AuthorizationCodeAuthenticationProvider(
|
||||||
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger) {
|
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger,
|
||||||
|
OAuth2UserService userService) {
|
||||||
|
|
||||||
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
|
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
|
||||||
|
Assert.notNull(userService, "userService cannot be null");
|
||||||
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
|
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
|
||||||
|
this.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,7 +126,16 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr
|
||||||
clientAuthentication.getAccessToken(),
|
clientAuthentication.getAccessToken(),
|
||||||
clientAuthentication.getClientRegistration());
|
clientAuthentication.getClientRegistration());
|
||||||
|
|
||||||
return clientAuthentication;
|
OAuth2User oauth2User = this.userService.loadUser(clientAuthentication);
|
||||||
|
|
||||||
|
Collection<? extends GrantedAuthority> mappedAuthorities =
|
||||||
|
this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
|
||||||
|
|
||||||
|
OAuth2AuthenticationToken authenticationResult = new OAuth2AuthenticationToken(
|
||||||
|
oauth2User, mappedAuthorities, clientAuthentication);
|
||||||
|
authenticationResult.setDetails(clientAuthentication.getDetails());
|
||||||
|
|
||||||
|
return authenticationResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setAccessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
|
public final void setAccessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
|
||||||
|
@ -115,6 +143,11 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr
|
||||||
this.accessTokenRepository = accessTokenRepository;
|
this.accessTokenRepository = accessTokenRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||||
|
Assert.notNull(authoritiesMapper, "authoritiesMapper cannot be null");
|
||||||
|
this.authoritiesMapper = authoritiesMapper;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(Class<?> authentication) {
|
public boolean supports(Class<?> authentication) {
|
||||||
return AuthorizationCodeAuthenticationToken.class.isAssignableFrom(authentication);
|
return AuthorizationCodeAuthenticationToken.class.isAssignableFrom(authentication);
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of an {@link AbstractAuthenticationToken}
|
* An implementation of an {@link AbstractAuthenticationToken}
|
||||||
* that represents an <i>OAuth 2.0 User</i> {@link Authentication}.
|
* that represents an <i>OAuth 2.0</i> {@link Authentication}.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This {@link Authentication} associates an {@link OAuth2User} principal to an
|
* This {@link Authentication} associates an {@link OAuth2User} principal to an
|
||||||
|
@ -38,13 +38,13 @@ import java.util.Collection;
|
||||||
* @see OAuth2User
|
* @see OAuth2User
|
||||||
* @see OAuth2ClientAuthenticationToken
|
* @see OAuth2ClientAuthenticationToken
|
||||||
*/
|
*/
|
||||||
public class OAuth2UserAuthenticationToken extends AbstractAuthenticationToken {
|
public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
|
||||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||||
private final OAuth2User principal;
|
private final OAuth2User principal;
|
||||||
private final OAuth2ClientAuthenticationToken clientAuthentication;
|
private final OAuth2ClientAuthenticationToken clientAuthentication;
|
||||||
|
|
||||||
public OAuth2UserAuthenticationToken(OAuth2User principal, Collection<? extends GrantedAuthority> authorities,
|
public OAuth2AuthenticationToken(OAuth2User principal, Collection<? extends GrantedAuthority> authorities,
|
||||||
OAuth2ClientAuthenticationToken clientAuthentication) {
|
OAuth2ClientAuthenticationToken clientAuthentication) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
|
Assert.notNull(clientAuthentication, "clientAuthentication cannot be null");
|
||||||
this.principal = principal;
|
this.principal = principal;
|
|
@ -1,131 +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.oauth2.client.authentication.userinfo;
|
|
||||||
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of an {@link AuthenticationProvider} that is responsible
|
|
||||||
* for obtaining the user attributes of the <i>End-User</i> (resource owner)
|
|
||||||
* from the <i>UserInfo Endpoint</i> and creating a <code>Principal</code>
|
|
||||||
* in the form of an {@link OAuth2User}.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The {@link OAuth2UserAuthenticationProvider} uses an {@link OAuth2UserService}
|
|
||||||
* for loading the {@link OAuth2User} and then associating it
|
|
||||||
* to the returned {@link OAuth2UserAuthenticationToken}.
|
|
||||||
*
|
|
||||||
* @author Joe Grandja
|
|
||||||
* @since 5.0
|
|
||||||
* @see OAuth2UserAuthenticationToken
|
|
||||||
* @see OAuth2ClientAuthenticationToken
|
|
||||||
* @see OAuth2UserService
|
|
||||||
* @see OAuth2User
|
|
||||||
*/
|
|
||||||
public class OAuth2UserAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
private final OAuth2UserService userService;
|
|
||||||
private GrantedAuthoritiesMapper authoritiesMapper = (authorities -> authorities);
|
|
||||||
|
|
||||||
public OAuth2UserAuthenticationProvider(OAuth2UserService userService) {
|
|
||||||
Assert.notNull(userService, "userService cannot be null");
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
OAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken)authentication;
|
|
||||||
|
|
||||||
// Section 3.1.2.1 Authentication Request - http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
|
||||||
// scope
|
|
||||||
// REQUIRED. OpenID Connect requests MUST contain the "openid" scope value.
|
|
||||||
if (clientAuthentication.getAuthorizedScopes().contains("openid")) {
|
|
||||||
// This is an OpenID Connect Authentication Request so return null
|
|
||||||
// and let OidcUserAuthenticationProvider handle it instead
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.userAuthenticated() && this.userAuthenticatedSameProviderAs(clientAuthentication)) {
|
|
||||||
// Create a new user authentication (using same principal)
|
|
||||||
// but with a different client authentication association
|
|
||||||
OAuth2UserAuthenticationToken currentUserAuthentication =
|
|
||||||
(OAuth2UserAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
return new OAuth2UserAuthenticationToken(
|
|
||||||
(OAuth2User)currentUserAuthentication.getPrincipal(),
|
|
||||||
currentUserAuthentication.getAuthorities(),
|
|
||||||
clientAuthentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2User oauth2User = this.userService.loadUser(clientAuthentication);
|
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> mappedAuthorities =
|
|
||||||
this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
|
|
||||||
|
|
||||||
OAuth2UserAuthenticationToken authenticationResult = new OAuth2UserAuthenticationToken(
|
|
||||||
oauth2User, mappedAuthorities, clientAuthentication);
|
|
||||||
authenticationResult.setDetails(clientAuthentication.getDetails());
|
|
||||||
|
|
||||||
return authenticationResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
|
||||||
return OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
|
||||||
Assert.notNull(authoritiesMapper, "authoritiesMapper cannot be null");
|
|
||||||
this.authoritiesMapper = authoritiesMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean userAuthenticated() {
|
|
||||||
Authentication currentAuthentication = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
return currentAuthentication != null &&
|
|
||||||
currentAuthentication instanceof OAuth2UserAuthenticationToken &&
|
|
||||||
currentAuthentication.isAuthenticated();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean userAuthenticatedSameProviderAs(OAuth2ClientAuthenticationToken clientAuthentication) {
|
|
||||||
OAuth2UserAuthenticationToken currentUserAuthentication =
|
|
||||||
(OAuth2UserAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
String userProviderId = this.getProviderIdentifier(
|
|
||||||
currentUserAuthentication.getClientAuthentication().getClientRegistration());
|
|
||||||
String clientProviderId = this.getProviderIdentifier(
|
|
||||||
clientAuthentication.getClientRegistration());
|
|
||||||
|
|
||||||
return userProviderId.equals(clientProviderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getProviderIdentifier(ClientRegistration clientRegistration) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append("[").append(clientRegistration.getProviderDetails().getAuthorizationUri()).append("]");
|
|
||||||
builder.append("[").append(clientRegistration.getProviderDetails().getTokenUri()).append("]");
|
|
||||||
builder.append("[").append(clientRegistration.getProviderDetails().getUserInfoEndpoint().getUri()).append("]");
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@ import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProvider;
|
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProvider;
|
||||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
|
@ -128,10 +127,7 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce
|
||||||
clientRegistration, new AuthorizationExchange(authorizationRequest, authorizationResponse));
|
clientRegistration, new AuthorizationExchange(authorizationRequest, authorizationResponse));
|
||||||
authorizationCodeAuthentication.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
authorizationCodeAuthentication.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||||
|
|
||||||
OAuth2ClientAuthenticationToken clientAuthentication =
|
return this.getAuthenticationManager().authenticate(authorizationCodeAuthentication);
|
||||||
(OAuth2ClientAuthenticationToken)this.getAuthenticationManager().authenticate(authorizationCodeAuthentication);
|
|
||||||
|
|
||||||
return this.getAuthenticationManager().authenticate(clientAuthentication);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setClientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
|
public final void setClientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
|
||||||
|
|
|
@ -18,10 +18,14 @@ package org.springframework.security.oauth2.oidc.client.authentication;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.authentication.AuthorizationGrantTokenExchanger;
|
import org.springframework.security.oauth2.client.authentication.AuthorizationGrantTokenExchanger;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.client.authentication.jwt.JwtDecoderRegistry;
|
import org.springframework.security.oauth2.client.authentication.jwt.JwtDecoderRegistry;
|
||||||
|
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2AuthenticationToken;
|
||||||
|
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserService;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.client.token.InMemoryAccessTokenRepository;
|
import org.springframework.security.oauth2.client.token.InMemoryAccessTokenRepository;
|
||||||
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
|
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
|
||||||
|
@ -30,26 +34,37 @@ import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.core.endpoint.AuthorizationResponse;
|
import org.springframework.security.oauth2.core.endpoint.AuthorizationResponse;
|
||||||
import org.springframework.security.oauth2.core.endpoint.TokenResponse;
|
import org.springframework.security.oauth2.core.endpoint.TokenResponse;
|
||||||
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
|
import org.springframework.security.oauth2.oidc.client.authentication.userinfo.OidcUserService;
|
||||||
import org.springframework.security.oauth2.oidc.core.IdToken;
|
import org.springframework.security.oauth2.oidc.core.IdToken;
|
||||||
import org.springframework.security.oauth2.oidc.core.OidcScope;
|
import org.springframework.security.oauth2.oidc.core.OidcScope;
|
||||||
import org.springframework.security.oauth2.oidc.core.endpoint.OidcParameter;
|
import org.springframework.security.oauth2.oidc.core.endpoint.OidcParameter;
|
||||||
|
import org.springframework.security.oauth2.oidc.core.user.OidcUser;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of an {@link AuthenticationProvider}
|
* An implementation of an {@link AuthenticationProvider}
|
||||||
* for the <i>OpenID Connect Core 1.0 Authorization Code Grant Flow</i>.
|
* for the <i>OpenID Connect Core 1.0 Authorization Code Grant Flow</i>.
|
||||||
*
|
* <p>
|
||||||
* This {@link AuthenticationProvider} is responsible for authenticating
|
* This {@link AuthenticationProvider} is responsible for authenticating
|
||||||
* an <i>authorization code</i> credential with the authorization server's <i>Token Endpoint</i>
|
* an <i>authorization code</i> credential with the authorization server's <i>Token Endpoint</i>
|
||||||
* and if valid, exchanging it for an <i>access token</i> credential.
|
* and if valid, exchanging it for an <i>access token</i> credential.
|
||||||
|
* <p>
|
||||||
|
* It will also obtain the user attributes of the <i>End-User</i> (resource owner)
|
||||||
|
* from the <i>UserInfo Endpoint</i> using an {@link OAuth2UserService}
|
||||||
|
* which will create a <code>Principal</code> in the form of an {@link OidcUser}.
|
||||||
*
|
*
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see AuthorizationCodeAuthenticationToken
|
* @see AuthorizationCodeAuthenticationToken
|
||||||
* @see OidcClientAuthenticationToken
|
|
||||||
* @see SecurityTokenRepository
|
* @see SecurityTokenRepository
|
||||||
|
* @see OidcClientAuthenticationToken
|
||||||
|
* @see OidcUserService
|
||||||
|
* @see OidcUser
|
||||||
* @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">Section 3.1 Authorization Code Grant Flow</a>
|
* @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">Section 3.1 Authorization Code Grant Flow</a>
|
||||||
* @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#TokenRequest">Section 3.1.3.1 Token Request</a>
|
* @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#TokenRequest">Section 3.1.3.1 Token Request</a>
|
||||||
* @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse">Section 3.1.3.3 Token Response</a>
|
* @see <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse">Section 3.1.3.3 Token Response</a>
|
||||||
|
@ -58,16 +73,21 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
|
||||||
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
|
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 static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
|
||||||
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
||||||
|
private final OAuth2UserService userService;
|
||||||
private final JwtDecoderRegistry jwtDecoderRegistry;
|
private final JwtDecoderRegistry jwtDecoderRegistry;
|
||||||
private SecurityTokenRepository<AccessToken> accessTokenRepository = new InMemoryAccessTokenRepository();
|
private SecurityTokenRepository<AccessToken> accessTokenRepository = new InMemoryAccessTokenRepository();
|
||||||
|
private GrantedAuthoritiesMapper authoritiesMapper = (authorities -> authorities);
|
||||||
|
|
||||||
public OidcAuthorizationCodeAuthenticationProvider(
|
public OidcAuthorizationCodeAuthenticationProvider(
|
||||||
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger,
|
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger,
|
||||||
|
OAuth2UserService userService,
|
||||||
JwtDecoderRegistry jwtDecoderRegistry) {
|
JwtDecoderRegistry jwtDecoderRegistry) {
|
||||||
|
|
||||||
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
|
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
|
||||||
|
Assert.notNull(userService, "userService cannot be null");
|
||||||
Assert.notNull(jwtDecoderRegistry, "jwtDecoderRegistry cannot be null");
|
Assert.notNull(jwtDecoderRegistry, "jwtDecoderRegistry cannot be null");
|
||||||
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
|
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
|
||||||
|
this.userService = userService;
|
||||||
this.jwtDecoderRegistry = jwtDecoderRegistry;
|
this.jwtDecoderRegistry = jwtDecoderRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +156,16 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
|
||||||
clientAuthentication.getAccessToken(),
|
clientAuthentication.getAccessToken(),
|
||||||
clientAuthentication.getClientRegistration());
|
clientAuthentication.getClientRegistration());
|
||||||
|
|
||||||
return clientAuthentication;
|
OAuth2User oauth2User = this.userService.loadUser(clientAuthentication);
|
||||||
|
|
||||||
|
Collection<? extends GrantedAuthority> mappedAuthorities =
|
||||||
|
this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
|
||||||
|
|
||||||
|
OAuth2AuthenticationToken authenticationResult = new OAuth2AuthenticationToken(
|
||||||
|
oauth2User, mappedAuthorities, clientAuthentication);
|
||||||
|
authenticationResult.setDetails(clientAuthentication.getDetails());
|
||||||
|
|
||||||
|
return authenticationResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setAccessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
|
public final void setAccessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
|
||||||
|
@ -144,6 +173,11 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
|
||||||
this.accessTokenRepository = accessTokenRepository;
|
this.accessTokenRepository = accessTokenRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||||
|
Assert.notNull(authoritiesMapper, "authoritiesMapper cannot be null");
|
||||||
|
this.authoritiesMapper = authoritiesMapper;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(Class<?> authentication) {
|
public boolean supports(Class<?> authentication) {
|
||||||
return AuthorizationCodeAuthenticationToken.class.isAssignableFrom(authentication);
|
return AuthorizationCodeAuthenticationToken.class.isAssignableFrom(authentication);
|
||||||
|
|
|
@ -1,46 +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.oauth2.oidc.client.authentication;
|
|
||||||
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.oidc.core.user.OidcUser;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link OAuth2UserAuthenticationToken} that represents an
|
|
||||||
* <i>OpenID Connect 1.0 User</i> {@link Authentication}.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This {@link Authentication} associates an {@link OidcUser} principal to an
|
|
||||||
* {@link OidcClientAuthenticationToken} which represents the <i>"Authorized Client"</i>.
|
|
||||||
*
|
|
||||||
* @author Joe Grandja
|
|
||||||
* @since 5.0
|
|
||||||
* @see OidcUser
|
|
||||||
* @see OidcClientAuthenticationToken
|
|
||||||
* @see OAuth2UserAuthenticationToken
|
|
||||||
*/
|
|
||||||
public class OidcUserAuthenticationToken extends OAuth2UserAuthenticationToken {
|
|
||||||
|
|
||||||
public OidcUserAuthenticationToken(OidcUser principal, Collection<? extends GrantedAuthority> authorities,
|
|
||||||
OidcClientAuthenticationToken clientAuthentication) {
|
|
||||||
super(principal, authorities, clientAuthentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,104 +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.oauth2.oidc.client.authentication.userinfo;
|
|
||||||
|
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserService;
|
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
|
||||||
import org.springframework.security.oauth2.oidc.client.authentication.OidcClientAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.oidc.client.authentication.OidcUserAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.oidc.core.user.OidcUser;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of an {@link AuthenticationProvider} that is responsible
|
|
||||||
* for obtaining the user attributes of the <i>End-User</i> (resource owner)
|
|
||||||
* from the <i>UserInfo Endpoint</i> and creating a <code>Principal</code>
|
|
||||||
* in the form of an {@link OidcUser}.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The {@link OidcUserAuthenticationProvider} uses an {@link OidcUserService}
|
|
||||||
* for loading the {@link OidcUser} and then associating it
|
|
||||||
* to the returned {@link OidcUserAuthenticationToken}.
|
|
||||||
*
|
|
||||||
* @author Joe Grandja
|
|
||||||
* @since 5.0
|
|
||||||
* @see OidcUserAuthenticationToken
|
|
||||||
* @see OidcClientAuthenticationToken
|
|
||||||
* @see OidcUserService
|
|
||||||
* @see OidcUser
|
|
||||||
*/
|
|
||||||
public class OidcUserAuthenticationProvider implements AuthenticationProvider {
|
|
||||||
private final OAuth2UserService userService;
|
|
||||||
private GrantedAuthoritiesMapper authoritiesMapper = (authorities -> authorities);
|
|
||||||
|
|
||||||
public OidcUserAuthenticationProvider(OAuth2UserService userService) {
|
|
||||||
Assert.notNull(userService, "userService cannot be null");
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
||||||
OidcClientAuthenticationToken clientAuthentication = (OidcClientAuthenticationToken) authentication;
|
|
||||||
|
|
||||||
if (this.userAuthenticated()) {
|
|
||||||
// Create a new user authentication (using same principal)
|
|
||||||
// but with a different client authentication association
|
|
||||||
OidcUserAuthenticationToken currentUserAuthentication =
|
|
||||||
(OidcUserAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
|
|
||||||
return new OidcUserAuthenticationToken(
|
|
||||||
(OidcUser) currentUserAuthentication.getPrincipal(),
|
|
||||||
currentUserAuthentication.getAuthorities(),
|
|
||||||
clientAuthentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuth2User oauth2User = this.userService.loadUser(clientAuthentication);
|
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> mappedAuthorities =
|
|
||||||
this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
|
|
||||||
|
|
||||||
OidcUserAuthenticationToken authenticationResult = new OidcUserAuthenticationToken(
|
|
||||||
(OidcUser)oauth2User, mappedAuthorities, clientAuthentication);
|
|
||||||
authenticationResult.setDetails(clientAuthentication.getDetails());
|
|
||||||
|
|
||||||
return authenticationResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> authentication) {
|
|
||||||
return OidcClientAuthenticationToken.class.isAssignableFrom(authentication);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
|
||||||
Assert.notNull(authoritiesMapper, "authoritiesMapper cannot be null");
|
|
||||||
this.authoritiesMapper = authoritiesMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean userAuthenticated() {
|
|
||||||
Authentication currentAuthentication = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
return currentAuthentication != null &&
|
|
||||||
currentAuthentication instanceof OidcUserAuthenticationToken &&
|
|
||||||
currentAuthentication.isAuthenticated();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,7 +29,7 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2AuthenticationToken;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||||
import org.springframework.security.oauth2.core.AccessToken;
|
import org.springframework.security.oauth2.core.AccessToken;
|
||||||
|
@ -100,7 +100,7 @@ public class OAuth2LoginAuthenticationFilterTests {
|
||||||
ClientRegistration clientRegistration = TestUtil.githubClientRegistration();
|
ClientRegistration clientRegistration = TestUtil.githubClientRegistration();
|
||||||
OAuth2ClientAuthenticationToken clientAuthentication = new OAuth2ClientAuthenticationToken(
|
OAuth2ClientAuthenticationToken clientAuthentication = new OAuth2ClientAuthenticationToken(
|
||||||
clientRegistration, mock(AccessToken.class));
|
clientRegistration, mock(AccessToken.class));
|
||||||
OAuth2UserAuthenticationToken userAuthentication = new OAuth2UserAuthenticationToken(
|
OAuth2AuthenticationToken userAuthentication = new OAuth2AuthenticationToken(
|
||||||
mock(OAuth2User.class), AuthorityUtils.createAuthorityList("ROLE_USER"), clientAuthentication);
|
mock(OAuth2User.class), AuthorityUtils.createAuthorityList("ROLE_USER"), clientAuthentication);
|
||||||
SecurityContextHolder.getContext().setAuthentication(userAuthentication);
|
SecurityContextHolder.getContext().setAuthentication(userAuthentication);
|
||||||
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
|
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
|
||||||
|
|
|
@ -17,7 +17,7 @@ package sample.web;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserAuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2AuthenticationToken;
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
@ -38,14 +38,14 @@ import java.util.Map;
|
||||||
public class MainController {
|
public class MainController {
|
||||||
|
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
public String index(Model model, @AuthenticationPrincipal OAuth2User user, OAuth2UserAuthenticationToken authentication) {
|
public String index(Model model, @AuthenticationPrincipal OAuth2User user, OAuth2AuthenticationToken authentication) {
|
||||||
model.addAttribute("userName", user.getName());
|
model.addAttribute("userName", user.getName());
|
||||||
model.addAttribute("clientName", authentication.getClientAuthentication().getClientRegistration().getClientName());
|
model.addAttribute("clientName", authentication.getClientAuthentication().getClientRegistration().getClientName());
|
||||||
return "index";
|
return "index";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/userinfo")
|
@RequestMapping("/userinfo")
|
||||||
public String userinfo(Model model, OAuth2UserAuthenticationToken authentication) {
|
public String userinfo(Model model, OAuth2AuthenticationToken authentication) {
|
||||||
Map userAttributes = Collections.emptyMap();
|
Map userAttributes = Collections.emptyMap();
|
||||||
String userInfoEndpointUri = authentication.getClientAuthentication().getClientRegistration()
|
String userInfoEndpointUri = authentication.getClientAuthentication().getClientRegistration()
|
||||||
.getProviderDetails().getUserInfoEndpoint().getUri();
|
.getProviderDetails().getUserInfoEndpoint().getUri();
|
||||||
|
@ -63,7 +63,7 @@ public class MainController {
|
||||||
return "userinfo";
|
return "userinfo";
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExchangeFilterFunction oauth2Credentials(OAuth2UserAuthenticationToken authentication) {
|
private ExchangeFilterFunction oauth2Credentials(OAuth2AuthenticationToken authentication) {
|
||||||
return ExchangeFilterFunction.ofRequestProcessor(
|
return ExchangeFilterFunction.ofRequestProcessor(
|
||||||
clientRequest -> {
|
clientRequest -> {
|
||||||
ClientRequest authorizedRequest = ClientRequest.from(clientRequest)
|
ClientRequest authorizedRequest = ClientRequest.from(clientRequest)
|
||||||
|
|
Loading…
Reference in New Issue