7

Background

Hey all, We have Spring project which uses Spring security. We have defined the security filters by defining

 <b:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">

whith filter-chain-map

and in the web.xml we do

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

 <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

and it all works well :). Now when hooking up Spring session with redis according to the doc the next following lines

<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>

create a filter named springSessionRepositoryFilter. So basically what we did is in every custom filter-chain we add that filter to be the very first filter . i.e:

<b:bean id="springSecurityFilterChain"   class="org.springframework.security.web.FilterChainProxy">
     <filter-chain-map request-matcher="ant">

           <filter-chain pattern="/api/someapieformobilelogin" filters="none" />  <!-- no filter on login -->
        <filter-chain pattern="/api/**"
            filters="springSessionRepositoryFilter, securityContextFilter,and some other spring security filter />

        <filter-chain pattern="/**"
            filters="springSessionRepositoryFilter, securityContextFilter,and some other spring security filter />

The results: the app seems to work good and also monitoring via redis-cli shows the spring is communicating with redis.

The question

Does the use of springSessionRepositoryFilter inside the filter-chain is ok? or we abused the filtering system?

Thanks,

Oak

Edit

It seems that above will not work for the case one wants to Authenticate the user from code i.e

Authentication authentication = authenticationManager
                .authenticate(authenticationToken);
SecurityContext securityContext = SecurityContextHolder
                .getContext();
securityContext.setAuthentication(authentication);

will failed. Maybe because its not enough to run it via filter-chain of org.springframework.security.web.FilterChainProxy.

What do you think on run it as filter in web.xml?

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

The above will force running springSessionRepositoryFilter before springSecurityFilterChain but in this example org.springframework.web.filter.DelegatingFilterProxy is being called twice. any other ways to make springSessionRepositoryFilter run as a filter before out springSecurityFilterChain filter?

Community
  • 1
  • 1
oak
  • 2,898
  • 2
  • 32
  • 65
  • I know this is an old question. bu did you find a solution for this problem? I currently face the same issue – 0riginal Oct 20 '16 at 11:00
  • This indeed old question, I think i can look the answer somehwere. Do you still need it? – oak Oct 27 '16 at 13:10
  • Hello thank you for the reply. We removed spring-session from our project temporaly because we couldn't fix this issue. If it takes too much time you dont have to search for the answer – 0riginal Oct 27 '16 at 14:02
  • Hey there, I added my answer to this question. Hope it can help you to figure it out – oak Oct 30 '16 at 07:38

2 Answers2

2

According to my testing, springSessionRepositoryFilter must run first. This is due the fact that springSessionRepositoryFilter replaces the HttpSession implementation. Here is my solution using xml files.

redis-cache.xml

<context:annotation-config />
<bean
    class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />

<bean
    class="org.springframework.security.web.session.HttpSessionEventPublisher" />

<!-- end of seesion managment configuration -->


<bean id="redisConnectionFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="port" value="${app.redis.port}" />
    <property name="hostName" value="${app.redis.hostname}" />
    <property name="password" value="${app.redis.password}" />
    <property name="usePool" value="true" />
</bean>

We use the combination of and RedisHttpSessionConfiguration because Spring Session does not yet provide XML Namespace support (see gh-104). This creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter. The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session. In this instance Spring Session is backed by Redis. source

Now, as we have the session filter named springSessionRepositoryFilter it must run as the first filter because it replaces the HttpSession implementation.

In order to do so, we declare it as the first filter in web.xml. For more info about filters and filter's order checkout the docs

web.xml

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>


<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    /WEB-INF/redis-cache.xml
    </param-value>
</context-param>

 <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Note that the first to run is springSessionRepositoryFilter. But actully org.springframework.web.filter.DelegatingFilterProxy class is running and it looks for the filter by the bean's name. So it search for the bean created by our early configurations. reference

The extra line about the redis-cache.xml are important as well. Otherwise our spring application context cannot know about our redis configuration

reference

oak
  • 2,898
  • 2
  • 32
  • 65
  • Thank you for the answer. I we have a similar setup now but we still have problems for some requests. Do you think two DelegatingFilterProxys could be a problem? – 0riginal Nov 02 '16 at 11:40
1

It does not matter. From the Javadoc:

The SessionRepositoryFilter must be placed before any Filter that access the HttpSession or that might commit the response to ensure the session is overridden and persisted properly.

So long as you add springSessionRepositoryFilter before anything that can commit the response or access the HttpSession, you are fine. In the case of Spring Security the main thing you will want to ensure is that springSessionRepositoryFilter is before the SecurityContextPersistenceFilter. This can be done by including springSessionRepositoryFilter within the container or within Spring Security's FilterChainProxy (i.e. <filter-chain>).

Rob Winch
  • 21,440
  • 2
  • 59
  • 76
  • 1
    Hey, thanks for replying. The solution above raised some issue. for example trying to do `SecurityContext securityContext = SecurityContextHolder.getContext(); securityContext.setAuthentication(authentication);` from code seems not to get run. My thoughts that even this filter is set to be the first via `` its still not enough and should run before it. what do you think? – oak Sep 09 '15 at 09:28