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?
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.
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));
}
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();
}
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);
}
}
@EnableWebMvcSecurity
sera obsolète en 4.0 https://jira.spring.io/browse/SEC-2790
Vous voudrez peut-être revoir votre configuration.
Something like should be present in Java config
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class HelloMethodSecurityConfig {
}
<security:global-method-security pre-post-annotations="enabled"/>