web-dev-qa-db-fra.com

Comment représenter le "filtre personnalisé" de Spring Security en utilisant Java?

Quelle est l'équivalent Java pour Spring Security <custom-filter> tag?

<http>
  <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>
</http>

J'ai essayé

http.addFilter( new MyUsernamePasswordAuthenticationFilter() )

où la classe étend le filtre par défaut, mais elle utilise toujours la valeur par défaut formLogin.

Mon filtre:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{

    // proof of concept of how the http.addFilter() works

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        System.out.println("running my own version of UsernmePasswordFilter ... ");

        String username = obtainUsername(request);
        String password = obtainPassword(request);

        if (username == null) {
            username = "";
        }

        if (password == null) {
            password = "";
        }

        username = username.trim();

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }
}

La pièce de configuration pertinente:

@Configuration
@EnableWebMvcSecurity  // annotate class configuring AuthenticationManagerBuilder
@ComponentScan("com.kayjed")
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      http
        .authorizeRequests()
            .antMatchers("/resources/**","/signup").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
        .logout()
            .permitAll();

      http.addFilter(new MyUsernamePasswordAuthenticationFilter());
    }

    ...
}

L'exécution de l'application MVC dans le débogueur affiche toujours l'authentification des tentatives de connexion à partir de la valeur par défaut UsernamePasswordAuthenticationFilter au lieu de mon intention d'employer la classe MyUsernamePasswordAuthenticationFilter.

Quoi qu'il en soit, je n'essaie pas d'amener quelqu'un à déboguer du code; j'aimerais plutôt voir un bon exemple en utilisant Java qui exécute l'équivalent de l'élément de filtre personnalisé dans l'approche XML. La documentation est un peu laconique.

29
user3722706

Quelques questions que vous devrez peut-être garder à l'esprit:

  1. Votre filtre doit être ajouté avant la norme UsernamePasswordAuthenticationFilter

    
    http.addFilterBefore(customUsernamePasswordAuthenticationFilter(),
            UsernamePasswordAuthenticationFilter.class)
    
  2. Si vous étendez UsernamePasswordAuthenticationFilter, votre filtre reviendra immédiatement sans rien faire sauf si vous définissez un RequestMatcher

    
    myAuthFilter.setRequiresAuthenticationRequestMatcher(
        new AntPathRequestMatcher("/login","POST"));
    
  3. Toute la configuration que vous effectuez dans http.formLogin().x().y().z() est appliquée à la norme UsernamePasswordAuthenticationFilter et non au filtre personnalisé que vous créez. Vous devrez le configurer manuellement vous-même. L'initialisation de mon filtre d'authentification ressemble à ceci:

    
    @Bean
    public MyAuthenticationFilter authenticationFilter() {
        MyAuthenticationFilter authFilter = new MyAuthenticationFilter();
        authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
        authFilter.setAuthenticationManager(authenticationManager);
        authFilter.setAuthenticationSuccessHandler(new MySuccessHandler("/app"));
        authFilter.setAuthenticationFailureHandler(new MyFailureHandler("/login?error=1"));
        authFilter.setUsernameParameter("username");
        authFilter.setPasswordParameter("password");
        return authFilter;
    }
    
33
Aner

Je ne trouve aucun problème dans ce code. Je pense que votre configuration est correcte. Le problème est ailleurs. J'ai un code similaire,

package com.programsji.config;

import Java.util.ArrayList;
import Java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import com.programsji.security.CustomAuthenticationProvider;
import com.programsji.security.CustomSuccessHandler;
import com.programsji.security.CustomUsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/theme/**").and()
                .debug(true);
    }

    @Bean
    public CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter()
            throws Exception {
        CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new CustomUsernamePasswordAuthenticationFilter();
        customUsernamePasswordAuthenticationFilter
                .setAuthenticationManager(authenticationManagerBean());
        customUsernamePasswordAuthenticationFilter
                .setAuthenticationSuccessHandler(customSuccessHandler());
        return customUsernamePasswordAuthenticationFilter;
    }

    @Bean
    public CustomSuccessHandler customSuccessHandler() {
        CustomSuccessHandler customSuccessHandler = new CustomSuccessHandler();
        return customSuccessHandler;
    }

    @Bean
    public CustomAuthenticationProvider customAuthenticationProvider() {
        CustomAuthenticationProvider customAuthenticationProvider = new CustomAuthenticationProvider();
        return customAuthenticationProvider;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        List<AuthenticationProvider> authenticationProviderList = new ArrayList<AuthenticationProvider>();
        authenticationProviderList.add(customAuthenticationProvider());
        AuthenticationManager authenticationManager = new ProviderManager(
                authenticationProviderList);
        return authenticationManager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/reportspage").hasRole("REPORT")
                .antMatchers("/rawdatapage").hasRole("RAWDATA").anyRequest()
                .hasRole("USER").and().formLogin().loginPage("/login")
                .failureUrl("/login?error")
                .loginProcessingUrl("/j_spring_security_check")
                .passwordParameter("j_password")
                .usernameParameter("j_username").defaultSuccessUrl("/")
                .permitAll().and().httpBasic().and().logout()
                .logoutSuccessUrl("/login?logout").and().csrf().disable()
                .addFilter(customUsernamePasswordAuthenticationFilter());
    }

}

Cela fonctionne bien sur ma demande. vous pouvez télécharger l'intégralité de ce projet à partir de l'url: https://github.com/programsji/rohit/tree/master/UsernamePasswordAuthenticationFilter

4
programsji.com

Essayez d'ajouter @Component à votre classe MyUsernamePasswordAuthenticationFilter.

Cette annotation rend la classe considérée comme candidate à l'auto-détection, voir: @ Component


Pour ça:

<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>

Vous pouvez ajouter ceci:

.addFilter[Before|After](authenticationTokenProcessingFilter, UsernamePasswordAuthenticationFilter.class)

Voir: Alias ​​de filtre standard et commande

2
Denis C de Azevedo