Simple web application with Spring Security: Part 13

In the last few pages on spring security series, I was about to tackle method-level security and domain-instance security using spring security; But before doing this, I am going to go back to basics and explore the basics of spring security in a deeper way.

Back to basics

We are going to revert to simplest configuration first of all:

In our springsecuritywebapp-servlet.xml file, we remove the configuration for the aclDemoController for now and any reference to it within the file.

In our web.xml:

We configure a listener to load the context of the web application at start up. This will load our applicationContext-security.xml file.

We register a filter named springSecurityFilterChain that delegates all requests matching the url pattern ‘/*’ to a DelegatingFilterProxy.

<!--
- Location of the XML file that defines the root application context -
Applied by ContextLoaderListener.
-->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		    WEB-INF\applicationContext-security.xml
        </param-value>
</context-param>

<!--
- Loads the root application context of this web app at startup. - The
application context is then available via -
WebApplicationContextUtils.getWebApplicationContext(servletContext).
-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<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>

In our applicationContext-security.xml we leave it empty like so:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">

</beans:beans>

Build and deploy

The application builds ok and deploys to tomcat. However it fails when starting up on tomcat due to:

SEVERE: Error filterStart
SEVERE: Context [/springsecuritywebapp] startup failed due to previous errors

Looking in the tomcat logs we see the following error:

23/12/2008 18:33:28 org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:387)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:971)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:246)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:884)
	at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:216)
	at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:145)
	at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:179)

Clearly the problem is that we haven’t configured any bean named ‘springSecurityFilterChain’.

Fixing springSecurityFilterChain problem

If we use the <http> configuration element it should auto create a default springSecurityFilterChain.

We update our applicationContext-security.xml to look like so:

<http auto-config="false" session-fixation-protection="none">
</http>

When we build and deploy this we get another problem:

org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: No AuthenticationEntryPoint could be established. Please make sure you have a login mechanism configured through the namespace (such as form-login) or specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute
Offending resource: ServletContext resource [/WEB-INF/applicationContext-security.xml]
	at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
	at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:72)

So spring security is failing fast as it expects us to have some form of authentication mechanism:

We update our applicationContext-security.xml to look like so:

<http auto-config="false" session-fixation-protection="none">
    <form-login login-page="/login.jsp" default-target-url="/home.htm" />
</http>

Building and deploy, we see another problem reported on tomcat:

org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_authenticationManager': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: No authentication providers were found in the application context

So spring security expects an authentication provider to be configured to facilitate the form login via an AuthenticationManager that is being automatically created by spring security and named _authenticationManager.

So we update our applicationContext-security.xml again to add the following snippet:

<authentication-provider>
   <user-service id="userDetailsService">
      <user password="password" name="username" authorities="ROLE_USER" />
   </user-service>
</authentication-provider>

Building and deploying again, we see from the tomcat logs that the application has started successfully. The authentication through form login (which is all we have configured) works as it should.

How it works behind the scenes

When the applications starts correctly using the configuration laid out as above, see see from the tomcat logs the following details:

INFO: Pre-instantiating singletons in
org.springframework.beans.factory.support.DefaultListableBeanFactory@195afdb: defining beans
[
_authenticationManager,
_filterChainProxy,
_httpSessionContextIntegrationFilter,
_filterChainProxyPostProcessor,
_filterChainList,
_securityContextHolderAwareRequestFilter,
_accessManager,
_portMapper,
_exceptionTranslationFilter,
_filterSecurityInterceptor,
_formLoginFilter,
_formLoginEntryPoint,
_entryPointInjectionBeanPostProcessor,
_userServiceInjectionPostProcessor,
org.springframework.security.providers.dao.DaoAuthenticationProvider#0,
userDetailsService,
org.springframework.security.config.AuthenticationProviderBeanDefinitionParser$AuthenticationProviderCacheResolver#0
]; root of factory hierarchy

What is happening is that from that small amount of configuration, spring security is instantiating a number of beans to enable the functionality. Of special interest is the _filterChainProxy. From the logs, we see the FilterChainProxy is configured as:

INFO: FilterChainProxy: FilterChainProxy[
UrlMatcher = org.springframework.security.util.AntUrlPathMatcher[requiresLowerCase='true']; Filter Chains: {/**=[
org.springframework.security.context.HttpSessionContextIntegrationFilter[ order=200; ],
org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ],
org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter[ order=1100; ],
org.springframework.security.ui.ExceptionTranslationFilter[ order=1400; ],
org.springframework.security.intercept.web.FilterSecurityInterceptor@1cd6a32]
}]

Following a HTTP Request

As an example, I try to visit the following page on the application: http://localhost:8080/springsecuritywebapp/login.jsp. This requests starts off its journey navigating through the apache tomcat container:

http-request-stack-trace-tomcat-springsecurity

Apache tomcats ApplicationFilterChain.doInternalChain method retrieves filter configured in our web.xml.

ApplicationFilterConfig[name=springSecurityFilterChain, filterClass=org.springframework.web.filter.DelegatingFilterProxy]

It then uses the filter [ of type DelegatingFilterProxy] and invokes doFilter on this passing the request and response types. As the DelegatingFilterProxy’s javadoc states:

This approach is particularly useful for Filter implementation with complex setup needs, allowing to apply the full Spring bean definition machinery to Filter instances. Alternatively, consider standard Filter setup in combination with looking up service beans from the Spring root application context.

And this is its purpose here, to delegate to a FilterChainProxy for which a bean is already instantiated (_filterChainProxy). This is then responsible for filtering the request through each of filters that are part of its VirtualFilterChain.

From our initial configuration set up for spring security, we have have five filters that are part of FilterChainProxys VirtualFilterChain. These are in order of execution:

  1. HttpSessionContextIntegrationFilter
  2. AuthenticationProcessingFilter
  3. SecurityContextHolderAwareRequestFilter
  4. ExceptionTranslationFilter
  5. FilterSecurityInterceptor

In the next part I will talk about what happens to our request to reach http://localhost:8080/springsecuritywebapp/login.jsp in each of these filters.

Getting the code

For this part I haven’t committed code to our code on svn as of yet as the changes are all documented here and very quick and simple.

11 Responses to “Simple web application with Spring Security: Part 13”

  1. marcKun Says:

    cool man.. very detailed walk thru… thanks a million

  2. madhava Says:

    hi can u please explain how spring security filter c hain works ,i need to add custom filter (password change filter to be called when credentials are expired)

  3. Dham Says:

    Hay,

    Thanks for posting such an useful article. its short, sweet n perfect.. i have jst solved a lot of erroneous phases though this.. nice work man.. keep it up..
    Cheers!!

  4. Amit Patel Says:

    Very good explanation. It is very useful
    Thanks!

  5. Ron Says:

    Hey,

    Thanks a lot for so compact and useful knowledge sharing on springSecurityFilterChain.

  6. Indroniel Deb Roy Says:

    Great walk through of “springSecurityFilterChain” … It helped me to understand the spring security model better!!

  7. stanley Says:

    Thank you!
    spring always gracefully fails without giving warnings.
    and the way it works are mostly magical (black box)..
    the official documentation lacks of warning from the impending doom…

  8. lwpro2 Says:

    have anyone have anyidea, on how the entry-point configuration would be invoked?

    as for custom filter, i think you can define the bean, following the strict naming requirement, and specify the custom-filter position, like <bean id=”authenticationProcessingFilter” scope=”prototype”
    class=”com.best2jj.myFilter”>
    <security:custom-filter position=”PRE_AUTH_FILTER” />
    <property name=”authenticationManager” ref=”authenticationManager” />
    </bean>

  9. lkafle Says:

    great article

  10. Yesu Raj Says:

    good post

  11. Exception while web application deployment: No bean named ‘springSecurityFilterChain’ is defined - All Tech In One Says:

    […] https://heraclitusonsoftware.wordpress.com/software-development/spring/simple-web-application-with-sp… […]

Leave a comment