diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java index 1bc63dee9c..8c3cd511f0 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java @@ -36,6 +36,7 @@ import org.springframework.security.oauth2.client.web.AuthorizationRequestReposi 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.oauth2.oidc.client.authentication.userinfo.OidcUserAuthenticationProvider; import org.springframework.security.oauth2.oidc.client.authentication.userinfo.OidcUserService; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.util.matcher.RequestMatcher; @@ -195,19 +196,6 @@ public final class OAuth2LoginConfigurer> exten return this; } - private OAuth2UserService getUserService() { - if (this.userService == null) { - List 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; - } - public OAuth2LoginConfigurer and() { return OAuth2LoginConfigurer.this; } @@ -219,13 +207,35 @@ public final class OAuth2LoginConfigurer> exten this.authorizationCodeGrantConfigurer.setBuilder(http); this.authorizationCodeGrantConfigurer.init(http); + OAuth2UserService userService = this.userInfoEndpointConfig.userService; + if (userService == null) { + if (!this.userInfoEndpointConfig.customUserTypes.isEmpty()) { + List 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(this.userInfoEndpointConfig.getUserService()); + 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); } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProvider.java index 18a7ed3f9a..abb310ea4a 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProvider.java @@ -65,10 +65,9 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr // 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 the openid scope value is not present, the behavior is entirely unspecified. if (authorizationCodeAuthentication.getAuthorizationRequest().getScope().contains("openid")) { - // The OpenID Connect implementation of Authorization Code AuthenticationProvider - // should handle OpenID Connect Authentication Requests so don't handle and return null + // This is an OpenID Connect Authentication Request so return null + // and let OidcAuthorizationCodeAuthenticationProvider handle it instead return null; } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/CustomUserTypesOAuth2UserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/CustomUserTypesOAuth2UserService.java index 5370d10004..78994d2f91 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/CustomUserTypesOAuth2UserService.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/CustomUserTypesOAuth2UserService.java @@ -20,7 +20,6 @@ import org.springframework.beans.PropertyAccessorFactory; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException; import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken; import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.security.oauth2.oidc.client.authentication.OidcClientAuthenticationToken; import org.springframework.util.Assert; import java.net.URI; @@ -70,9 +69,6 @@ public class CustomUserTypesOAuth2UserService implements OAuth2UserService { } Map userAttributes = this.userInfoRetriever.retrieve(clientAuthentication); - if (OidcClientAuthenticationToken.class.isAssignableFrom(clientAuthentication.getClass())) { - userAttributes.putAll(((OidcClientAuthenticationToken)clientAuthentication).getIdToken().getClaims()); - } BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(customUser); wrapper.setAutoGrowNestedPaths(true); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DefaultOAuth2UserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DefaultOAuth2UserService.java index 78abb23172..26457ebdbf 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DefaultOAuth2UserService.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DefaultOAuth2UserService.java @@ -22,7 +22,6 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio import org.springframework.security.oauth2.core.user.DefaultOAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; -import org.springframework.security.oauth2.oidc.client.authentication.OidcClientAuthenticationToken; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -54,10 +53,6 @@ public class DefaultOAuth2UserService implements OAuth2UserService { @Override public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException { - if (OidcClientAuthenticationToken.class.isAssignableFrom(clientAuthentication.getClass())) { - return null; - } - String userNameAttributeName = clientAuthentication.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName(); if (!StringUtils.hasText(userNameAttributeName)) { throw new IllegalArgumentException( diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DelegatingOAuth2UserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DelegatingOAuth2UserService.java index 989c787915..eaa7bb3fe3 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DelegatingOAuth2UserService.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/DelegatingOAuth2UserService.java @@ -20,6 +20,8 @@ import org.springframework.security.oauth2.client.authentication.OAuth2ClientAut import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.util.Assert; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -41,7 +43,7 @@ public class DelegatingOAuth2UserService implements OAuth2UserService { public DelegatingOAuth2UserService(List userServices) { Assert.notEmpty(userServices, "userServices cannot be empty"); - this.userServices = userServices; + this.userServices = Collections.unmodifiableList(new ArrayList<>(userServices)); } @Override diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationProvider.java index 81c340d9e4..0c1fcd1a4b 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationProvider.java @@ -25,10 +25,6 @@ import org.springframework.security.oauth2.client.authentication.OAuth2ClientAut import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationIdentifierStrategy; 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.client.authentication.userinfo.OidcUserService; -import org.springframework.security.oauth2.oidc.core.user.OidcUser; import org.springframework.util.Assert; import java.util.Collection; @@ -47,13 +43,9 @@ import java.util.Collection; * @author Joe Grandja * @since 5.0 * @see OAuth2UserAuthenticationToken - * @see OidcUserAuthenticationToken * @see OAuth2ClientAuthenticationToken - * @see OidcClientAuthenticationToken * @see OAuth2UserService - * @see OidcUserService * @see OAuth2User - * @see OidcUser */ public class OAuth2UserAuthenticationProvider implements AuthenticationProvider { private final ClientRegistrationIdentifierStrategy providerIdentifierStrategy = new ProviderIdentifierStrategy(); @@ -67,14 +59,26 @@ public class OAuth2UserAuthenticationProvider implements AuthenticationProvider @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { - OAuth2UserAuthenticationToken userAuthentication = (OAuth2UserAuthenticationToken) authentication; - OAuth2ClientAuthenticationToken clientAuthentication = userAuthentication.getClientAuthentication(); + 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.getAuthorizedScope().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 - return this.createUserAuthentication( - (OAuth2UserAuthenticationToken)SecurityContextHolder.getContext().getAuthentication(), + OAuth2UserAuthenticationToken currentUserAuthentication = + (OAuth2UserAuthenticationToken)SecurityContextHolder.getContext().getAuthentication(); + + return new OAuth2UserAuthenticationToken( + (OAuth2User)currentUserAuthentication.getPrincipal(), + currentUserAuthentication.getAuthorities(), clientAuthentication); } @@ -83,29 +87,23 @@ public class OAuth2UserAuthenticationProvider implements AuthenticationProvider Collection mappedAuthorities = this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities()); - OAuth2UserAuthenticationToken authenticationResult; - if (OidcUser.class.isAssignableFrom(oauth2User.getClass())) { - authenticationResult = new OidcUserAuthenticationToken( - (OidcUser)oauth2User, mappedAuthorities, (OidcClientAuthenticationToken)clientAuthentication); - } else { - authenticationResult = new OAuth2UserAuthenticationToken( + 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; } - @Override - public boolean supports(Class authentication) { - return OAuth2UserAuthenticationToken.class.isAssignableFrom(authentication); - } - private boolean userAuthenticated() { Authentication currentAuthentication = SecurityContextHolder.getContext().getAuthentication(); return currentAuthentication != null && @@ -125,23 +123,6 @@ public class OAuth2UserAuthenticationProvider implements AuthenticationProvider return userProviderId.equals(clientProviderId); } - private OAuth2UserAuthenticationToken createUserAuthentication( - OAuth2UserAuthenticationToken currentUserAuthentication, - OAuth2ClientAuthenticationToken newClientAuthentication) { - - if (OidcUserAuthenticationToken.class.isAssignableFrom(currentUserAuthentication.getClass())) { - return new OidcUserAuthenticationToken( - (OidcUser) currentUserAuthentication.getPrincipal(), - currentUserAuthentication.getAuthorities(), - newClientAuthentication); - } else { - return new OAuth2UserAuthenticationToken( - (OAuth2User)currentUserAuthentication.getPrincipal(), - currentUserAuthentication.getAuthorities(), - newClientAuthentication); - } - } - private static class ProviderIdentifierStrategy implements ClientRegistrationIdentifierStrategy { @Override diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationToken.java index 7597ec0102..0cd739e7d8 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationToken.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/userinfo/OAuth2UserAuthenticationToken.java @@ -24,7 +24,6 @@ import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.util.Assert; import java.util.Collection; -import java.util.Collections; /** * An implementation of an {@link AbstractAuthenticationToken} @@ -44,10 +43,6 @@ public class OAuth2UserAuthenticationToken extends AbstractAuthenticationToken { private final OAuth2User principal; private final OAuth2ClientAuthenticationToken clientAuthentication; - public OAuth2UserAuthenticationToken(OAuth2ClientAuthenticationToken clientAuthentication) { - this(null, Collections.emptyList(), clientAuthentication); - } - public OAuth2UserAuthenticationToken(OAuth2User principal, Collection authorities, OAuth2ClientAuthenticationToken clientAuthentication) { super(authorities); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthorizationCodeAuthenticationFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthorizationCodeAuthenticationFilter.java index 3b058eb509..d840ad0d7f 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthorizationCodeAuthenticationFilter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthorizationCodeAuthenticationFilter.java @@ -22,7 +22,6 @@ import org.springframework.security.oauth2.client.authentication.AuthorizationCo import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException; import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken; -import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserAuthenticationToken; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.core.OAuth2Error; @@ -129,8 +128,7 @@ public class AuthorizationCodeAuthenticationFilter extends AbstractAuthenticatio OAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken)this.getAuthenticationManager().authenticate(authorizationCodeAuthentication); - return this.getAuthenticationManager().authenticate( - new OAuth2UserAuthenticationToken(clientAuthentication)); + return this.getAuthenticationManager().authenticate(clientAuthentication); } public final RequestMatcher getAuthorizationResponseMatcher() { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizationCodeAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizationCodeAuthenticationProvider.java index 5ecea6a905..7f4e69b0ee 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizationCodeAuthenticationProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcAuthorizationCodeAuthenticationProvider.java @@ -79,9 +79,9 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati // 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 the openid scope value is not present, the behavior is entirely unspecified. if (!authorizationCodeAuthentication.getAuthorizationRequest().getScope().contains(OidcScope.OPENID)) { - // Let the standard OAuth 2.0 Authorization Code AuthenticationProvider handle this + // This is NOT an OpenID Connect Authentication Request so return null + // and let AuthorizationCodeAuthenticationProvider handle it instead return null; } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcUserAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcUserAuthenticationToken.java index c476165fee..47df8bbe13 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcUserAuthenticationToken.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcUserAuthenticationToken.java @@ -17,12 +17,10 @@ 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.OAuth2ClientAuthenticationToken; import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserAuthenticationToken; import org.springframework.security.oauth2.oidc.core.user.OidcUser; import java.util.Collection; -import java.util.Collections; /** * An {@link OAuth2UserAuthenticationToken} that represents an @@ -40,17 +38,9 @@ import java.util.Collections; */ public class OidcUserAuthenticationToken extends OAuth2UserAuthenticationToken { - public OidcUserAuthenticationToken(OidcClientAuthenticationToken clientAuthentication) { - this(null, Collections.emptyList(), clientAuthentication); - } - public OidcUserAuthenticationToken(OidcUser principal, Collection authorities, OidcClientAuthenticationToken clientAuthentication) { - this(principal, authorities, (OAuth2ClientAuthenticationToken)clientAuthentication); - } - - public OidcUserAuthenticationToken(OidcUser principal, Collection authorities, - OAuth2ClientAuthenticationToken clientAuthentication) { super(principal, authorities, clientAuthentication); } + } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserAuthenticationProvider.java new file mode 100644 index 0000000000..525e295f61 --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserAuthenticationProvider.java @@ -0,0 +1,104 @@ +/* + * 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 End-User (resource owner) + * from the UserInfo Endpoint and creating a Principal + * in the form of an {@link OidcUser}. + * + *

+ * 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 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(); + } +} diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserService.java index 27fe626d61..6a0b63c517 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserService.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/userinfo/OidcUserService.java @@ -18,9 +18,9 @@ package org.springframework.security.oauth2.oidc.client.authentication.userinfo; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationException; import org.springframework.security.oauth2.client.authentication.OAuth2ClientAuthenticationToken; +import org.springframework.security.oauth2.client.authentication.userinfo.NimbusUserInfoRetriever; import org.springframework.security.oauth2.client.authentication.userinfo.OAuth2UserService; import org.springframework.security.oauth2.client.authentication.userinfo.UserInfoRetriever; -import org.springframework.security.oauth2.client.authentication.userinfo.NimbusUserInfoRetriever; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.oidc.client.authentication.OidcClientAuthenticationToken; @@ -58,9 +58,6 @@ public class OidcUserService implements OAuth2UserService { @Override public OAuth2User loadUser(OAuth2ClientAuthenticationToken clientAuthentication) throws OAuth2AuthenticationException { - if (!OidcClientAuthenticationToken.class.isAssignableFrom(clientAuthentication.getClass())) { - return null; - } OidcClientAuthenticationToken oidcClientAuthentication = (OidcClientAuthenticationToken)clientAuthentication; UserInfo userInfo = null; diff --git a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java index 1556290b9f..73ca39e275 100644 --- a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java +++ b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java @@ -359,7 +359,6 @@ public class OAuth2LoginApplicationTests { TokenResponse tokenResponse = TokenResponse.withToken("access-token-1234") .tokenType(AccessToken.TokenType.BEARER) .expiresIn(60 * 1000) - .scope(Collections.singleton("openid")) .build(); AuthorizationGrantTokenExchanger mock = mock(AuthorizationGrantTokenExchanger.class);