Add in-memory AccessTokenRepository

Fixes gh-4508
This commit is contained in:
Joe Grandja 2017-08-22 21:59:20 -04:00
parent d6ba348a59
commit bc6be86aec
4 changed files with 106 additions and 1 deletions

View File

@ -31,8 +31,11 @@ import org.springframework.security.oauth2.client.authentication.jwt.ProviderJwt
import org.springframework.security.oauth2.client.authentication.nimbus.NimbusAuthorizationCodeTokenExchanger; import org.springframework.security.oauth2.client.authentication.nimbus.NimbusAuthorizationCodeTokenExchanger;
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.client.token.InMemoryAccessTokenRepository;
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
import org.springframework.security.oauth2.client.user.OAuth2UserService; import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.client.user.nimbus.NimbusOAuth2UserService; import org.springframework.security.oauth2.client.user.nimbus.NimbusOAuth2UserService;
import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.http.HttpClientConfig; import org.springframework.security.oauth2.core.http.HttpClientConfig;
import org.springframework.security.oauth2.core.provider.DefaultProviderMetadata; import org.springframework.security.oauth2.core.provider.DefaultProviderMetadata;
import org.springframework.security.oauth2.core.provider.ProviderMetadata; import org.springframework.security.oauth2.core.provider.ProviderMetadata;
@ -57,6 +60,7 @@ final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecuri
private R authorizationResponseMatcher; private R authorizationResponseMatcher;
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger; private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
private SecurityTokenRepository<AccessToken> accessTokenRepository;
private OAuth2UserService userInfoService; private OAuth2UserService userInfoService;
private Map<URI, Class<? extends OAuth2User>> customUserTypes = new HashMap<>(); private Map<URI, Class<? extends OAuth2User>> customUserTypes = new HashMap<>();
private Map<URI, String> userNameAttributeNames = new HashMap<>(); private Map<URI, String> userNameAttributeNames = new HashMap<>();
@ -80,6 +84,12 @@ final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecuri
return this; return this;
} }
AuthorizationCodeAuthenticationFilterConfigurer<H, R> accessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
Assert.notNull(accessTokenRepository, "accessTokenRepository cannot be null");
this.accessTokenRepository = accessTokenRepository;
return this;
}
AuthorizationCodeAuthenticationFilterConfigurer<H, R> userInfoService(OAuth2UserService userInfoService) { AuthorizationCodeAuthenticationFilterConfigurer<H, R> userInfoService(OAuth2UserService userInfoService) {
Assert.notNull(userInfoService, "userInfoService cannot be null"); Assert.notNull(userInfoService, "userInfoService cannot be null");
this.userInfoService = userInfoService; this.userInfoService = userInfoService;
@ -124,7 +134,8 @@ final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecuri
@Override @Override
public void init(H http) throws Exception { public void init(H http) throws Exception {
AuthorizationCodeAuthenticationProvider authenticationProvider = new AuthorizationCodeAuthenticationProvider( AuthorizationCodeAuthenticationProvider authenticationProvider = new AuthorizationCodeAuthenticationProvider(
this.getAuthorizationCodeTokenExchanger(http), this.getProviderJwtDecoderRegistry(http), this.getUserInfoService(http)); this.getAuthorizationCodeTokenExchanger(http), this.getAccessTokenRepository(),
this.getProviderJwtDecoderRegistry(http), this.getUserInfoService(http));
if (this.userAuthoritiesMapper != null) { if (this.userAuthoritiesMapper != null) {
authenticationProvider.setAuthoritiesMapper(this.userAuthoritiesMapper); authenticationProvider.setAuthoritiesMapper(this.userAuthoritiesMapper);
} }
@ -161,6 +172,13 @@ final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecuri
return this.authorizationCodeTokenExchanger; return this.authorizationCodeTokenExchanger;
} }
private SecurityTokenRepository<AccessToken> getAccessTokenRepository() {
if (this.accessTokenRepository == null) {
this.accessTokenRepository = new InMemoryAccessTokenRepository();
}
return this.accessTokenRepository;
}
private ProviderJwtDecoderRegistry getProviderJwtDecoderRegistry(H http) { private ProviderJwtDecoderRegistry getProviderJwtDecoderRegistry(H http) {
HttpClientConfig httpClientConfig = this.getHttpClientConfig(http); HttpClientConfig httpClientConfig = this.getHttpClientConfig(http);
Map<ProviderMetadata, JwtDecoder> jwtDecoders = new HashMap<>(); Map<ProviderMetadata, JwtDecoder> jwtDecoders = new HashMap<>();

View File

@ -26,7 +26,9 @@ import org.springframework.security.oauth2.client.authentication.AuthorizationRe
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.client.registration.InMemoryClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
import org.springframework.security.oauth2.client.user.OAuth2UserService; import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
@ -139,6 +141,12 @@ public final class OAuth2LoginConfigurer<H extends HttpSecurityBuilder<H>> exten
return this; return this;
} }
public TokenEndpointConfig accessTokenRepository(SecurityTokenRepository<AccessToken> accessTokenRepository) {
Assert.notNull(accessTokenRepository, "accessTokenRepository cannot be null");
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.accessTokenRepository(accessTokenRepository);
return this;
}
public OAuth2LoginConfigurer<H> and() { public OAuth2LoginConfigurer<H> and() {
return OAuth2LoginConfigurer.this; return OAuth2LoginConfigurer.this;
} }

View File

@ -26,6 +26,7 @@ import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtDecoder; import org.springframework.security.jwt.JwtDecoder;
import org.springframework.security.oauth2.client.authentication.jwt.ProviderJwtDecoderRegistry; import org.springframework.security.oauth2.client.authentication.jwt.ProviderJwtDecoderRegistry;
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.token.SecurityTokenRepository;
import org.springframework.security.oauth2.client.user.OAuth2UserService; import org.springframework.security.oauth2.client.user.OAuth2UserService;
import org.springframework.security.oauth2.core.AccessToken; import org.springframework.security.oauth2.core.AccessToken;
import org.springframework.security.oauth2.core.endpoint.TokenResponseAttributes; import org.springframework.security.oauth2.core.endpoint.TokenResponseAttributes;
@ -79,19 +80,23 @@ import java.util.Collection;
*/ */
public class AuthorizationCodeAuthenticationProvider implements AuthenticationProvider { public class AuthorizationCodeAuthenticationProvider implements AuthenticationProvider {
private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger; private final AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
private final SecurityTokenRepository<AccessToken> accessTokenRepository;
private final ProviderJwtDecoderRegistry providerJwtDecoderRegistry; private final ProviderJwtDecoderRegistry providerJwtDecoderRegistry;
private final OAuth2UserService userInfoService; private final OAuth2UserService userInfoService;
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
public AuthorizationCodeAuthenticationProvider( public AuthorizationCodeAuthenticationProvider(
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger, AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger,
SecurityTokenRepository<AccessToken> accessTokenRepository,
ProviderJwtDecoderRegistry providerJwtDecoderRegistry, ProviderJwtDecoderRegistry providerJwtDecoderRegistry,
OAuth2UserService userInfoService) { OAuth2UserService userInfoService) {
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null"); Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
Assert.notNull(accessTokenRepository, "accessTokenRepository cannot be null");
Assert.notNull(providerJwtDecoderRegistry, "providerJwtDecoderRegistry cannot be null"); Assert.notNull(providerJwtDecoderRegistry, "providerJwtDecoderRegistry cannot be null");
Assert.notNull(userInfoService, "userInfoService cannot be null"); Assert.notNull(userInfoService, "userInfoService cannot be null");
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger; this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
this.accessTokenRepository = accessTokenRepository;
this.providerJwtDecoderRegistry = providerJwtDecoderRegistry; this.providerJwtDecoderRegistry = providerJwtDecoderRegistry;
this.userInfoService = userInfoService; this.userInfoService = userInfoService;
} }
@ -134,6 +139,8 @@ public class AuthorizationCodeAuthenticationProvider implements AuthenticationPr
accessTokenAuthentication.getAccessToken(), accessTokenAuthentication.getIdToken()); accessTokenAuthentication.getAccessToken(), accessTokenAuthentication.getIdToken());
authenticationResult.setDetails(accessTokenAuthentication.getDetails()); authenticationResult.setDetails(accessTokenAuthentication.getDetails());
this.accessTokenRepository.saveSecurityToken(accessToken, authenticationResult);
return authenticationResult; return authenticationResult;
} }

View File

@ -0,0 +1,72 @@
/*
* 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.token;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
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.HashMap;
import java.util.Map;
/**
* A basic implementation of a {@link SecurityTokenRepository}
* that stores {@link AccessToken}(s) <i>in-memory</i>.
*
* @author Joe Grandja
* @since 5.0
* @see SecurityTokenRepository
* @see AccessToken
*/
public final class InMemoryAccessTokenRepository implements SecurityTokenRepository<AccessToken> {
private final Map<String, AccessToken> accessTokens = new HashMap<>();
@Override
public AccessToken loadSecurityToken(OAuth2AuthenticationToken authentication) {
Assert.notNull(authentication, "authentication cannot be null");
return this.accessTokens.get(this.resolveAuthenticationKey(authentication));
}
@Override
public void saveSecurityToken(AccessToken accessToken, OAuth2AuthenticationToken authentication) {
Assert.notNull(accessToken, "accessToken cannot be null");
Assert.notNull(authentication, "authentication cannot be null");
this.accessTokens.put(this.resolveAuthenticationKey(authentication), accessToken);
}
@Override
public void removeSecurityToken(OAuth2AuthenticationToken authentication) {
Assert.notNull(authentication, "authentication cannot be null");
this.accessTokens.remove(this.resolveAuthenticationKey(authentication));
}
private String resolveAuthenticationKey(OAuth2AuthenticationToken authentication) {
String authenticationKey;
OAuth2User oauth2User = (OAuth2User) authentication.getPrincipal();
if (OidcUser.class.isAssignableFrom(oauth2User.getClass())) {
OidcUser oidcUser = (OidcUser)oauth2User;
authenticationKey = oidcUser.getIssuer().toString() + "-" + oidcUser.getSubject();
} else {
authenticationKey = authentication.getClientRegistration().getProviderDetails().getUserInfoUri() +
"-" + oauth2User.getName();
}
return authenticationKey;
}
}