Saqib Javed
Saqib Javed

Reputation: 177

Spring Custom filter chain

I am writing my own filter chain to dynamically load user roles from database and filter the urls

application works fine when i properly login to the application using login page

but when i try to access some protected url that requires authentication instead of being redirected to the login page; i am getting a class cast exception.

debugging shows me that String "anonymousUser" is returned instead of my domain principal object :(

java.lang.ClassCastException: java.lang.String cannot be cast to com.mytech.myapp.model.MyAppUser at com.mytech.myapp.web.controller.helper.LeftMenuHelper.getManageLeftMenu(LeftMenuHelper.java:171) at com.mytech.myapp.web.controller.ManageController.setLeftTree(ManageController.java:1377) at com.mytech.myapp.web.controller.ManageController.renderManagePage(ManageController.java:379) at com.mytech.myapp.web.controller.ManageController.handleNoSuchRequestHandlingMethod(ManageController.java:371) at org.springframework.web.servlet.mvc.multiaction.MultiActionController.handleRequestInternal(MultiActionController.java:413) at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153) at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501) at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378) at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109) at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390) at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105) at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) at

my security xml is as follows

    <?xml version="1.0" encoding="UTF-8"?>

<b:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:sec="http://www.springframework.org/schema/security"
    xmlns:b="http://www.springframework.org/schema/beans"
    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">

    <b:bean id="springSecurityFilterChain" class="org.springframework.security.util.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/brands/**" filters="none" />
            <sec:filter-chain pattern="/javascript/**" filters="none" />
            <sec:filter-chain pattern="/index.html" filters="none" />
            <sec:filter-chain pattern="/login.do" filters="none" />
            <sec:filter-chain pattern="/forgotPassword.do" filters="none" />
            <sec:filter-chain pattern="/ws/restapi/**" filters="none" />
            <sec:filter-chain pattern="/**" filters="
                httpSessionContextIntegrationFilter,
                logoutFilter,
                preAuthFilter,
                authenticationProcessingFilter,
                anonymousProcessingFilter,
                filterSecurityInterceptor
            "/>
        </sec:filter-chain-map>
    </b:bean>
    <!--
    -->

    <b:bean id="anonymousProcessingFilter" class="org.springframework.security.providers.anonymous.AnonymousProcessingFilter">
        <b:property name="key" value="foobar" />
        <b:property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS" />
    </b:bean>

    <b:bean id="anonymousAuthenticationProvider" class="org.springframework.security.providers.anonymous.AnonymousAuthenticationProvider">
        <b:property name="key" value="foobar" />
    </b:bean>

    <b:bean id="httpSessionContextIntegrationFilter" class="org.springframework.security.context.HttpSessionContextIntegrationFilter">
        <sec:custom-filter position="SESSION_CONTEXT_INTEGRATION_FILTER"/>
    </b:bean>

    <b:bean id="logoutFilter" class="org.springframework.security.ui.logout.LogoutFilter">
        <b:constructor-arg value="/login.do?code=logout" />
        <b:constructor-arg>
            <b:list>
                <b:ref bean="securityContextLogoutHandler" />
            </b:list>
        </b:constructor-arg>
        <sec:custom-filter position="LOGOUT_FILTER"/>
    </b:bean>

    <b:bean id="securityContextLogoutHandler" class="org.springframework.security.ui.logout.SecurityContextLogoutHandler" />

    <b:bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
        <sec:custom-filter position="FILTER_SECURITY_INTERCEPTOR"/>
        <b:property name="authenticationManager" ref="authenticationManagerAlias" />
        <b:property name="accessDecisionManager" ref="accessDecisionManager" />
        <b:property name="objectDefinitionSource" ref="MyAppRoleUrlFilterSource" />
    </b:bean>

    <b:bean id="MyAppRoleUrlFilterSource" class="com.softech.myapp.web.filter.MyAppRoleUrlFilterSource">
    </b:bean>

    <b:bean id="accessDecisionManager" class="org.springframework.security.vote.UnanimousBased">
        <b:property name="decisionVoters" ref="roleVoter" />
    </b:bean>

    <b:bean id="roleVoter" class="org.springframework.security.vote.RoleVoter">
        <b:property name="rolePrefix" value="" />
    </b:bean>

    <b:bean id="preAuthFilter" class="com.softech.myapp.web.filter.MyAppRequestPreAuthFilter">
        <sec:custom-filter position="PRE_AUTH_FILTER" />
        <b:property name="principalRequestHeader" value="MYAPP_AUTH_USER_TOKEN" />
        <b:property name="authenticationManager" ref="authenticationManagerAlias" />
        <b:property name="authenticationDetailsSource" ref="userDetailsService"></b:property>

        <b:property name="preAuthEntryUrl" value="/interceptor.do"></b:property>
        <b:property name="listenFrom" value="*"></b:property>
    </b:bean>

    <b:bean id="preAuthProvider" class="org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider">
        <sec:custom-authentication-provider />
        <b:property name="preAuthenticatedUserDetailsService">
            <b:bean id="userDetailsServiceWrapper" class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
                <b:property name="userDetailsService" ref="userDetailsService" />
            </b:bean>
        </b:property>
    </b:bean>

    <b:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
        <b:property name="loginFormUrl" value="/login.do"/>
        <b:property name="forceHttps" value="false" />
    </b:bean>

    <sec:authentication-manager alias='authenticationManagerAlias'/>
    <b:bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
        <b:property name="providers">
            <b:list>
                <b:ref local="secureDaoAuthenticationProvider"/>
                <b:ref local="daoAuthenticationProvider"/>
            </b:list>
        </b:property>
    </b:bean>

    <b:bean id="authenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
        <sec:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
        <b:property name="defaultTargetUrl" value="/interceptor.do"/>
        <b:property name="authenticationFailureUrl" value="/login.do"/>
        <b:property name="authenticationManager" ref="authenticationManagerAlias"/>
        <b:property name="authenticationDetailsSource" ref="myAppUserAuthenticationDetailsSource"/>
        <b:property name="alwaysUseDefaultTargetUrl" value="true"/>
    </b:bean>    

    <!-- <authentication-provider user-service-ref="userDetailsService"/> -->
    <!-- the SHA-1 password encoder -->
    <b:bean id="secureDaoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
        <b:property name="userDetailsService" ref="userDetailsService"/>
        <b:property name="passwordEncoder" ref="passwordEncoder"/>
        <b:property name="saltSource" ref="saltSource"/>
        <sec:custom-authentication-provider/>  
    </b:bean>   

    <!-- Plain Text password encoder - the default -->
    <b:bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
        <b:property name="userDetailsService" ref="userDetailsService"/>
        <sec:custom-authentication-provider/>  
    </b:bean>

    <b:bean id="myAppUserAuthenticationDetailsSource" class="org.springframework.security.ui.WebAuthenticationDetailsSource">
        <b:property name="clazz" value="com.softech.myapp.web.filter.MyAppUserAuthenticationDetails"/>
    </b:bean>   

   <!-- Automatically receives AuthenticationEvent messages -->
   <b:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>

</b:beans>

Upvotes: 3

Views: 6333

Answers (1)

Maksym Demidas
Maksym Demidas

Reputation: 7817

"Redirected to the login page" feature depends on two filters:

  • FilterSecurityInterceptor - check security rules, throw AccessDeniedException
  • ExceptionTranslationFilter - catch AccessDeniedException and start authentication in a case of anonymous user

As I can see ExceptionTranslationFilter is absent in your conf. So please add it to your filter chain. The order is very important, it must be inserted before FilterSecurityInterceptor.

Upvotes: 2

Related Questions