Răsfoiți Sursa

SecurityTokenRepository associates SecurityToken to ClientRegistration

Fixes gh-4563
Joe Grandja 8 ani în urmă
părinte
comite
680984c242

+ 1 - 1
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AuthorizationCodeAuthenticationProvider.java

@@ -155,7 +155,7 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr
 		}
 		oauth2UserAuthentication.setDetails(oauth2ClientAuthentication.getDetails());
 
-		this.accessTokenRepository.saveSecurityToken(accessToken, oauth2UserAuthentication);
+		this.accessTokenRepository.saveSecurityToken(accessToken, clientRegistration);
 
 		return oauth2UserAuthentication;
 	}

+ 40 - 25
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/token/InMemoryAccessTokenRepository.java

@@ -15,58 +15,73 @@
  */
 package org.springframework.security.oauth2.client.token;
 
-import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.client.registration.ClientRegistrationIdentifierStrategy;
 import org.springframework.security.oauth2.core.AccessToken;
-import org.springframework.security.oauth2.core.user.OAuth2User;
-import org.springframework.security.oauth2.oidc.core.user.OidcUser;
 import org.springframework.util.Assert;
 
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.Map;
 
 /**
- * A basic implementation of a {@link SecurityTokenRepository}
- * that stores {@link AccessToken}(s) <i>in-memory</i>.
+ * A {@link SecurityTokenRepository} that associates an {@link AccessToken}
+ * to a {@link ClientRegistration Client} and stores it <i>in-memory</i>.
  *
  * @author Joe Grandja
  * @since 5.0
  * @see SecurityTokenRepository
  * @see AccessToken
+ * @see ClientRegistration
  */
 public final class InMemoryAccessTokenRepository implements SecurityTokenRepository<AccessToken> {
+	private final ClientRegistrationIdentifierStrategy<String> identifierStrategy = new AuthorizedClientIdentifierStrategy();
 	private final Map<String, AccessToken> accessTokens = new HashMap<>();
 
 	@Override
-	public AccessToken loadSecurityToken(OAuth2UserAuthenticationToken authentication) {
-		Assert.notNull(authentication, "authentication cannot be null");
-		return this.accessTokens.get(this.resolveAuthenticationKey(authentication));
+	public AccessToken loadSecurityToken(ClientRegistration registration) {
+		Assert.notNull(registration, "registration cannot be null");
+		return this.accessTokens.get(this.identifierStrategy.getIdentifier(registration));
 	}
 
 	@Override
-	public void saveSecurityToken(AccessToken accessToken, OAuth2UserAuthenticationToken authentication) {
+	public void saveSecurityToken(AccessToken accessToken, ClientRegistration registration) {
 		Assert.notNull(accessToken, "accessToken cannot be null");
-		Assert.notNull(authentication, "authentication cannot be null");
-		this.accessTokens.put(this.resolveAuthenticationKey(authentication), accessToken);
+		Assert.notNull(registration, "registration cannot be null");
+		this.accessTokens.put(this.identifierStrategy.getIdentifier(registration), accessToken);
 	}
 
 	@Override
-	public void removeSecurityToken(OAuth2UserAuthenticationToken authentication) {
-		Assert.notNull(authentication, "authentication cannot be null");
-		this.accessTokens.remove(this.resolveAuthenticationKey(authentication));
+	public void removeSecurityToken(ClientRegistration registration) {
+		Assert.notNull(registration, "registration cannot be null");
+		this.accessTokens.remove(this.identifierStrategy.getIdentifier(registration));
 	}
 
-	private String resolveAuthenticationKey(OAuth2UserAuthenticationToken authentication) {
-		String authenticationKey;
+	/**
+	 * A client is considered <i>&quot;authorized&quot;</i>, if it receives a successful response from the <i>Token Endpoint</i>.
+	 *
+	 * @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-5.1">Section 5.1 Access Token Response</a>
+	 */
+	private static class AuthorizedClientIdentifierStrategy implements ClientRegistrationIdentifierStrategy<String> {
 
-		OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal();
-		if (OidcUser.class.isAssignableFrom(oauth2User.getClass())) {
-			OidcUser oidcUser = (OidcUser)oauth2User;
-			authenticationKey = oidcUser.getIssuer().toString() + "-" + oidcUser.getSubject();
-		} else {
-			authenticationKey = authentication.getClientAuthentication().getClientRegistration()
-				.getProviderDetails().getUserInfoUri() + "-" +  oauth2User.getName();
-		}
+		@Override
+		public String getIdentifier(ClientRegistration clientRegistration) {
+			StringBuilder builder = new StringBuilder();
+
+			// Access Token Request attributes
+			builder.append("[").append(clientRegistration.getAuthorizationGrantType().getValue()).append("]");
+			builder.append("[").append(clientRegistration.getRedirectUri()).append("]");
+			builder.append("[").append(clientRegistration.getClientId()).append("]");
+
+			// Access Token Response attributes
+			builder.append("[").append(clientRegistration.getScope().toString()).append("]");
 
-		return authenticationKey;
+			// Client alias is unique as well
+			builder.append("[").append(clientRegistration.getClientAlias()).append("]");
+
+			return Base64.getEncoder().encodeToString(builder.toString().getBytes());
+		}
 	}
 }
+

+ 8 - 5
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/token/SecurityTokenRepository.java

@@ -15,22 +15,25 @@
  */
 package org.springframework.security.oauth2.client.token;
 
-import org.springframework.security.oauth2.client.authentication.OAuth2UserAuthenticationToken;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
 import org.springframework.security.oauth2.core.SecurityToken;
 
 /**
  * Implementations of this interface are responsible for the persistence
- * of {@link SecurityToken}(s) that are associated to an {@link OAuth2UserAuthenticationToken}.
+ * and association of an OAuth 2.0 / OpenID Connect 1.0
+ * {@link SecurityToken} to a {@link ClientRegistration Client}.
  *
  * @author Joe Grandja
  * @since 5.0
+ * @see SecurityToken
+ * @see ClientRegistration
  */
 public interface SecurityTokenRepository<T extends SecurityToken> {
 
-	T loadSecurityToken(OAuth2UserAuthenticationToken authentication);
+	T loadSecurityToken(ClientRegistration registration);
 
-	void saveSecurityToken(T securityToken, OAuth2UserAuthenticationToken authentication);
+	void saveSecurityToken(T securityToken, ClientRegistration registration);
 
-	void removeSecurityToken(OAuth2UserAuthenticationToken authentication);
+	void removeSecurityToken(ClientRegistration registration);
 
 }