Java – Combining DispatcherServlet, ContextLoaderListener and SpringSecurity

hibernatejavaservletsspring-mvcspring-security

I have quite a nut to crack here.. Been trying to integrate said 3 technologies into our webapp.. We want to use

  1. Spring Web
  2. Spring MVC as view technology (with freemarker)
  3. Spring Security as security layer

But whichever way I configure my web.xml and other context files I can't get everything to work at the same time.. With my current configuration everything will work, except SpringSecurity will not intercept the URL patterns

Some googling (and commons sense) told me that combining DispatcherServlet and ContextLoaderListener might be a problem.

So here are my configurations. (Sorry for so much text and thanks for reading):

web.xml:

<!-- Needed by Spring -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/dw-manager-context.xml</param-value>
</context-param>

<!-- Needed by Spring MVC -->
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!-- Needed by Spring Security -->
<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>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

My servlet-context.xml:

<!-- Scan for controllers -->
<context:component-scan base-package="dw.manager" />

<!-- Need to declare annotation driven transactions again so they are picked up above controller methods -->
<tx:annotation-driven transaction-manager="transactionManager" />

<mvc:annotation-driven />

<bean id="viewResolver"     class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <!-- ... -->
</bean>

<bean id="freemarkerConfig"
    class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <!-- ... -->
</bean>

My manager-context.xml:

<context:annotation-config />   

    <!-- deployment-setup just loads properties (files) -->
<import resource="deployment-setup.xml" />
<import resource="spring-security-context.xml" />
<import resource="dw-manager-datasource.xml" />

<!-- Import sub-modules -->
<import resource="classpath:dw-security-context.xml" />
<!-- ... -->

Spring-Security-context.xml :

<http pattern="/login" security="none" />
<http pattern="/accessDenied" security="none" />
<http pattern="/" security="none" />

<!-- enable use of expressions, define URL patterns and login/logout forms 
    and targets) -->
<http use-expressions="true" access-denied-page="/accessDenied">
    <intercept-url pattern="/*" access="hasRole('ROLE_USER')" />
    <!-- more stuff -->
</http>

<!-- a lot more... -->

manager-datasource just sets up the database…


Thank's for reading it all and hopefully helping me.. 😉


edit: some more info

I can't just skip the ContextLoaderListener, it is required by SpringSecurity. I also cannot skip the contextConfigLocation as this is the context required by the ContextLoaderListener. I just define the name myself else it will search for an applicationContext.xml. Maybe I can add an empty contextConfigLocation? But that probably just means, that underlying modules won't find their beans to inject..?


edit2

I think the main problem is that SpringSecurity needs a webapp context (ContextLoaderListener) to work but the web application is running inside the servlet context. The controller methods get mapped by the servlet context and thus spring security running "outside" the servlet context doesn't get notified by the event and the filter doesn't kick in..

Best Answer

Sigh.. I don't know why it didn't work the first time around, probably the wrong solution was in the cache while trying the correct one.. However it's working now just the way I posted it. Thank's Arun for your time.

Only problem now: spring-test-mvc does not support Spring Security's FilterChain but that's another question..