/* * 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.Collections; import org.springframework.http.MediaType; import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.authentication.AuthenticationEventPublisher; 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.authentication.OAuth2AuthenticationManager; import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter; import org.springframework.security.oauth2.provider.authentication.TokenExtractor; 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.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; 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.util.matcher.MediaTypeRequestMatcher; import org.springframework.util.Assert; import org.springframework.web.accept.ContentNegotiationStrategy; import org.springframework.web.accept.HeaderContentNegotiationStrategy; /** * * @author Rob Winch * @author Dave Syer * * @since 2.0.0 */ public final class ResourceServerSecurityConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint(); private AccessDeniedHandler accessDeniedHandler = new OAuth2AccessDeniedHandler(); private OAuth2AuthenticationProcessingFilter resourcesServerFilter; private AuthenticationManager authenticationManager; private AuthenticationEventPublisher eventPublisher = null; private ResourceServerTokenServices resourceTokenServices; private TokenStore tokenStore = new InMemoryTokenStore(); private String resourceId = "oauth2-resource"; private SecurityExpressionHandler<FilterInvocation> expressionHandler = new OAuth2WebSecurityExpressionHandler(); private TokenExtractor tokenExtractor; private boolean stateless = true; public ResourceServerSecurityConfigurer() { resourceId(resourceId); } private ClientDetailsService clientDetails() { return getBuilder().getSharedObject(ClientDetailsService.class); } public TokenStore getTokenStore() { return tokenStore; } /** * Flag to indicate that only token-based authentication is allowed on these resources. * @param stateless the flag value (default true) * @return this (for fluent builder) */ public ResourceServerSecurityConfigurer stateless(boolean stateless) { this.stateless = stateless; return this; } public ResourceServerSecurityConfigurer authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) { this.authenticationEntryPoint = authenticationEntryPoint; return this; } public ResourceServerSecurityConfigurer accessDeniedHandler(AccessDeniedHandler accessDeniedHandler) { this.accessDeniedHandler = accessDeniedHandler; return this; } public ResourceServerSecurityConfigurer tokenStore(TokenStore tokenStore) { Assert.state(tokenStore != null, "TokenStore cannot be null"); this.tokenStore = tokenStore; return this; } public ResourceServerSecurityConfigurer eventPublisher(AuthenticationEventPublisher eventPublisher) { Assert.state(eventPublisher != null, "AuthenticationEventPublisher cannot be null"); this.eventPublisher = eventPublisher; return this; } public ResourceServerSecurityConfigurer expressionHandler( SecurityExpressionHandler<FilterInvocation> expressionHandler) { Assert.state(expressionHandler != null, "SecurityExpressionHandler cannot be null"); this.expressionHandler = expressionHandler; return this; } public ResourceServerSecurityConfigurer tokenExtractor(TokenExtractor tokenExtractor) { Assert.state(tokenExtractor != null, "TokenExtractor cannot be null"); this.tokenExtractor = tokenExtractor; return this; } public ResourceServerSecurityConfigurer authenticationManager(AuthenticationManager authenticationManager) { Assert.state(authenticationManager != null, "AuthenticationManager cannot be null"); this.authenticationManager = authenticationManager; return this; } public ResourceServerSecurityConfigurer tokenServices(ResourceServerTokenServices tokenServices) { Assert.state(tokenServices != null, "ResourceServerTokenServices cannot be null"); this.resourceTokenServices = tokenServices; return this; } @Override public void init(HttpSecurity http) throws Exception { registerDefaultAuthenticationEntryPoint(http); } @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 ResourceServerSecurityConfigurer resourceId(String resourceId) { this.resourceId = resourceId; if (authenticationEntryPoint instanceof OAuth2AuthenticationEntryPoint) { ((OAuth2AuthenticationEntryPoint) authenticationEntryPoint).setRealmName(resourceId); } return this; } @Override public void configure(HttpSecurity http) throws Exception { AuthenticationManager oauthAuthenticationManager = oauthAuthenticationManager(http); resourcesServerFilter = new OAuth2AuthenticationProcessingFilter(); resourcesServerFilter.setAuthenticationEntryPoint(authenticationEntryPoint); resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager); if (eventPublisher != null) { resourcesServerFilter.setAuthenticationEventPublisher(eventPublisher); } if (tokenExtractor != null) { resourcesServerFilter.setTokenExtractor(tokenExtractor); } resourcesServerFilter = postProcess(resourcesServerFilter); resourcesServerFilter.setStateless(stateless); // @formatter:off http .authorizeRequests().expressionHandler(expressionHandler) .and() .addFilterBefore(resourcesServerFilter, AbstractPreAuthenticatedProcessingFilter.class) .exceptionHandling() .accessDeniedHandler(accessDeniedHandler) .authenticationEntryPoint(authenticationEntryPoint); // @formatter:on } private AuthenticationManager oauthAuthenticationManager(HttpSecurity http) { OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager(); if (authenticationManager != null) { if (authenticationManager instanceof OAuth2AuthenticationManager) { oauthAuthenticationManager = (OAuth2AuthenticationManager) authenticationManager; } else { return authenticationManager; } } oauthAuthenticationManager.setResourceId(resourceId); oauthAuthenticationManager.setTokenServices(resourceTokenServices(http)); oauthAuthenticationManager.setClientDetailsService(clientDetails()); return oauthAuthenticationManager; } private ResourceServerTokenServices resourceTokenServices(HttpSecurity http) { tokenServices(http); return this.resourceTokenServices; } private ResourceServerTokenServices tokenServices(HttpSecurity http) { if (resourceTokenServices != null) { return resourceTokenServices; } DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(tokenStore()); tokenServices.setSupportRefreshToken(true); tokenServices.setClientDetailsService(clientDetails()); this.resourceTokenServices = tokenServices; return tokenServices; } private TokenStore tokenStore() { Assert.state(tokenStore != null, "TokenStore cannot be null"); return this.tokenStore; } public AccessDeniedHandler getAccessDeniedHandler() { return this.accessDeniedHandler; } }