当有多个<http>元素</http> </authorize>时,Spring Security“<authorize url =”...“>”标签无法正确评估网址

时间:2013-09-13 21:58:29

标签: spring-security

我正在尝试使用<authorize>标记的spring security的“url”属性。我陷入一种奇怪的情况,标签似乎没有生效。

我的业务需求是使用两个<http>元素,一个用于Web服务访问,另一个用于普通用户访问:Web服务访问是无状态的,但用户访问是基于会话的,这就是我们需要两个http的原因元素。

为了说明这个问题,我将使用spring security 3.1.4教程。我可以通过在spring配置文件中添加一个额外的<http>元素来重现此问题。

教程中的原始applicationContext-secutiry.xml定义如下:

<http pattern="/static/**" security="none"/>
<http pattern="/loggedout.jsp" security="none"/>

<http use-expressions="true">
    <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"/>
    <intercept-url pattern="/secure/**" access="isAuthenticated()" />
    ....
 </http>

它的着陆页index.jsp使用“authorize”标签,如下所示:

<sec:authorize url='/secure/index.jsp'>
<p>
    You can currently access "/secure" URLs.
</p>
</sec:authorize>

当用户第一次尝试访问此页面时,标记将检查url'/secure/index.jsp'的权限,这需要身份验证,因此,标记不会替换其内容和UI显示消息,如。

你的主要对象是......:null

现在,通过在最后一个“http”元素

之前添加一个新的http元素来更改applicationContext-security.xml
<http pattern="/static/**" security="none"/>
<http pattern="/loggedout.jsp" security="none"/>

<!--This is the new element added-->
<http pattern="/user/**"
     use-expressions="true">
    <intercept-url pattern="/user/**" access="hasRole('user')"/>
    <http-basic />
 </http>

<http use-expressions="true">
    <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"/>
    <intercept-url pattern="/secure/**" access="isAuthenticated()" />
    ....
 </http>

现在,我访问了index.jsp(还没有登录),页面实际打印出一条消息说:

你的主要对象是......:null 您当前可以访问“/ secure”网址。 您当前可以访问“/ secure / extreme”网址。

在这种情况下,“authorize”标签的评估结果为true,即使我还没有登录!

我尝试通过源代码DefaultFilterInvocationSecurityMetadataSource调试,并发现当第一个http请求“/index.jsp”进来时,它使用applicationContext-security.xml中的默认元素(最后一个)但是当“”标签尝试检查对“/secure/index.jsp”的访问,DefaultFilterInvocationSecurityMetadataSource使用新元素,其getAttributes()返回null到DefaultWebInvocationPrivilegeEvaluator,最终返回true。

对我来说,这看起来像是一个弹簧安全漏洞:授权标记网址“/secure/index.jsp”应该与默认的“http”匹配,而不是另一个。

我使用的一种解决方法是将“/secure/index.jsp”和“/secure/extreme/index.jsp”的“intercept-url”定义从默认的“http”复制到新的“http”元素然后UI按预期工作。但我不想复制代码!

任何想法都表示赞赏。

2 个答案:

答案 0 :(得分:1)

我已解决此问题如下。

Java:

package com.github.kazuki43zoo.web.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.stereotype.Component;

@Component
public class CustomWebInvocationPrivilegeEvaluatorProvideFilter implements Filter,
        WebInvocationPrivilegeEvaluator, BeanPostProcessor {

    private List<WebInvocationPrivilegeEvaluator> webInvocationPrivilegeEvaluators = new ArrayList<>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        request.setAttribute(WebAttributes.WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE, this);
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        webInvocationPrivilegeEvaluators.clear();
    }

    @Override
    public boolean isAllowed(String uri, Authentication authentication) {
        for (WebInvocationPrivilegeEvaluator privilegeEvaluator : webInvocationPrivilegeEvaluators) {
            if (!privilegeEvaluator.isAllowed(uri, authentication)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean isAllowed(String contextPath, String uri, String method,
            Authentication authentication) {
        for (WebInvocationPrivilegeEvaluator privilegeEvaluator : webInvocationPrivilegeEvaluators) {
            if (!privilegeEvaluator.isAllowed(contextPath, uri, method, authentication)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof WebInvocationPrivilegeEvaluator
                && !bean.getClass().isAssignableFrom(getClass())) {
            webInvocationPrivilegeEvaluators.add((WebInvocationPrivilegeEvaluator) bean);
        }
        return bean;
    }

}

的web.xml:

<filter>
    <filter-name>CustomWebInvocationPrivilegeEvaluatorProvideFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetBeanName</param-name>
        <param-value>customWebInvocationPrivilegeEvaluatorProvideFilter</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CustomWebInvocationPrivilegeEvaluatorProvideFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

答案 1 :(得分:0)

这对我有用:

org.springframework.context.ApplicationContext ctx = org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
java.util.Map<String, org.springframework.security.web.access.WebInvocationPrivilegeEvaluator>
        wipes = ctx.getBeansOfType(org.springframework.security.web.access.WebInvocationPrivilegeEvaluator.class);

if(wipes.size() > 0){
    //I need last one
    org.springframework.security.web.access.WebInvocationPrivilegeEvaluator appEvaluator =
            (WebInvocationPrivilegeEvaluator)wipes.values().toArray()[wipes.size() - 1];

    //set request attribute so that JSP tag can use it        request.setAttribute(org.springframework.security.web.WebAttributes.WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE
            , appEvaluator);

}