您的位置:首页 > 编程语言 > Java开发

Spring Security3源码分析-SSL支持

2013-05-30 12:43 531 查看



来自:http://dead-knight.iteye.com/blog/1521223 






Spring Security3源码分析-SSL支持

博客分类: 

Spring Security

Sping Security3对于SSL的支持仅仅表现在对需要拦截的url(标签intercept-url)设置requires-channel=https属性。

如果一个url设置了requires-channel为https,那么该url在http的访问会直接重定向到https的通道中去。后面再具体分析。

首先需要在应用中配置SSL的支持,具体配置方法可参考

http://lengyun3566.iteye.com/blog/1141347

 

Sping Security3支持SSL分别表现下面几个类

 
类名称用途描述
ChannelProcessingFilter通道处理过滤器。只要intercept-url标签中包含requires-channel属性,该过滤器就被创建
ChannelDecisionManagerImpl通道决策管理器。该管理器包含两个ChannelProcessor实例用于处理安全、不安全两种Channel方式
SecureChannelProcessor安全通道处理器
InsecureChannelProcessor不安全通道处理器
AbstractRetryEntryPoint抽象的通道重操作入口点,是entrypoint的父类
RetryWithHttpEntryPoint如果当前以安全通道访问不安全通道,也可以通过http的入口点重定向到不安全通道中
RetryWithHttpsEntryPoint如果当前以不安全通道访问安全通道,就要通过https的入口点重定向到安全通道中
PortMapperImpl端口映射处理。主要是针对非默认端口(80、8080、443、8443)的情况
 

 看ChannelProcessingFilter过滤器的作用

ChannelProcessingFilter首先检查当前请求的url是否已配置了requires-channel属性,如果没配置,不处理。如果配置了,就把决策权交给ChannelDecisionManagerImpl处理。

ChannelProcessingFilter对应类路径:org.springframework.security.web.access.channel.ChannelProcessingFilter

具体源码如下

Java代码  



public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)  

        throws IOException, ServletException {  

    HttpServletRequest request = (HttpServletRequest) req;  

    HttpServletResponse response = (HttpServletResponse) res;  

  

    FilterInvocation fi = new FilterInvocation(request, response, chain);  

    //获取url的权限配置信息  

    Collection<ConfigAttribute> attr = this.securityMetadataSource.getAttributes(fi);  

  

    if (attr != null) {  

        if (logger.isDebugEnabled()) {  

            logger.debug("Request: " + fi.toString() + "; ConfigAttributes: " + attr);  

        }  

        //把决策权交给channelDecisionManager处理  

        channelDecisionManager.decide(fi, attr);  

  

        if (fi.getResponse().isCommitted()) {  

            return;  

        }  

    }  

  

    chain.doFilter(request, response);  

}  

 接着看ChannelDecisionManagerImpl的作用

ChannelDecisionManagerImpl根据requires-channel的值做相应处理,requires-channel值有以下三种

any:任何通道都支持。决策管理器不做处理

https:只支持安全通道。决策管理器把决策任务交给ChannelProcessor列表循环处理

http:只支持http。决策管理器把决策任务交给ChannelProcessor列表循环处理

ChannelDecisionManagerImpl的源码为:

Java代码  



public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {  

  

    Iterator<ConfigAttribute> attrs = config.iterator();  

    //判断是否为any值  

    while (attrs.hasNext()) {  

        ConfigAttribute attribute = attrs.next();  

        if (ANY_CHANNEL.equals(attribute.getAttribute())) {  

            return;  

        }  

    }  

    //循环ChannelProcessor列表执行decide  

    for (ChannelProcessor processor : channelProcessors) {  

        processor.decide(invocation, config);  

  

        if (invocation.getResponse().isCommitted()) {  

            break;  

        }  

    }  

}  

 

继续看ChannelProcessor 的作用

实际上在构造ChannelDecisionManager的bean时,已经注入了两个ChannelProcessor ,分别是SecureChannelProcessor、InsecureChannelProcessor

先看SecureChannelProcessor(负责处理安全通道)执行过程

Java代码  



public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {  

    Assert.isTrue((invocation != null) && (config != null), "Nulls cannot be provided");  

    for (ConfigAttribute attribute : config) {  

        if (supports(attribute)) {  

            if (!invocation.getHttpRequest().isSecure()) {  

                entryPoint.commence(invocation.getRequest(), invocation.getResponse());  

            }  

        }  

    }  

}  

根据当前的请求是否安全,进行相应的处理。实际工作的是抽象的父类AbstractRetryEntryPoint的commence完成

AbstractRetryEntryPoint的commence方法源码:

Java代码  



public void commence(HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException {  

    String pathInfo = request.getPathInfo();  

    String queryString = request.getQueryString();  

    String contextPath = request.getContextPath();  

    String destination = request.getServletPath() + ((pathInfo == null) ? "" : pathInfo)  

        + ((queryString == null) ? "" : ("?" + queryString));  

  

    String redirectUrl = contextPath;  

    //获取当前请求所在端口  

 Integer currentPort = new Integer(portResolver.getServerPort(request));  

    //根据当前端口获得映射的端口(需要配置port-mappings标签),如果是http的访问,则获取映射的https端口,如果是https的访问,则获取相应的http端口  

 Integer redirectPort = getMappedPort(currentPort);  

    //如果获取到匹配端口,则根据当前请求构造重定向请求的url  

    if (redirectPort != null) {  

        boolean includePort = redirectPort.intValue() != standardPort;  

  

        redirectUrl = scheme + request.getServerName() + ((includePort) ? (":" + redirectPort) : "") + contextPath  

            + destination;  

    }  

  

    if (logger.isDebugEnabled()) {  

        logger.debug("Redirecting to: " + redirectUrl);  

    }  

    //执行重定向操作  

    res.sendRedirect(res.encodeRedirectURL(redirectUrl));  

}  

通过以上分析,应该很清楚的知道:

如果以http的方式登录到应用中,再访问配置了requires-channel=https的url时,就会重定向到https的通道去,以SSL方式访问。

 

如果以https的方式登录到应用中,再访问配置了requires-channel=http的url时,就会重定向到http的通道去,以不安全的方式访问。

分享到: 

 



Spring Security3源码分析-CAS支持 | Spring
Security3源码分析-认证授权分析

2012-05-10 12:48

浏览 1312

评论(7)

分类:企业架构

相关推荐


评论


7 楼 Dead_knight 2012-08-10  

lintghi 写道

Dead_knight 写道

lintghi 写道

bingfengfzl 写道

我用的是spring security3.11requires-channel="https"配不上,有办法解决不高手可以加你qq不,新人上路。。

我也遇到相似的问题. 用命名空间可以, 但是用自己配置bean的方式, 却提示不能是requires-channel这个属性.

如果自己配置的bean,是不支持requires-channel属性的。因为这是使用spring schema的xsd约束的。 

使用命名空间requires-channel="https"也不行么?如果不行,我研究下3.11版本与3.02版本的差异

到最后我是这样配置的: 

<bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter"> 

<property name="securityMetadataSource" ref="defaultFilterInvocationSecurityMetadataSource"/> 

<property name="channelDecisionManager" ref="channelDecisionManager"/> 

</bean> 

<bean id="defaultFilterInvocationSecurityMetadataSource" 

class="org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource"> 

<constructor-arg name="requestMap"> 

<map> 

<entry> 

<key> 

<bean class="org.springframework.security.web.util.AntPathRequestMatcher"> 

<constructor-arg name="pattern" value="/login.do"/> 

</bean> 

</key> 

<list> 

<bean class="org.springframework.security.access.SecurityConfig"> 

<constructor-arg name="config" value="REQUIRES_SECURE_CHANNEL"/> 

</bean> 

</list> 

</entry> 

</map> 

</constructor-arg> 

</bean> 

上面是配置ChannelProcessFilter. 

<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">

<property name="authenticationManager" ref="customAuthenticationManager"/> 

<property name="accessDecisionManager" ref="affirmativeBased"/> 

<property name="securityMetadataSource"> 

<security:filter-security-metadata-source id="expressionBasedFilterInvocationSecurityMetadataSource" use-expressions="true" lowercase-comparisons="true"> 

<security:intercept-url pattern="/login.do" access="permitAll"/> 

</security:filter-security-metadata-source> 

</property> 

</bean> 

由于没法使用requires-channel, 所以intercept-url只使用pattern, access属性. filters属性有不能用. 不知道在哪里配置. 

目前发现3.1和3.0x的区别是, 用bean方式配置时, 要用构造注入而不是属性注入.

这篇文章没有对SSL的bean初始化进行分析。 

最简单的方法,你自己配置bean时,直接打开这个类的源码,查看某个属性是通过构造注入,还是set注入就知道。 

Spring Security里面很多类都是构造注入的

6 楼 lintghi 2012-08-10  

Dead_knight 写道

lintghi 写道

bingfengfzl 写道

我用的是spring security3.11requires-channel="https"配不上,有办法解决不高手可以加你qq不,新人上路。。

我也遇到相似的问题. 用命名空间可以, 但是用自己配置bean的方式, 却提示不能是requires-channel这个属性.

如果自己配置的bean,是不支持requires-channel属性的。因为这是使用spring schema的xsd约束的。

使用命名空间requires-channel="https"也不行么?如果不行,我研究下3.11版本与3.02版本的差异

到最后我是这样配置的: 

<bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter">

<property name="securityMetadataSource" ref="defaultFilterInvocationSecurityMetadataSource"/>

<property name="channelDecisionManager" ref="channelDecisionManager"/>

</bean>

<bean id="defaultFilterInvocationSecurityMetadataSource" 

class="org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource">

<constructor-arg name="requestMap">

<map>

<entry>

<key>

<bean class="org.springframework.security.web.util.AntPathRequestMatcher">

<constructor-arg name="pattern" value="/login.do"/>

</bean>

</key>

<list>

<bean class="org.springframework.security.access.SecurityConfig">

<constructor-arg name="config" value="REQUIRES_SECURE_CHANNEL"/>

</bean>

</list>

</entry>

</map>

</constructor-arg>

</bean>

上面是配置ChannelProcessFilter. 

<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">

<property name="authenticationManager" ref="customAuthenticationManager"/>

<property name="accessDecisionManager" ref="affirmativeBased"/>

<property name="securityMetadataSource">

<security:filter-security-metadata-source id="expressionBasedFilterInvocationSecurityMetadataSource" use-expressions="true" lowercase-comparisons="true">

<security:intercept-url pattern="/login.do" access="permitAll"/>

</security:filter-security-metadata-source>

</property>

</bean>

由于没法使用requires-channel, 所以intercept-url只使用pattern, access属性. filters属性有不能用. 不知道在哪里配置. 

目前发现3.1和3.0x的区别是, 用bean方式配置时, 要用构造注入而不是属性注入.

5 楼 Dead_knight 2012-08-09  

lintghi 写道

bingfengfzl 写道

我用的是spring security3.11requires-channel="https"配不上,有办法解决不高手可以加你qq不,新人上路。。

我也遇到相似的问题. 用命名空间可以, 但是用自己配置bean的方式, 却提示不能是requires-channel这个属性.

如果自己配置的bean,是不支持requires-channel属性的。因为这是使用spring schema的xsd约束的。 

使用命名空间requires-channel="https"也不行么?如果不行,我研究下3.11版本与3.02版本的差异

4 楼 lintghi 2012-08-09  

bingfengfzl 写道

我用的是spring security3.11requires-channel="https"配不上,有办法解决不高手可以加你qq不,新人上路。。

我也遇到相似的问题. 用命名空间可以, 但是用自己配置bean的方式, 却提示不能是requires-channel这个属性.

3 楼 bingfengfzl 2012-08-01  
我用的是spring security3.11requires-channel="https"配不上,有办法解决不高手可以加你qq不,新人上路。。

2 楼 Dead_knight 2012-07-31  

bingfengfzl 写道

求源码,可以贴配置文件出来不? 

求源码,小弟不胜感激bingfengfzl@163.com

源码很简单的,仅仅是intercept-url配置中增加requires-channel属性而已 

Java代码  



<security:http auto-config="true" >  

    <security:port-mappings>  

        <security:port-mapping http="8888" https="8443"/>  

    </security:port-mappings>  

    <security:form-login login-page="/login.jsp"/>  

    <security:logout logout-success-url="/login.jsp" invalidate-session="true"/>  

    <security:intercept-url pattern="/login.jsp*" filters="none"/>  

    <security:intercept-url pattern="/admin.jsp*" access="ROLE_USER,ROLE_ADMIN"  requires-channel="https"/>  

    <security:intercept-url pattern="/UserList.do*" access="ROLE_USER,ROLE_ADMIN"  requires-channel="http"/>  

    <security:intercept-url pattern="/index.jsp*" access="ROLE_USER,ROLE_ADMIN"/>  

    <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>  

    <security:session-management session-fixation-protection="none">  

    </security:session-management>  

</security:http>  

1 楼 bingfengfzl 2012-07-31  
求源码,可以贴配置文件出来不?

求源码,小弟不胜感激bingfengfzl@163.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: