eis
eis

Reputation: 53462

How to have spring security context in child context

I'm trying to have spring security context in child context, so I could have url security on the servlet context file.

I have:

  <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>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/spring-security.xml
    </param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>myapp-soap</servlet-name>
    <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
    <init-param>
      <param-name>transformWsdlLocations</param-name>
      <param-value>true</param-value>
    </init-param>
  </servlet>

on web.xml, general security configuration on spring-security.xml and

<!-- Authorization configurations -->
<security:http auto-config="false" use-expressions="true"
    create-session="never"
    authentication-manager-ref="authenticationManager"
    entry-point-ref="authenticationEntryPoint">

    <security:custom-filter
        position="PRE_AUTH_FILTER" ref="serviceAuthenticationFilter"/>

    <security:intercept-url
        pattern="/GetForbiddenUrl" access="hasRole('roleThatDoesntExist')" />
    <security:intercept-url pattern="/**" access="permitAll" />
</security:http>
<!-- annotation security -->
<security:global-method-security pre-post-annotations="enabled"/>

on the myapp-soap-servlet.xml. It doesn't work but fails with

ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/my-app/v1/soap]] (ServerService Thread Pool -- 192) JBWEB000284: Exception starting filter springSecurityFilterChain:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined

However, if I move <security:http> part to spring-security root context configuration, everything works. Shouldn't it work the way I try? How can I get url-based security in my child context?

I also tried combining the context files into one, but the same problem seems to occur.

Upvotes: 9

Views: 7104

Answers (2)

Rob Winch
Rob Winch

Reputation: 21720

The DelegatingFilterProxy will by default look in the root ApplicationContext which means by default you need to place your <http> configuration there (it is what creates the springSecurityFilterChain).

However, you can specify use that DelegatingFilterProxy a different ApplicationContext by specifying the contextAttribute for it to use. To do this update your web.xml as shown below

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>contextAttribute</param-name>
        <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.myapp-soap</param-value>
    </init-param>
</filter>

A similar example using Spring Security 3.2+'s AbstractSecurityWebApplicationInitializer can be seen below:

public class SecurityApplicationInitializer extends
        AbstractSecurityWebApplicationInitializer {

    @Override
    protected String getDispatcherWebApplicationContextSuffix() {
        // NOTE: if you are using AbstractDispatcherServletInitializer or
        // AbstractAnnotationConfigDispatcherServletInitializer You probably
        // want this value to be "dispatcher"
        return "myapp-soap";
    }

}

This works because it modifies the name of the ServletContext attribute that DelegatingFilterProxy uses to lookup the ApplicationContext. Instead of using the default value which discovers the root ApplicationContext it now uses the attribute that your MessageDispatcherServlet is using (thus pointing to the child context).

Note that MessageDispatcherServlet's (or any subclass of FrameworkServlet such as DispatcherServlet) stores the ApplicationContext in the ServletContext using the attribute name "org.springframework.web.servlet.FrameworkServlet.CONTEXT." + <servlet-name> where <servlet-name> is the name of the servlet. So in this instance, the attribute that must be configured is org.springframework.web.servlet.FrameworkServlet.CONTEXT.myapp-soap. If you changed the servlet-name from myapp-soap to spring-servlet, then you would use org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring-servlet instead.

PS I think the subject should read "How to have spring security context as child context"

Upvotes: 19

zagyi
zagyi

Reputation: 17518

<security:http> will have to go to the main application context instead of the child (servlet) context, because this security namespace element creates the springSecurityFilterChain bean, which is looked up by DelegatingFilterProxy in the main context. As its javadoc clearly states:

web.xml will usually contain a DelegatingFilterProxy definition, with the specified filter-name corresponding to a bean name in Spring's root application context.

Upvotes: 2

Related Questions