Skip to content
Permalink
ec215f79f4
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
578 lines (485 sloc) 20.6 KB
/*
* Copyright 2002-2013 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.config.annotation.web.configurers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.ProxyCreator;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.OAuth2RequestValidator;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
import org.springframework.security.oauth2.provider.client.InMemoryClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* Configure the properties and enhanced functionality of the Authorization Server endpoints.
*
* @author Rob Winch
* @author Dave Syer
* @since 2.0
*/
public final class AuthorizationServerEndpointsConfigurer {
private AuthorizationServerTokenServices tokenServices;
private ConsumerTokenServices consumerTokenServices;
private AuthorizationCodeServices authorizationCodeServices;
private ResourceServerTokenServices resourceTokenServices;
private TokenStore tokenStore;
private TokenEnhancer tokenEnhancer;
private AccessTokenConverter accessTokenConverter;
private ApprovalStore approvalStore;
private TokenGranter tokenGranter;
private OAuth2RequestFactory requestFactory;
private OAuth2RequestValidator requestValidator;
private UserApprovalHandler userApprovalHandler;
private AuthenticationManager authenticationManager;
private ClientDetailsService clientDetailsService;
private String prefix;
private Map<String, String> patternMap = new HashMap<String, String>();
private Set<HttpMethod> allowedTokenEndpointRequestMethods = new HashSet<HttpMethod>();
private FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping;
private boolean approvalStoreDisabled;
private List<Object> interceptors = new ArrayList<Object>();
private DefaultTokenServices defaultTokenServices;
private UserDetailsService userDetailsService;
private boolean tokenServicesOverride = false;
private boolean userDetailsServiceOverride = false;
private boolean reuseRefreshToken = true;
private WebResponseExceptionTranslator exceptionTranslator;
public AuthorizationServerTokenServices getTokenServices() {
return ProxyCreator.getProxy(AuthorizationServerTokenServices.class,
new ObjectFactory<AuthorizationServerTokenServices>() {
@Override
public AuthorizationServerTokenServices getObject() throws BeansException {
return tokenServices();
}
});
}
public TokenStore getTokenStore() {
return tokenStore();
}
public TokenEnhancer getTokenEnhancer() {
return tokenEnhancer;
}
public AccessTokenConverter getAccessTokenConverter() {
return accessTokenConverter();
}
public ApprovalStore getApprovalStore() {
return approvalStore;
}
public ClientDetailsService getClientDetailsService() {
return ProxyCreator.getProxy(ClientDetailsService.class, new ObjectFactory<ClientDetailsService>() {
@Override
public ClientDetailsService getObject() throws BeansException {
return clientDetailsService();
}
});
}
public OAuth2RequestFactory getOAuth2RequestFactory() {
return ProxyCreator.getProxy(OAuth2RequestFactory.class, new ObjectFactory<OAuth2RequestFactory>() {
@Override
public OAuth2RequestFactory getObject() throws BeansException {
return requestFactory();
}
});
}
public OAuth2RequestValidator getOAuth2RequestValidator() {
return requestValidator();
}
public UserApprovalHandler getUserApprovalHandler() {
return userApprovalHandler();
}
public AuthorizationServerEndpointsConfigurer tokenStore(TokenStore tokenStore) {
this.tokenStore = tokenStore;
return this;
}
public AuthorizationServerEndpointsConfigurer tokenEnhancer(TokenEnhancer tokenEnhancer) {
this.tokenEnhancer = tokenEnhancer;
return this;
}
public AuthorizationServerEndpointsConfigurer reuseRefreshTokens(boolean reuseRefreshToken) {
this.reuseRefreshToken = reuseRefreshToken;
return this;
}
public AuthorizationServerEndpointsConfigurer accessTokenConverter(AccessTokenConverter accessTokenConverter) {
this.accessTokenConverter = accessTokenConverter;
return this;
}
public AuthorizationServerEndpointsConfigurer tokenServices(AuthorizationServerTokenServices tokenServices) {
this.tokenServices = tokenServices;
if (tokenServices != null) {
this.tokenServicesOverride = true;
}
return this;
}
public boolean isTokenServicesOverride() {
return tokenServicesOverride;
}
public boolean isUserDetailsServiceOverride() {
return userDetailsServiceOverride;
}
public AuthorizationServerEndpointsConfigurer userApprovalHandler(UserApprovalHandler approvalHandler) {
this.userApprovalHandler = approvalHandler;
return this;
}
public AuthorizationServerEndpointsConfigurer approvalStore(ApprovalStore approvalStore) {
if (approvalStoreDisabled) {
throw new IllegalStateException("ApprovalStore was disabled");
}
this.approvalStore = approvalStore;
return this;
}
/**
* Explicitly disable the approval store, even if one would normally be added automatically (usually when JWT is not
* used). Without an approval store the user can only be asked to approve or deny a grant without any more granular
* decisions.
*
* @return this for fluent builder
*/
public AuthorizationServerEndpointsConfigurer approvalStoreDisabled() {
this.approvalStoreDisabled = true;
return this;
}
public AuthorizationServerEndpointsConfigurer prefix(String prefix) {
this.prefix = prefix;
return this;
}
public AuthorizationServerEndpointsConfigurer pathMapping(String defaultPath, String customPath) {
this.patternMap.put(defaultPath, customPath);
return this;
}
public AuthorizationServerEndpointsConfigurer addInterceptor(HandlerInterceptor interceptor) {
this.interceptors.add(interceptor);
return this;
}
public AuthorizationServerEndpointsConfigurer addInterceptor(WebRequestInterceptor interceptor) {
this.interceptors.add(interceptor);
return this;
}
public AuthorizationServerEndpointsConfigurer exceptionTranslator(WebResponseExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
return this;
}
/**
* The AuthenticationManager for the password grant.
*
* @param authenticationManager an AuthenticationManager, fully initialized
* @return this for a fluent style
*/
public AuthorizationServerEndpointsConfigurer authenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
return this;
}
public AuthorizationServerEndpointsConfigurer tokenGranter(TokenGranter tokenGranter) {
this.tokenGranter = tokenGranter;
return this;
}
/**
* N.B. this method is not part of the public API. To set up a custom ClientDetailsService please use
* {@link AuthorizationServerConfigurerAdapter#configure(ClientDetailsServiceConfigurer)}.
*/
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
this.clientDetailsService = clientDetailsService;
}
public AuthorizationServerEndpointsConfigurer requestFactory(OAuth2RequestFactory requestFactory) {
this.requestFactory = requestFactory;
return this;
}
public AuthorizationServerEndpointsConfigurer requestValidator(OAuth2RequestValidator requestValidator) {
this.requestValidator = requestValidator;
return this;
}
public AuthorizationServerEndpointsConfigurer authorizationCodeServices(
AuthorizationCodeServices authorizationCodeServices) {
this.authorizationCodeServices = authorizationCodeServices;
return this;
}
public AuthorizationServerEndpointsConfigurer allowedTokenEndpointRequestMethods(HttpMethod... requestMethods) {
Collections.addAll(allowedTokenEndpointRequestMethods, requestMethods);
return this;
}
public AuthorizationServerEndpointsConfigurer userDetailsService(UserDetailsService userDetailsService) {
if (userDetailsService != null) {
this.userDetailsService = userDetailsService;
this.userDetailsServiceOverride = true;
}
return this;
}
public ConsumerTokenServices getConsumerTokenServices() {
return consumerTokenServices();
}
public ResourceServerTokenServices getResourceServerTokenServices() {
return resourceTokenServices();
}
public AuthorizationCodeServices getAuthorizationCodeServices() {
return authorizationCodeServices();
}
public Set<HttpMethod> getAllowedTokenEndpointRequestMethods() {
return allowedTokenEndpointRequestMethods();
}
public OAuth2RequestValidator getRequestValidator() {
return requestValidator();
}
public TokenGranter getTokenGranter() {
return tokenGranter();
}
public FrameworkEndpointHandlerMapping getFrameworkEndpointHandlerMapping() {
return frameworkEndpointHandlerMapping();
}
public WebResponseExceptionTranslator getExceptionTranslator() {
return exceptionTranslator();
}
private ResourceServerTokenServices resourceTokenServices() {
if (resourceTokenServices == null) {
if (tokenServices instanceof ResourceServerTokenServices) {
return (ResourceServerTokenServices) tokenServices;
}
resourceTokenServices = createDefaultTokenServices();
}
return resourceTokenServices;
}
private Set<HttpMethod> allowedTokenEndpointRequestMethods() {
// HTTP POST should be the only allowed endpoint request method by default.
if (allowedTokenEndpointRequestMethods.isEmpty()) {
allowedTokenEndpointRequestMethods.add(HttpMethod.POST);
}
return allowedTokenEndpointRequestMethods;
}
private ConsumerTokenServices consumerTokenServices() {
if (consumerTokenServices == null) {
if (tokenServices instanceof ConsumerTokenServices) {
return (ConsumerTokenServices) tokenServices;
}
consumerTokenServices = createDefaultTokenServices();
}
return consumerTokenServices;
}
private AuthorizationServerTokenServices tokenServices() {
if (tokenServices != null) {
return tokenServices;
}
this.tokenServices = createDefaultTokenServices();
return tokenServices;
}
public AuthorizationServerTokenServices getDefaultAuthorizationServerTokenServices() {
if (defaultTokenServices != null) {
return defaultTokenServices;
}
this.defaultTokenServices = createDefaultTokenServices();
return this.defaultTokenServices;
}
private DefaultTokenServices createDefaultTokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setReuseRefreshToken(reuseRefreshToken);
tokenServices.setClientDetailsService(clientDetailsService());
tokenServices.setTokenEnhancer(tokenEnhancer());
addUserDetailsService(tokenServices, this.userDetailsService);
return tokenServices;
}
private TokenEnhancer tokenEnhancer() {
if (this.tokenEnhancer == null && accessTokenConverter() instanceof JwtAccessTokenConverter) {
tokenEnhancer = (TokenEnhancer) accessTokenConverter;
}
return this.tokenEnhancer;
}
private AccessTokenConverter accessTokenConverter() {
if (this.accessTokenConverter == null) {
accessTokenConverter = new DefaultAccessTokenConverter();
}
return this.accessTokenConverter;
}
private TokenStore tokenStore() {
if (tokenStore == null) {
if (accessTokenConverter() instanceof JwtAccessTokenConverter) {
this.tokenStore = new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter());
}
else {
this.tokenStore = new InMemoryTokenStore();
}
}
return this.tokenStore;
}
private ApprovalStore approvalStore() {
if (approvalStore == null && tokenStore() != null && !isApprovalStoreDisabled()) {
TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
tokenApprovalStore.setTokenStore(tokenStore());
this.approvalStore = tokenApprovalStore;
}
return this.approvalStore;
}
private boolean isApprovalStoreDisabled() {
return approvalStoreDisabled || (tokenStore() instanceof JwtTokenStore);
}
private ClientDetailsService clientDetailsService() {
if (clientDetailsService == null) {
this.clientDetailsService = new InMemoryClientDetailsService();
}
if (this.defaultTokenServices != null) {
addUserDetailsService(defaultTokenServices, userDetailsService);
}
return this.clientDetailsService;
}
private void addUserDetailsService(DefaultTokenServices tokenServices, UserDetailsService userDetailsService) {
if (userDetailsService != null) {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>(
userDetailsService));
tokenServices
.setAuthenticationManager(new ProviderManager(Arrays.<AuthenticationProvider> asList(provider)));
}
}
private UserApprovalHandler userApprovalHandler() {
if (userApprovalHandler == null) {
if (approvalStore() != null) {
ApprovalStoreUserApprovalHandler handler = new ApprovalStoreUserApprovalHandler();
handler.setApprovalStore(approvalStore());
handler.setRequestFactory(requestFactory());
handler.setClientDetailsService(clientDetailsService);
this.userApprovalHandler = handler;
}
else if (tokenStore() != null) {
TokenStoreUserApprovalHandler userApprovalHandler = new TokenStoreUserApprovalHandler();
userApprovalHandler.setTokenStore(tokenStore());
userApprovalHandler.setClientDetailsService(clientDetailsService());
userApprovalHandler.setRequestFactory(requestFactory());
this.userApprovalHandler = userApprovalHandler;
}
else {
throw new IllegalStateException("Either a TokenStore or an ApprovalStore must be provided");
}
}
return this.userApprovalHandler;
}
private AuthorizationCodeServices authorizationCodeServices() {
if (authorizationCodeServices == null) {
authorizationCodeServices = new InMemoryAuthorizationCodeServices();
}
return authorizationCodeServices;
}
private WebResponseExceptionTranslator exceptionTranslator() {
if (exceptionTranslator != null) {
return exceptionTranslator;
}
exceptionTranslator = new DefaultWebResponseExceptionTranslator();
return exceptionTranslator;
}
private OAuth2RequestFactory requestFactory() {
if (requestFactory != null) {
return requestFactory;
}
requestFactory = new DefaultOAuth2RequestFactory(clientDetailsService());
return requestFactory;
}
private OAuth2RequestValidator requestValidator() {
if (requestValidator != null) {
return requestValidator;
}
requestValidator = new DefaultOAuth2RequestValidator();
return requestValidator;
}
private List<TokenGranter> getDefaultTokenGranters() {
ClientDetailsService clientDetails = clientDetailsService();
AuthorizationServerTokenServices tokenServices = tokenServices();
AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
OAuth2RequestFactory requestFactory = requestFactory();
List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetails,
requestFactory));
tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetails, requestFactory));
ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, clientDetails, requestFactory);
tokenGranters.add(implicit);
tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetails, requestFactory));
if (authenticationManager != null) {
tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
clientDetails, requestFactory));
}
return tokenGranters;
}
private TokenGranter tokenGranter() {
if (tokenGranter == null) {
tokenGranter = new TokenGranter() {
private CompositeTokenGranter delegate;
@Override
public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
if (delegate == null) {
delegate = new CompositeTokenGranter(getDefaultTokenGranters());
}
return delegate.grant(grantType, tokenRequest);
}
};
}
return tokenGranter;
}
private FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping() {
if (frameworkEndpointHandlerMapping == null) {
frameworkEndpointHandlerMapping = new FrameworkEndpointHandlerMapping();
frameworkEndpointHandlerMapping.setMappings(patternMap);
frameworkEndpointHandlerMapping.setPrefix(prefix);
frameworkEndpointHandlerMapping.setInterceptors(interceptors.toArray());
}
return frameworkEndpointHandlerMapping;
}
}