web-dev-qa-db-fra.com

Fournisseur d'authentification personnalisé non appelé

J'essaie d'installer un client AuthenticationProvider avec Spring Security, mais je n'ai pas beaucoup de chance de le faire fonctionner. J'utilise configuration Java donc il me manque probablement quelque chose de simple, mais comme la plupart des supports d'apprentissage sont basés sur la configuration XML, ils ne me sautent pas aux yeux.

Ceci utilise Spring v4.0.1.RELEASE mais avec Spring Security v3.2.2.RELEASE. Numéro de version choc peut-être?

Autant que je sache, tout ce que j'avais à faire était de créer mon fournisseur:

public class KBServicesAuthProvider implements AuthenticationProvider {
  @Autowired
  private ApplicationConfig applicationConfig;

  @Autowired
  private SessionServiceClient sessionServiceClient;

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String email = (String) authentication.getPrincipal();
    String password = (String) authentication.getCredentials();

    try {
      KBSessionInfo sessionInfo = sessionServiceClient.login(applicationConfig.getKbServicesPresenceId(), email,
          password);

      List<GrantedAuthority> grantedRoles = new ArrayList<>();
      for (KBRoleMembership role : sessionInfo.getAuthenticatedUser().getRoleMemberships()) {
        grantedRoles.add(new SimpleGrantedAuthority(role.getRoleId()));
      }

      return new UsernamePasswordAuthenticationToken(email, password, grantedRoles);
    } catch (InvalidSessionException e) {
      throw new AuthenticationCredentialsNotFoundException("Username or password was not accepted", e);
    }
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
  }
}

Et ensuite, configurez une classe pour décrire ma configuration de sécurité. Cette classe liens dans mon fournisseur:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired(required = true)
  SessionServiceClient sessionServiceClient;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/").permitAll().anyRequest().authenticated();
    http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(getKBServicesAuthenticationProvider());
  }

  @Bean
  protected AuthenticationProvider getKBServicesAuthenticationProvider() {
    return new KBServicesAuthProvider();
  }
}

Mais je ne vois rien dans les journaux et aucun de mes points de débogage n'est touché. L'application agit comme si elle n'était pas sécurisée (pour que je puisse toujours accéder à plusieurs URL, etc.).

Des idées sur ce que je devrais vérifier?

13
Lee Theobald

Ce n'est peut-être pas la solution complète, car je suis moi-même aux prises avec ce problème. J'utilise un fournisseur d'authentification personnalisé et un service de détails d'utilisateur personnalisés. Je constate le même comportement que vous: les points d'arrêt sont touchés dans mon service de détails utilisateur, mais pas dans mon fournisseur d'authentification. Voici à quoi ressemble toute ma classe de configuration:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        AuthenticationProvider rememberMeAuthenticationProvider = rememberMeAuthenticationProvider();
        TokenBasedRememberMeServices tokenBasedRememberMeServices = tokenBasedRememberMeServices();

        List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(2);
        authenticationProviders.add(rememberMeAuthenticationProvider);
        authenticationProviders.add(customAuthenticationProvider);
        AuthenticationManager authenticationManager = authenticationManager(authenticationProviders);

        http
                .csrf().disable()
                .headers().disable()
                .addFilter(new RememberMeAuthenticationFilter(authenticationManager, tokenBasedRememberMeServices))
                .rememberMe().rememberMeServices(tokenBasedRememberMeServices)
                .and()
                .authorizeRequests()
                .antMatchers("/js/**", "/css/**", "/img/**", "/login", "/processLogin").permitAll()
                .antMatchers("/index.jsp", "/index.html", "/index").hasRole("USER")
                .antMatchers("/admin", "/admin.html", "/admin.jsp", "/js/saic/jswe/admin/**").hasRole("ADMIN")
                .and()
                .formLogin().loginProcessingUrl("/processLogin").loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
                .and()
                .exceptionHandling().accessDeniedPage("/login")
                .and()
                .logout().permitAll();
    }

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

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

    @Bean
    public AuthenticationManager authenticationManager(List<AuthenticationProvider> authenticationProviders) {
        return new ProviderManager(authenticationProviders);
    }

    @Bean
    public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
        return new TokenBasedRememberMeServices("testKey", userDetailsService);
    }

    @Bean
    public AuthenticationProvider rememberMeAuthenticationProvider() {
        return new org.springframework.security.authentication.RememberMeAuthenticationProvider("testKey");
    }

    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
}

Je viens de découvrir que si j'ajoute spécifiquement mon fournisseur d'authentification à l'objet HttpSecurity, mes points d'arrêt commencent à être touchés:

http
                .csrf().disable()
                .headers().disable()
                .authenticationProvider(customAuthenticationProvider)

Mon objectif est de faire en sorte que BCryptPasswordEncoder fonctionne, ce qui n’est pas le cas avec cette configuration: tout est retourné avec des informations d’identité incorrectes. Quoi qu'il en soit, je pensais partager.

6
Bal

Je faisais face au même problème, le problème est avec votre méthode qui retournera toujours faux.

@Override
public boolean supports(Class<?> authentication) {
      return authentication.equals
  (UsernamePasswordAuthenticationToken.class);
}

Modifiez la méthode ci-dessus pour la méthode ci-dessous et le problème sera résolu.

@Override
    public boolean supports(Class<?> authentication) {
          return (UsernamePasswordAuthenticationToken.class
                    .isAssignableFrom(authentication));
    }
5
Mohit Sharma

Vous avez oublié l'annotation @Autowired.

@Autowired
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.authenticationProvider(getKBServicesAuthenticationProvider());
}

En outre, vous souhaiterez peut-être supprimer la .antMatchers("/").permitAll().

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests().anyRequest().authenticated();
  http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
}
3
Christopher Z

J'ai eu le même problème (mon fournisseur d'authentification personnalisé n'est pas touché) et j'ai résolu le problème en introduisant springSecurityFilterChain , après avoir lu Pourquoi Spring Security fonctionne-t-il dans Tomcat mais pas lorsqu'il est déployé sur Weblogic? Donc, mon problème était peut-être lié spécifiquement à WebServer, mais j'avais également un problème de fournisseur d'authentification personnalisé sur Tomcat et j'ai vérifié que ma configuration fonctionnait maintenant sur Tomcat.

J'utilise la version 1.4.1 de Spring Boot qui contient Spring 4.3.3 et Spring Security 4.1.3 et suivantes Déploiement traditionnel

J'ai testé ma configuration sur Tomcat v9.0 ainsi que sur WebLogic 12c R2 et j'ai vérifié que tout fonctionnait bien. J'espère que cela servira au moins à quelqu'un qui utilise Tomcat.

Ci-dessous ma configuration démarrée depuis la classe principale.

Application.Java

public class Application {
    public static void main( String[] args ) {
        SpringApplication.run(new Class[] {AppConfig.class, Initializer.class, SecurityInitializer.class}, args);
    }
}

Initializer.Java

public class Initializer extends SpringBootServletInitializer implements WebApplicationInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(AppConfig.class);
    }

    @Override
    public void onStartup(ServletContext container) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(WebConfig.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet("my-servlet", new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/*");
    }
}

Ici, AbstractSecurityWebApplicationInitializer est en train de générer la méthode springSecurityFilterChain from onStartup. Je n'en ai implémenté aucune, car j'essaie d'utiliser la configuration par défaut.

SecurityInitializer.Java

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

AppConfig.Java

@Configuration
@EnableAutoConfiguration
@EnableScheduling
@EnableMBeanExport
@EnableAsync
@EnableAspectJAutoProxy
@ComponentScan("com.my.package")
public class AppConfig {


}

SecurityConfig.Java

@Configuration
@EnableWebSecurity
@ComponentScan("com.my.package")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RestfulRemoteAuthenticationProvider restfulRemoteAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(restfulRemoteAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }
}

WebConfig.Java

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.my.controller.package")
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public InternalResourceViewResolver internalViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setOrder(1);
        return viewResolver;
    }
}

Ceci est mon fournisseur d'authentification personnalisé pour obtenir les informations d'authentification d'un autre composant via une demande restante.

RestfulRemoteAuthenticationProvider.Java

@Component
public class RestfulRemoteAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private ManagementClientAdapterFactory managementClientAdapterFactory;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        // my logic to get and configure authSource which is my environment specific thing, also same for RemoteAuthRequestResult

        RemoteAuthRequestResult result = (RemoteAuthRequestResult)authSource.sendRequest();
        if(result.isAuthenticated()) {
            List<GrantedAuthority> grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
            return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
        }
        throw new BadCredentialsException("User not found by given credential");
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}
2
Steve Park

@EnableWebMvcSecurity sera obsolète en 4.0 https://jira.spring.io/browse/SEC-2790

Vous voudrez peut-être revoir votre configuration.

1
Nitesh Virani
   Something like should be present in Java config 
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class HelloMethodSecurityConfig {
}
1
Nitin Prabhu
<security:global-method-security pre-post-annotations="enabled"/>
0
Nitin Prabhu