Printemps de Démarrage + Sécurité + Thymeleaf et jeton CSRF pas injecté automatiquement

Avertissement: je sais comment injecter le jeton dans un formulaire avec thymeleaf manuellement avec ceci:

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />`

Le but de ce post est d'améliorer la connaissance de la plate-forme et d'obtenir une meilleure compréhension de ce qui se passe à l'intérieur de Printemps de Démarrage

Je n'ai pas essayé de Printemps de Démarrage, mais récemment, j'ai décidé de lui donner un essai, et dois avouer son impressionnant, mais avec Thymeleaf et de la Sécurité sur Spring MVC, je n'ai pas besoin d'injecter de jeton CSRF sur les formes (POST), car Thymeleaf a pris soin d'elle automatiquement, mais, dès le Printemps de Démarrage pour une raison quelconque, il ne le fait pas.

De la Printemps De Démarrage De Référence, j'ai trouvé une liste de propriétés communes utilisé sur demande.fichier de propriétés, et ceux liés à la thymeleaf et de la sécurité sont:

Thymeleaf Propriétés

spring.thymeleaf.check-template-location=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.excluded-view-names= # comma-separated list of view names that should be excluded from resolution
spring.thymeleaf.view-names= # comma-separated list of view names that can be resolved
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html # ;charset=<encoding> is added
spring.thymeleaf.cache=true # set to false for hot refresh

Propriétés De Sécurité

security.user.name=user # login username
security.user.password= # login password
security.user.role=USER # role assigned to the user
security.require-ssl=false # advanced settings ...
security.enable-csrf=false
security.basic.enabled=true
security.basic.realm=Spring
security.basic.path= # /**
security.basic.authorize-mode= # ROLE, AUTHENTICATED, NONE
security.filter-order=0
security.headers.xss=false
security.headers.cache=false
security.headers.frame=false
security.headers.content-type=false
security.headers.hsts=all # none /domain /all
security.sessions=stateless # always /never /if_required /stateless
security.ignored= # Comma-separated list of paths to exclude from the     default secured paths

Mais si la solution pour faire Thymeleaf injecter le jeton est de nouveau là, je n'arrive pas à le voir.

Modifier: ajout de ma configuration

Le projet a été créé à l'aide de l'initialiseur, qui a été livré au la dernière version STS (qui à mon avis est génial), avec le Web, Thymeleaf, la Sécurité, la JPA, MySQL, H2, Mail, Facebook, Twitter, LinkedIn et de l'Actionneur éléments vérifiés, et a ajouté quelques extras aftwerwards

À l'aide de Java 7 et Tomcat 7, parce que j'ai l'intention de déployer le projet sur Openshift dans un proche avenir, et à côté il y a ma config fichiers:

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.3.RELEASE</version>
    <relativePath/>
</parent>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <start-class>com.adrisasws.springmvc.WebApplication</start-class>
    <java.version>1.7</java.version>
    <tomcat.version>7.0.59</tomcat.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.spring.platform</groupId>
            <artifactId>platform-bom</artifactId>
            <version>1.1.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity3</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.social</groupId>
        <artifactId>spring-social-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-social-facebook</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-social-linkedin</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-social-twitter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.social</groupId>
        <artifactId>spring-social-google</artifactId>
        <version>1.0.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
<profiles>
    <profile>
        <id>openshift</id>
        <build>
            <finalName>webapp</finalName>
            <plugins>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.1.1</version>
                    <configuration>
                        <outputDirectory>webapps</outputDirectory>
                        <warName>ROOT</warName>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Sécurité config (exactement le même fichier de sécurité, je suis en utilisant un non-démarrage du projet dans lequel le jeton CSRF est injecté automatiquement)

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    //////////////////////////////////////////////////////////////////////////
    //                             DEPENDENCIES                            //
    //////////////////////////////////////////////////////////////////////////

    @Autowired private DataSource dataSource;
    @Autowired private UserRepository userRepository;


    //////////////////////////////////////////////////////////////////////////
    //                              PROPERTIES                             //
    //////////////////////////////////////////////////////////////////////////

    @Value("${custom.security.rememberme-secret}")  private String secret;
    @Value("${custom.security.rememberme-create-tables}") private String createTables;

    private final static String[] adminRequests = new String[] { ... some matchers here... };
    private final static String[] userRequests = new String[] { ... some matchers here... };
    private final static String[] publicRequests = new String[] { ...some matchers here... };


    //////////////////////////////////////////////////////////////////////////
    //                             AUTHORIZATION                           //
    //////////////////////////////////////////////////////////////////////////

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/images/**", "/js/**", "/error**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers(adminRequests).access("hasRole('"+Role.ADMIN.toString()+"')")
                .antMatchers(userRequests).access("hasRole('"+Role.USER.toString()+"')")
                .antMatchers(publicRequests).permitAll()
                .anyRequest().authenticated()
                .and()
            .requiresChannel()
                .anyRequest().requiresSecure()
                .and()
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/", false)
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login?logout")
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID")
                .permitAll()
                .and()
            .rememberMe()
                .rememberMeServices(rememberMeService())
                .and()
            .apply(new SpringSocialConfigurer());
    }


    //////////////////////////////////////////////////////////////////////////
    //                             AUTHENTICATION                          //
    //////////////////////////////////////////////////////////////////////////

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService())
            .passwordEncoder(bCryptPasswordEncoder());
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder(11);
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return new UserRepositoryUserDetailsService(userRepository);
    }

    @Bean
    public SocialUserDetailsService socialUserDetailsService() {
        return new UserRepositorySocialUserDetailsService(userDetailsService());
    }


    //////////////////////////////////////////////////////////////////////////
    //                              REMEMBER ME                            //
    //////////////////////////////////////////////////////////////////////////

    @Bean
    public JdbcTokenRepositoryImpl jdbcTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        jdbcTokenRepository.setCreateTableOnStartup(Boolean.valueOf(createTables));
        return jdbcTokenRepository; 
    }

    @Bean
    public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
        return new RememberMeAuthenticationProvider(secret);
    }

    @Bean 
    public PersistentTokenBasedRememberMeServices rememberMeService() {
        PersistentTokenBasedRememberMeServices service = 
                new PersistentTokenBasedRememberMeServices(secret, userDetailsService(), jdbcTokenRepository());
        service.setUseSecureCookie(true);
        service.setParameter("rememberme");
        service.setTokenValiditySeconds(AbstractRememberMeServices.TWO_WEEKS_S);
        return service;
    }

    @Bean
    public RememberMeAuthenticationFilter authenticationFilter() throws Exception {
        return new RememberMeAuthenticationFilter(authenticationManager(), rememberMeService());
    }
}

dans mon printemps de démarrage configt au moment liées à thymeleaf, et à des fins de développement

spring.thymeleaf.cache=false

et thymeleaf modèles ressembler à ceci (ma page de connexion à l'heure actuelle, seules les contenus pertinents pour la clarté)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
    xmlns:sec="http://www.thymeleaf.org/extras/spring-security/"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
    layout:decorator="thymeleaf/layouts/default">
<head>
    ... css and meta tags ...
</head>
<body>
        ... some html ...
        <th:block sec:authorize="isAnonymous()">
        <!-- Bad Credentials -->
        <div th:if="${param.error}" class="alert alert-danger text-center">
            Invalid username and/or password.
        </div>
        <!-- Logout -->
        <div th:if="${param.logout}" class="alert alert-success text-center">
            You have been logged out.
        </div>

        <!-- Login Form -->
        <form id="f" th:action="@{/login}" method="post" role="form" autocomplete="off">
            <!-- Username -->       
            <input type="text" class="form-control text-center" id="username" name="username" th:placeholder="#{form.login.username}" />
            <!-- Password -->
            <input type="password" class="form-control text-center" id="password" name="password" th:placeholder="#{form.login.password}" />
            <!-- Remember me -->
            <input type="checkbox" id="rememberme" name="rememberme" />
            <!-- Submit -->
            <button type="submit" class="btn btn-primary" th:utext="#{form.login.submit}">Login</button>
            <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
        </form>
        ... more html and javascript ...
</body>
</html>

Edit2 - après avoir fait un peu de débogage dans le sens Faraj Farook pointu, je trouve que, dans un projet avec la configuration que j'ai posté, au Printemps version de Démarrage, dans cette classe org.thymeleaf.spring4.requestdata.RequestDataValueProcessor4Delegate, la fonction suivante renvoie une valeur null processeur

public Map<String, String> getExtraHiddenFields(
        final RequestContext requestContext, final HttpServletRequest request) {

    final RequestDataValueProcessor processor = requestContext.getRequestDataValueProcessor();
    if (processor == null) {
        return null;
    }

    return processor.getExtraHiddenFields(request);

}

tandis que le non de Printemps version de démarrage, il renvoie un processeur qui est une instance de org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor.

Quel est votre Printemps de configuration de la Sécurité? Quel est votre pom? Quel est votre Thymeleaf fichier ressemble?
Ajouté le pom, le Printemps de Sécurité config et un échantillon de Thymeleaf modèle, désolé pour le retard

OriginalL'auteur saljuama | 2015-04-08