/*
* 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.Collections;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
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.error.OAuth2AccessDeniedHandler;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
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.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
/**
*
* @author Rob Winch
* @since 3.2
*/
public final class OAuth2ServerConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
private AccessDeniedHandler accessDeniedHandler = new OAuth2AccessDeniedHandler();
private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter;
private OAuth2AuthenticationProcessingFilter resourcesServerFilter;
private AuthorizationServerTokenServices tokenServices;
private AuthorizationCodeServices authorizationCodeServices;
private ResourceServerTokenServices resourceTokenServices;
private TokenStore tokenStore;
private TokenGranter tokenGranter;
private ConsumerTokenServices consumerTokenServices;
private String resourceId = "oauth2-resource";
private SecurityExpressionHandler<FilterInvocation> expressionHandler = new OAuth2WebSecurityExpressionHandler();
private ClientDetailsService clientDetails() {
return getBuilder().getSharedObject(ClientDetailsService.class);
}
public AuthorizationServerTokenServices getTokenServices() {
return tokenServices;
}
public OAuth2ServerConfigurer tokenStore(TokenStore tokenStore) {
this.tokenStore = tokenStore;
return this;
}
@Override
public void init(HttpSecurity http) throws Exception {
registerDefaultAuthenticationEntryPoint(http);
http
.securityContext()
.securityContextRepository(new NullSecurityContextRepository())
.and()
.csrf().disable()
.httpBasic();
}
@SuppressWarnings("unchecked")
private void registerDefaultAuthenticationEntryPoint(HttpSecurity http) {
ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class);
if(exceptionHandling == null) {
return;
}
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if(contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA, MediaType.TEXT_XML);
preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(authenticationEntryPoint), preferredMatcher);
}
public OAuth2ServerConfigurer resourceId(String resourceId) {
this.resourceId = resourceId;
return this;
}
@Override
@SuppressWarnings("unchecked")
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
clientCredentialsTokenEndpointFilter = new ClientCredentialsTokenEndpointFilter();
clientCredentialsTokenEndpointFilter.setAuthenticationManager(authenticationManager);
clientCredentialsTokenEndpointFilter = postProcess(clientCredentialsTokenEndpointFilter);
AuthenticationManager oauthAuthenticationManager = oauthAuthenticationManager(http);
resourcesServerFilter = new OAuth2AuthenticationProcessingFilter();
resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager);
resourcesServerFilter = postProcess(resourcesServerFilter);
this.tokenGranter = tokenGranter(http);
this.consumerTokenServices = consumerTokenServices(http);
http
.authorizeRequests()
.expressionHandler(expressionHandler)
.and()
.addFilterBefore(resourcesServerFilter, AbstractPreAuthenticatedProcessingFilter.class)
.addFilterBefore(clientCredentialsTokenEndpointFilter, BasicAuthenticationFilter.class)
.getConfigurer(ExceptionHandlingConfigurer.class)
.accessDeniedHandler(accessDeniedHandler);
}
private AuthenticationManager oauthAuthenticationManager(HttpSecurity http) {
OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();
oauthAuthenticationManager.setResourceId(resourceId);
oauthAuthenticationManager
.setTokenServices(resourceTokenServices(http));
return oauthAuthenticationManager;
}
private ResourceServerTokenServices resourceTokenServices(
HttpSecurity http) {
tokenServices(http);
return this.resourceTokenServices;
}
private AuthorizationServerTokenServices tokenServices(HttpSecurity http) {
if (tokenServices != null) {
return tokenServices;
}
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetails());
this.tokenServices = tokenServices;
this.resourceTokenServices = tokenServices;
return tokenServices;
}
private TokenStore tokenStore() {
if (tokenStore == null) {
this.tokenStore = new InMemoryTokenStore();
}
return this.tokenStore;
}
public AuthorizationCodeServices getAuthorizationCodeServices() {
return authorizationCodeServices;
}
private AuthorizationCodeServices authorizationCodeServices(
HttpSecurity http) {
if (authorizationCodeServices == null) {
authorizationCodeServices = new InMemoryAuthorizationCodeServices();
}
return authorizationCodeServices;
}
private AuthenticationManager authenticationManager(HttpSecurity http) {
return http.getSharedObject(AuthenticationManager.class);
}
public TokenGranter getTokenGranter() {
return tokenGranter;
}
public ConsumerTokenServices getConsumerTokenServices() {
return consumerTokenServices;
}
private ConsumerTokenServices consumerTokenServices(HttpSecurity http) {
if(consumerTokenServices == null) {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setClientDetailsService(clientDetails());
defaultTokenServices.setTokenStore(tokenStore());
consumerTokenServices = defaultTokenServices;
}
return consumerTokenServices;
}
private TokenGranter tokenGranter(HttpSecurity http) throws Exception {
if(tokenGranter == null) {
ClientDetailsService clientDetails = clientDetails();
AuthorizationServerTokenServices tokenServices = tokenServices(http);
AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices(http);
AuthenticationManager authenticationManager = authenticationManager(http);
List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices,
authorizationCodeServices, clientDetails));
tokenGranters
.add(new RefreshTokenGranter(tokenServices, clientDetails));
tokenGranters
.add(new ImplicitTokenGranter(tokenServices, clientDetails));
tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices,
clientDetails));
tokenGranters.add(new ResourceOwnerPasswordTokenGranter(
authenticationManager, tokenServices, clientDetails));
tokenGranter = new CompositeTokenGranter(tokenGranters);
}
return tokenGranter;
}
}