/* * Copyright 2002-2016 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.web.access.expression; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.expression.ExpressionParser; import org.springframework.expression.ParseException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestVariablesExtractor; import org.springframework.util.Assert; /** * Expression-based {@code FilterInvocationSecurityMetadataSource}. * * @author Luke Taylor * @since 3.0 */ public final class ExpressionBasedFilterInvocationSecurityMetadataSource extends DefaultFilterInvocationSecurityMetadataSource { private final static Log logger = LogFactory .getLog(ExpressionBasedFilterInvocationSecurityMetadataSource.class); public ExpressionBasedFilterInvocationSecurityMetadataSource( LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap, SecurityExpressionHandler<FilterInvocation> expressionHandler) { super(processMap(requestMap, expressionHandler.getExpressionParser())); Assert.notNull(expressionHandler, "A non-null SecurityExpressionHandler is required"); } private static LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> processMap( LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap, ExpressionParser parser) { Assert.notNull(parser, "SecurityExpressionHandler returned a null parser object"); LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestToExpressionAttributesMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>( requestMap); for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap .entrySet()) { RequestMatcher request = entry.getKey(); Assert.isTrue(entry.getValue().size() == 1, "Expected a single expression attribute for " + request); ArrayList<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(1); String expression = entry.getValue().toArray(new ConfigAttribute[1])[0] .getAttribute(); logger.debug("Adding web access control expression '" + expression + "', for " + request); AbstractVariableEvaluationContextPostProcessor postProcessor = createPostProcessor( request); try { attributes.add(new WebExpressionConfigAttribute( parser.parseExpression(expression), postProcessor)); } catch (ParseException e) { throw new IllegalArgumentException( "Failed to parse expression '" + expression + "'"); } requestToExpressionAttributesMap.put(request, attributes); } return requestToExpressionAttributesMap; } private static AbstractVariableEvaluationContextPostProcessor createPostProcessor( Object request) { if (request instanceof RequestVariablesExtractor) { return new RequestVariablesExtractorEvaluationContextPostProcessor( (RequestVariablesExtractor) request); } return null; } static class AntPathMatcherEvaluationContextPostProcessor extends AbstractVariableEvaluationContextPostProcessor { private final AntPathRequestMatcher matcher; public AntPathMatcherEvaluationContextPostProcessor( AntPathRequestMatcher matcher) { this.matcher = matcher; } @Override Map<String, String> extractVariables(HttpServletRequest request) { return this.matcher.extractUriTemplateVariables(request); } } static class RequestVariablesExtractorEvaluationContextPostProcessor extends AbstractVariableEvaluationContextPostProcessor { private final RequestVariablesExtractor matcher; public RequestVariablesExtractorEvaluationContextPostProcessor( RequestVariablesExtractor matcher) { this.matcher = matcher; } @Override Map<String, String> extractVariables(HttpServletRequest request) { return this.matcher.extractUriTemplateVariables(request); } } }