2
0
Эх сурвалжийг харах

Add OIDC Client and User Authentication

Fixes gh-4521
Joe Grandja 8 жил өмнө
parent
commit
991a154703

+ 18 - 4
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 <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="http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">Section 3.1 OpenID Connect Authorization Code 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>
@@ -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<? extends GrantedAuthority> 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);

+ 1 - 11
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 <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-5.1">Section 5.1 Access Token Response</a>
  */
 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;
-	}
 }

+ 2 - 2
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 <i>OAuth 2.0 User</i> {@link Authentication}.
  *
  * <p>
- * This {@link Authentication} associates an {@link OAuth2User} principal
- * to an <i>&quot;Authorized Client&quot;</i> identified in {@link #getClientAuthentication()}.
+ * This {@link Authentication} associates an {@link OAuth2User} principal to a
+ * {@link OAuth2ClientAuthenticationToken} which represents the <i>&quot;Authorized Client&quot;</i>.
  *
  * @author Joe Grandja
  * @since 5.0

+ 7 - 6
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<String, Object> userAttributes = this.getUserInfo(token);
 		UserInfo userInfo = new UserInfo(userAttributes);
@@ -135,10 +137,9 @@ public class NimbusOAuth2UserService implements OAuth2UserService {
 		}
 
 		Map<String, Object> 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);

+ 56 - 0
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
+ * <i>OpenID Connect 1.0 Client</i> {@link Authentication} (also known as <i>Relying Party</i>).
+ *
+ * <p>
+ * A client is considered <i>&quot;authenticated&quot;</i>,
+ * if it receives a successful response from the <i>Token Endpoint</i>.
+ * 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 <a target="_blank" href="http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse">3.1.3.3 Successful Token Response</a>
+ */
+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;
+	}
+}

+ 45 - 0
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
+ * <i>OpenID Connect 1.0 User</i> {@link Authentication}.
+ *
+ * <p>
+ * This {@link Authentication} associates an {@link OidcUser} principal to a
+ * {@link OidcClientAuthenticationToken} which represents the <i>&quot;Authorized Client&quot;</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);
+	}
+}