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 e5d6a3095f..b4b53811fd 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 @@ -32,8 +32,11 @@ import org.springframework.security.oauth2.client.web.AuthorizationGrantTokenExc import org.springframework.security.oauth2.core.AccessToken; import org.springframework.security.oauth2.core.endpoint.TokenResponseAttributes; 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.IdToken; import org.springframework.security.oauth2.oidc.core.endpoint.OidcParameter; +import org.springframework.security.oauth2.oidc.core.user.OidcUser; import org.springframework.util.Assert; import java.util.Collection; @@ -68,6 +71,7 @@ import java.util.Collection; * @since 5.0 * @see AuthorizationCodeAuthenticationToken * @see OAuth2ClientAuthenticationToken + * @see OidcClientAuthenticationToken * @see OAuth2UserAuthenticationToken * @see AuthorizationGrantTokenExchanger * @see TokenResponseAttributes @@ -75,6 +79,7 @@ import java.util.Collection; * @see IdToken * @see OAuth2UserService * @see OAuth2User + * @see OidcUser * @see Section 4.1 Authorization Code Grant Flow * @see Section 3.1 OpenID Connect Authorization Code Flow * @see Section 4.1.3 Access Token Request @@ -128,8 +133,12 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr idToken = new IdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims()); } - OAuth2ClientAuthenticationToken oauth2ClientAuthentication = - new OAuth2ClientAuthenticationToken(clientRegistration, accessToken, idToken); + OAuth2ClientAuthenticationToken oauth2ClientAuthentication; + if (idToken != null) { + oauth2ClientAuthentication = new OidcClientAuthenticationToken(clientRegistration, accessToken, idToken); + } else { + oauth2ClientAuthentication = new OAuth2ClientAuthenticationToken(clientRegistration, accessToken); + } oauth2ClientAuthentication.setDetails(authorizationCodeAuthentication.getDetails()); OAuth2User user = this.userInfoService.loadUser(oauth2ClientAuthentication); @@ -137,8 +146,13 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr Collection authorities = this.authoritiesMapper.mapAuthorities(user.getAuthorities()); - OAuth2UserAuthenticationToken oauth2UserAuthentication = - new OAuth2UserAuthenticationToken(user, authorities, oauth2ClientAuthentication); + OAuth2UserAuthenticationToken oauth2UserAuthentication; + if (OidcUser.class.isAssignableFrom(user.getClass())) { + oauth2UserAuthentication = new OidcUserAuthenticationToken( + (OidcUser)user, authorities, (OidcClientAuthenticationToken)oauth2ClientAuthentication); + } else { + oauth2UserAuthentication = new OAuth2UserAuthenticationToken(user, authorities, oauth2ClientAuthentication); + } oauth2UserAuthentication.setDetails(oauth2ClientAuthentication.getDetails()); this.accessTokenRepository.saveSecurityToken(accessToken, oauth2UserAuthentication); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2ClientAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2ClientAuthenticationToken.java index 25a10f7574..6cf0dd8bc5 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2ClientAuthenticationToken.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2ClientAuthenticationToken.java @@ -21,7 +21,6 @@ import org.springframework.security.core.SpringSecurityCoreVersion; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.core.AccessToken; -import org.springframework.security.oauth2.oidc.core.IdToken; import org.springframework.util.Assert; /** @@ -38,24 +37,19 @@ import org.springframework.util.Assert; * @since 5.0 * @see ClientRegistration * @see AccessToken - * @see IdToken * @see Section 5.1 Access Token Response */ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private final ClientRegistration clientRegistration; private final AccessToken accessToken; - private final IdToken idToken; - - public OAuth2ClientAuthenticationToken(ClientRegistration clientRegistration, - AccessToken accessToken, IdToken idToken) { + public OAuth2ClientAuthenticationToken(ClientRegistration clientRegistration, AccessToken accessToken) { super(AuthorityUtils.NO_AUTHORITIES); Assert.notNull(clientRegistration, "clientRegistration cannot be null"); Assert.notNull(accessToken, "accessToken cannot be null"); this.clientRegistration = clientRegistration; this.accessToken = accessToken; - this.idToken = idToken; this.setAuthenticated(true); // The Client is authenticated by the Authorization Server } @@ -76,8 +70,4 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken public AccessToken getAccessToken() { return this.accessToken; } - - public IdToken getIdToken() { - return this.idToken; - } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2UserAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2UserAuthenticationToken.java index 75e2cc40ef..92ae66009c 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2UserAuthenticationToken.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2UserAuthenticationToken.java @@ -29,8 +29,8 @@ import java.util.Collection; * that represents an OAuth 2.0 User {@link Authentication}. * *

- * This {@link Authentication} associates an {@link OAuth2User} principal - * to an "Authorized Client" identified in {@link #getClientAuthentication()}. + * This {@link Authentication} associates an {@link OAuth2User} principal to a + * {@link OAuth2ClientAuthenticationToken} which represents the "Authorized Client". * * @author Joe Grandja * @since 5.0 diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/user/web/nimbus/NimbusOAuth2UserService.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/user/web/nimbus/NimbusOAuth2UserService.java index 47647831e4..7c7bf400a9 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/user/web/nimbus/NimbusOAuth2UserService.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/user/web/nimbus/NimbusOAuth2UserService.java @@ -36,6 +36,7 @@ import org.springframework.security.oauth2.core.OAuth2Error; 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.security.oauth2.oidc.core.UserInfo; import org.springframework.security.oauth2.oidc.core.user.DefaultOidcUser; import org.springframework.security.oauth2.oidc.core.user.OidcUser; @@ -65,6 +66,7 @@ import java.util.Set; * @author Joe Grandja * @since 5.0 * @see OAuth2ClientAuthenticationToken + * @see OidcClientAuthenticationToken * @see OAuth2User * @see OidcUser * @see UserInfo @@ -86,14 +88,14 @@ public class NimbusOAuth2UserService implements OAuth2UserService { if (this.getCustomUserTypes().containsKey(userInfoUri)) { return this.loadCustomUser(token); } - if (token.getIdToken() != null) { - return this.loadOidcUser(token); + if (OidcClientAuthenticationToken.class.isAssignableFrom(token.getClass())) { + return this.loadOidcUser((OidcClientAuthenticationToken)token); } return this.loadOAuth2User(token); } - protected OAuth2User loadOidcUser(OAuth2ClientAuthenticationToken token) throws OAuth2AuthenticationException { + protected OidcUser loadOidcUser(OidcClientAuthenticationToken token) throws OAuth2AuthenticationException { // TODO Retrieving the UserInfo should be optional. Need to add the capability for opting in/out Map userAttributes = this.getUserInfo(token); UserInfo userInfo = new UserInfo(userAttributes); @@ -135,10 +137,9 @@ public class NimbusOAuth2UserService implements OAuth2UserService { } Map userAttributes = this.getUserInfo(token); - if (token.getIdToken() != null) { - userAttributes.putAll(token.getIdToken().getClaims()); + if (OidcClientAuthenticationToken.class.isAssignableFrom(token.getClass())) { + userAttributes.putAll(((OidcClientAuthenticationToken)token).getIdToken().getClaims()); } - BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(user); wrapper.setAutoGrowNestedPaths(true); wrapper.setPropertyValues(userAttributes); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcClientAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcClientAuthenticationToken.java new file mode 100644 index 0000000000..57c704dec6 --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcClientAuthenticationToken.java @@ -0,0 +1,56 @@ +/* + * 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.oauth2.client.authentication.OAuth2ClientAuthenticationToken; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.core.AccessToken; +import org.springframework.security.oauth2.oidc.core.IdToken; +import org.springframework.util.Assert; + +/** + * A {@link OAuth2ClientAuthenticationToken} that represents an + * OpenID Connect 1.0 Client {@link Authentication} (also known as Relying Party). + * + *

+ * A client is considered "authenticated", + * if it receives a successful response from the Token Endpoint. + * This {@link Authentication} associates the client identified in {@link #getClientRegistration()} + * to the {@link #getAccessToken()} granted by the resource owner along with the {@link #getIdToken()} + * containing Claims about the authentication of the End-User. + * + * @author Joe Grandja + * @since 5.0 + * @see IdToken + * @see OAuth2ClientAuthenticationToken + * @see 3.1.3.3 Successful Token Response + */ +public class OidcClientAuthenticationToken extends OAuth2ClientAuthenticationToken { + private final IdToken idToken; + + public OidcClientAuthenticationToken(ClientRegistration clientRegistration, + AccessToken accessToken, IdToken idToken) { + + super(clientRegistration, accessToken); + Assert.notNull(idToken, "idToken cannot be null"); + this.idToken = idToken; + } + + public IdToken getIdToken() { + return this.idToken; + } +} 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 new file mode 100644 index 0000000000..df98aca977 --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/oidc/client/authentication/OidcUserAuthenticationToken.java @@ -0,0 +1,45 @@ +/* + * 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.OAuth2UserAuthenticationToken; +import org.springframework.security.oauth2.oidc.core.user.OidcUser; + +import java.util.Collection; + +/** + * A {@link OAuth2UserAuthenticationToken} that represents an + * OpenID Connect 1.0 User {@link Authentication}. + * + *

+ * This {@link Authentication} associates an {@link OidcUser} principal to a + * {@link OidcClientAuthenticationToken} which represents the "Authorized Client". + * + * @author Joe Grandja + * @since 5.0 + * @see OidcUser + * @see OidcClientAuthenticationToken + * @see OAuth2UserAuthenticationToken + */ +public class OidcUserAuthenticationToken extends OAuth2UserAuthenticationToken { + + public OidcUserAuthenticationToken(OidcUser principal, Collection authorities, + OidcClientAuthenticationToken clientAuthentication) { + super(principal, authorities, clientAuthentication); + } +}