/* * 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.configuration; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.aop.framework.Advised; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.security.authentication.AnonymousAuthenticationProvider; import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.ReflectionUtils; /** * @author Dave Syer * */ @Configuration public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter implements Ordered { private int order = 3; @Autowired(required = false) private TokenStore tokenStore; @Autowired(required = false) private AuthenticationEventPublisher eventPublisher; @Autowired(required = false) private Map<String, ResourceServerTokenServices> tokenServices; @Autowired private ApplicationContext context; private List<ResourceServerConfigurer> configurers = Collections.emptyList(); @Autowired(required = false) private AuthorizationServerEndpointsConfiguration endpoints; @Override public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } /** * @param configurers the configurers to set */ @Autowired(required = false) public void setConfigurers(List<ResourceServerConfigurer> configurers) { this.configurers = configurers; } private static class NotOAuthRequestMatcher implements RequestMatcher { private FrameworkEndpointHandlerMapping mapping; public NotOAuthRequestMatcher(FrameworkEndpointHandlerMapping mapping) { this.mapping = mapping; } @Override public boolean matches(HttpServletRequest request) { String requestPath = getRequestPath(request); for (String path : mapping.getPaths()) { if (requestPath.startsWith(mapping.getPath(path))) { return false; } } return true; } private String getRequestPath(HttpServletRequest request) { String url = request.getServletPath(); if (request.getPathInfo() != null) { url += request.getPathInfo(); } return url; } } @Override protected void configure(HttpSecurity http) throws Exception { ResourceServerSecurityConfigurer resources = new ResourceServerSecurityConfigurer(); ResourceServerTokenServices services = resolveTokenServices(); if (services != null) { resources.tokenServices(services); } else { if (tokenStore != null) { resources.tokenStore(tokenStore); } else if (endpoints != null) { resources.tokenStore(endpoints.getEndpointsConfigurer().getTokenStore()); } } if (eventPublisher != null) { resources.eventPublisher(eventPublisher); } for (ResourceServerConfigurer configurer : configurers) { configurer.configure(resources); } // @formatter:off http.authenticationProvider(new AnonymousAuthenticationProvider("default")) // N.B. exceptionHandling is duplicated in resources.configure() so that // it works .exceptionHandling() .accessDeniedHandler(resources.getAccessDeniedHandler()).and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .csrf().disable(); // @formatter:on http.apply(resources); if (endpoints != null) { // Assume we are in an Authorization Server http.requestMatcher(new NotOAuthRequestMatcher(endpoints.oauth2EndpointHandlerMapping())); } for (ResourceServerConfigurer configurer : configurers) { // Delegates can add authorizeRequests() here configurer.configure(http); } if (configurers.isEmpty()) { // Add anyRequest() last as a fall back. Spring Security would // replace an existing anyRequest() matcher with this one, so to // avoid that we only add it if the user hasn't configured anything. http.authorizeRequests().anyRequest().authenticated(); } } private ResourceServerTokenServices resolveTokenServices() { if (tokenServices == null || tokenServices.size() == 0) { return null; } if (tokenServices.size() == 1) { return tokenServices.values().iterator().next(); } if (tokenServices.size() == 2) { // Maybe they are the ones provided natively Iterator<ResourceServerTokenServices> iter = tokenServices.values().iterator(); ResourceServerTokenServices one = iter.next(); ResourceServerTokenServices two = iter.next(); if (elementsEqual(one, two)) { return one; } } return context.getBean(ResourceServerTokenServices.class); } private boolean elementsEqual(Object one, Object two) { // They might just be equal if (one == two) { return true; } Object targetOne = findTarget(one); Object targetTwo = findTarget(two); return targetOne == targetTwo; } private Object findTarget(Object item) { Object current = item; while (current instanceof Advised) { try { current = ((Advised) current).getTargetSource().getTarget(); } catch (Exception e) { ReflectionUtils.rethrowRuntimeException(e); } } return current; } }