1

I have a small Spring/ JSF/ JDBC webapp, which worked fine until Spring Security was added. Since adding the springsecurityfilterchain, the sign-up button (as opposed to sign-in) on the login/welcome screen does not work anymore. the JSF primefaces loading bar appears, but stays indefinitely without transitioning to the next page. My initial investigation leads me to believe it has something to do with the springsecurityfilterchain, as commenting in/out this piece of code basically turns the problem on/off.

Any help is much appreciated.

Code: web.xml

    <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>KimaPortal</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>Resources Servlet</servlet-name>
    <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Resources Servlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
  </servlet-mapping>
  <servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value></param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/app/*</url-pattern>
  </servlet-mapping>
  <filter>
    <filter-name>charEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>charEncodingFilter</filter-name>
    <url-pattern>*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
  <context-param>
    <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>
  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
  </context-param>
  <listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
  </listener>

  <!--  Spring security filters -->
  <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>



</web-app>

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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.xsd">

<import resource="datasource-config.xml" />
<import resource="webflow-config.xml"/>
<import resource="security-config.xml"/>

<!-- <bean id="userEntity" class="org.bluprnt.KimaPortal.domain.UserEntity"/> -->
<bean id="userEntityServices" class="org.bluprnt.KimaPortal.domain.UserEntityServices">
    <property name="authenticationManager" ref="authenticationManager" />
</bean> 

<bean id="applicationContextProvider" class="org.bluprnt.KimaPortal.domain.ApplicationContextProvider"/>

</beans>

webflow-config.xml

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

<bean id="facesContextListener" class="org.springframework.faces.webflow.FlowFacesContextLifecycleListener">
</bean>

<!-- <bean id="jpaFlowExecutionListener" class="org.springframework.webflow.persistence.JpaFlowExecutionListener"> -->
<!-- <constructor-arg ref="entityManagerFactory" /> -->
<!-- <constructor-arg ref="transactionManager" /> -->
<!-- </bean> -->

<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="facesContextListener"/>
<webflow:listener ref="securityFlowExecutionListener" />
<!-- <webflow:listener ref="jpaFlowExecutionListener" /> -->
</webflow:flow-execution-listeners>
</webflow:flow-executor> 

<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices" base-path="WEB-INF/flows">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>

<faces:flow-builder-services id="facesFlowBuilderServices" development="true"/>

<faces:resources/>

<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="1"/>
<property name="flowRegistry" ref="flowRegistry"/>
<property name="defaultHandler">
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
</property>
</bean>

<bean class="org.springframework.faces.webflow.JsfFlowHandlerAdapter">
<property name ="flowExecutor" ref="flowExecutor" />
</bean>

<bean id="faceletsViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.faces.mvc.JsfView" />
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".xhtml" />
</bean>

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

<bean id="securityFlowExecutionListener"
      class="org.springframework.webflow.security.SecurityFlowExecutionListener" />


</beans>

security-config.xml

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

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">

<security:http auto-config="true">
    <security:form-login login-page="/app/main"  default-target-url="/app/account" />
    <security:logout logout-url="/app/logout" logout-success-url="/app/main" />
</security:http>

<security:authentication-manager>
    <security:authentication-provider user-service-ref="userEntityServices">
        <security:password-encoder hash="md5"/>
    </security:authentication-provider>
</security:authentication-manager>

<bean id="userEntityAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <property name="userDetailsService" ref="userEntityServices" />
    <property name="hideUserNotFoundExceptions" value="false"/>
</bean>

<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <constructor-arg>
        <ref bean="daoAuthenticationProvider" />
    </constructor-arg>
</bean>   

<bean id="daoAuthenticationProvider"
    class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userEntityServices"/>
</bean>

</beans> 

main-flow.xml

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

<flow xmlns="http://www.springframework.org/schema/webflow"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/webflow
        http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"> 

    <var name="user" class="org.bluprnt.KimaPortal.domain.UserEntity" />



    <view-state id="welcome" view="welcome.xhtml">
        <transition on="newUser" to="signUp"/>
    </view-state>

    <view-state id="signUp" view="signUp.xhtml" model="user">
        <transition on="backToSignIn" to="welcome"/>
        <transition on="confirmSignUp" to="authentication">
        <evaluate expression="userEntityServices.createUserEntity(user)" />
        </transition>
    </view-state>

    <action-state id="authentication">
        <evaluate expression="userEntityServices.authenticateUser(user)" />
        <transition on="yes" to="authenticationSuccessful" />
        <transition on="no" to="welcome" />
    </action-state>

    <end-state id="authenticationSuccessful" view="externalRedirect:account" />

</flow> 

account-flow.xml

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

<!-- use spring roles tables TO DO -->
<secured attributes="ROLE_USER"/>

    <view-state id="userHome" view="authenticatedWelcome.xhtml">
    </view-state>

</flow>

UserEntityServices.java

package org.bluprnt.KimaPortal.domain;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.*;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.DataSourceUtils;

public class UserEntityServices implements UserDetailsService {
    private ApplicationContext ctx;
    private DataSource ds;
    private Connection c;
    private AuthenticationManager authenticationManager;


    public void createUserEntity(UserEntity user) {
        try {
            // Check if user exists
            if (checkIfUserExists(user) == false){
                createDBConnectionIfNA();
                    // retrieve a list of three random cities
                String statement = new String("insert into kima_users " +
                "values ('" + user.getUserName() +"', '" 
                        + user.getPassword() + "', '" 
                        + user.getFirstName() + "', '" 
                        + user.getLastName() + "');");
                System.out.println(statement);
                PreparedStatement ps = c.prepareStatement(statement);
                ps.execute();

            } else {
                // throw error about user already existing
                // TO DO !!
            }
        } catch (SQLException ex) {
            // something has failed and we print a stack trace to analyze the error
            ex.printStackTrace();
            // ignore failure closing connection
                    try { c.close(); } catch (SQLException e) { }
        } finally {
            // properly release our connection
            DataSourceUtils.releaseConnection(c, ds);
            this.c = null;
            this.ds = null;
        }

    }

    public boolean checkIfUserExists (UserEntity user){
        try {
            createDBConnectionIfNA();
            // SQL statement to check whether username already exists in DB
            String statement = new String("select * from kima_users where userName = '" + user.getUserName() + "' ");
            System.out.println(statement);
            PreparedStatement ps = c.prepareStatement(statement);
            ResultSet rs = ps.executeQuery();
            if (!rs.next()){
                    //user does not exist
                    return false;
                }else{
                    //user exists
                    return true;
                }
        } catch (SQLException ex) {
            // something has failed and we print a stack trace to analyze the error
            ex.printStackTrace();
            // ignore failure closing connection
            try { c.close();} catch (SQLException e) { }
        } finally {
            // properly release our connection
            DataSourceUtils.releaseConnection(c, ds);
            this.c = null;
            this.ds = null;
        }
        //conservative guaranteed return value
        return true;
    }


    //method to retrieve userEntity from DB by user name
    public UserEntity getUserFromDBByUserName (String userName) {
        try {
            UserEntity user = new UserEntity();
            createDBConnectionIfNA();
            String statement = new String("select * from kima_users where userName = '" + userName + "' ");
            System.out.println(statement);
            PreparedStatement ps = c.prepareStatement(statement);
            ResultSet rs = ps.executeQuery();
            user.setUserName(rs.getString("userName"));
            user.setPassword(rs.getString("password"));
            user.setFirstName(rs.getString("firstName"));
            user.setLastName(rs.getString("lastName"));
            return user;
        } catch (SQLException ex) {
            // something has failed and we print a stack trace to analyse the error
            ex.printStackTrace();
            // ignore failure closing connection
            try { c.close();} catch (SQLException e) { }
        } finally {
            // properly release our connection
            DataSourceUtils.releaseConnection(c, ds);
            this.c = null;
            this.ds = null;
        }
        return null;
    }


    //method for user authentication as part of login procedure main-flow to account-flow
    public boolean authenticateUser (UserEntity user){
        System.out.println("2");
        try {
        Authentication request = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        //authenticationManager.authenticate calls loadUserByUsername(username)
        Authentication result =  authenticationManager.authenticate(request);
        SecurityContextHolder.getContext().setAuthentication(result);
        return true;
        } catch(AuthenticationException e){
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(), "Sorry!"));
            return false;
        }
    }

    public AuthenticationManager getAuthenticationManager() {
        return authenticationManager;
    }

    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }


    //userDetailsService implementation for spring security
    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        System.out.println("1");
        UserEntity user = getUserFromDBByUserName(userName);
        if (user == null){
            throw new UsernameNotFoundException(String.format("No such user with name '%s'", userName));
        }
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        User userDetails = new User(user.getUserName(), user.getPassword(), authorities);
        return userDetails;

    }

    // method to create DB connection and to pass on applicationContext, dataSource and Connection as instance variable
    // ATTENTION: dataSource and connection to be closed after query is execute
    private void createDBConnectionIfNA(){
        // check whether there is an existing connection - create one if not
        if (!(this.ctx != null && this.ds != null && this.c != null)) {
            // Create a new application context. this processes the Spring config
            ApplicationContextProvider acp = new ApplicationContextProvider();
            ApplicationContext ctx = acp.getApplicationContext();
            // Retrieve the data source from the application context
            DataSource ds = (DataSource) ctx.getBean("dataSource");
            // Open a database connection using Spring's DataSourceUtils
            java.sql.Connection c = DataSourceUtils.getConnection(ds);
            //pass on connection objects to instance variables
            this.ctx = ctx;
            this.ds = ds;
            this.c = c;
        }
    }

}

pom.xml includes following dependencies (truncated due to size limit):

<org.springframework.version>4.2.4.RELEASE</org.springframework.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat-maven-plugin</artifactId>
      <version>2.2</version>
      <type>pom</type>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.1.1</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.6</version>
        <type>maven-plugin</type>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.webflow</groupId>
        <artifactId>spring-faces</artifactId>
        <version>2.4.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-api</artifactId>
        <version>2.2.13</version>
    </dependency>
    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>5.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.sun.facelets</groupId>
        <artifactId>jsf-facelets</artifactId>
        <version>1.1.14</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>com.sun.faces</groupId>
        <artifactId>jsf-impl</artifactId>
        <version>2.2.13</version>
    </dependency>
    <dependency>
        <groupId>antlr</groupId>
        <artifactId>antlr</artifactId>
        <version>2.7.7</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>2.0.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.5.6</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>2.5</version>
        <type>pom</type>
    </dependency>

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.webflow</groupId>
        <artifactId>spring-webflow</artifactId>
        <version>2.4.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>
  </dependencies>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Fonderman
  • 11
  • 3

1 Answers1

0

We ran into the exact same problem. The issue originates in the Spring filter-chain. When enabling spring-security you added new filter-chain components in web.xml like this:

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

This causes a complete set of filters to be added. One of these filters is to prevent CSRF (Cross-site Request Forgery). Somehow the combination of webflow-2 and spring-security causes the CSRF tokens to go missing in the processing chain. This becomes evident when looking at the respective log sections where the filter chain is stopped in the CsrfFilter.

DEBUG 2016-07-25 06:47:59,013 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 1 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG 2016-07-25 06:47:59,013 (HttpSessionSecurityContextRepository.java:171) - HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG 2016-07-25 06:47:59,014 (HttpSessionSecurityContextRepository.java:101) - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@42281bdb. A new one will be created.
DEBUG 2016-07-25 06:47:59,014 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 2 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG 2016-07-25 06:47:59,014 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG 2016-07-25 06:47:59,014 (HstsHeaderWriter.java:128) - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@481c2a9e
DEBUG 2016-07-25 06:47:59,014 (FilterChainProxy.java:324) - /start-flow.do?execution=e1s1 at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG 2016-07-25 06:47:59,015 (CsrfFilter.java:106) - Invalid CSRF token found for http://localhost:8080/center/start-flow.do?execution=e1s1

In the last line it is clearly shown that the last filter executed is CsrfFilter which is filter 4 out of 14 in our setup. It throws an error Invalid CSRF token found for .... and cancels the filter chain. If we set a breakpoint in CsrfFilter we can also clearly see that the csrfToken is in fact null.

As a quick fix we now just disabled CSRF and are happy with that:

<security:http auto-config="true" use-expressions="true">
    <!-- CSRF: Cross-site request forgery must be DISABLED when using web-flow!
         Web-flow request do not provide correct CSRF tokens!!! -->
    <security:csrf disabled="true"/>
    <security:intercept-url pattern="/**" access="permitAll" />
    <security:intercept-url pattern="/secure/**" access="hasRole('ROLE_USER')" />
    <security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
</security:http>

As of now I am afraid if you require CSRF you need to provide your own fix. There are discussions on SO regarding CSRF in webflow-2 see: here (has some security concerns detailed here).

Community
  • 1
  • 1
Matthias Steinbauer
  • 1,786
  • 11
  • 24