2017-01-18 1 views
0

Hallo an alle Spring-Experten!AbstractAuthenticationProcessingFilter wird nicht ausgelöst vor UsernamePasswordAuthenticationFilter

Ich habe ein Problem, das ich versuche, für eine Weile zu lösen, aber ich denke, dass ich eine Sackgasse erreicht habe.

Also im Grunde, was ich brauche, ist meine Spring-Security zu konfigurieren (in Spring-Boot), zwei Authentifizierungsmechanismen (eine für Legacy JSP-Seiten und eine für REST-APIs) zu haben. So folgte ich dem folgenden Beitrag: multiple authentication mechanisms in a single app using java config

Es funktionierte gut mit einem LDAP-Authentifizierungsanbieter. Aber dann habe ich versucht, meine LDAP-Verbindung zu erweitern, um auch ein Ticket von einem Drittanbieter-Dienst zu erhalten (der für zukünftige Verbindungen mit anderen Diensten verwendet wird), und dort hatte ich ein Problem.

Also habe ich einen neuen Authentication Token-, Filter- und Authentifizierungsanbieter erstellt, aber der Standard UsernamePasswordAuthenticationFilter wird zuerst ausgelöst, egal was ich mache.

Ich habe versucht, diesem Beitrag How to configure a custom filter programatically in Spring Security? zu folgen und sah, dass das Problem in der Tatsache sein könnte, dass mein Filter UsernamePasswordAuthenticationFilter verlängert wurde. Also habe ich das entfernt und versucht, eine einfache AbstractAuthenticationProcessingFilter zu haben, immer noch - kein Glück.

Ich denke, das Problem ist in meiner WebSecurity-Konfiguration. Derzeit, mit dem folgenden Code werde ich teilen, die REST Api-Authentifizierung ist zurück 405 - Methode nicht erlaubt und das Legacy Login steckt in einer Endlosschleife und stürzt ab, noch bevor ich "Login" klicke.

@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true) //Enables @PreAuthorize on methods 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private LDAPConfigurationBean ldapBean; 

    @Autowired 
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
//HERE GOES LDAP CONNECTION STUFF    
//  Add the custom LDAP + Token provider to the Authentication provider chain 
     auth.authenticationProvider(new TicketAndLDAPAuthenticationProvider(authenticator,authoritiesPopulator)); 

//  Creating an LDAP provider using the authenticator and the populator. 
     auth.authenticationProvider(new LdapAuthenticationProvider(authenticator,authoritiesPopulator)); 

    } 


    @Configuration 
    @Order(1) 
    public static class ConfigureFilters extends WebSecurityConfigurerAdapter { 
     protected void configure(HttpSecurity http) throws Exception { 
      http.csrf().disable(); 
      http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(),UsernamePasswordAuthenticationFilter.class); 
     } 
    } 

    //Management Endpoints Authorization 
    @Configuration 
    @Order(2) 
    public static class EndpointsWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     protected void configure(HttpSecurity http) throws Exception { 
      http 
        .antMatcher("/manage/health") 
        .authorizeRequests() 
        .anyRequest().permitAll(); 
     } 
    } 

    //API Authentication+Authorization 
    @Configuration 
    @Order(3) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 

     @Autowired 
     private RestAuthenticationEntryPoint authenticationEntryPoint; 
     @Autowired 
     private RestAuthSuccessHandler authSuccessHandler; 
     @Autowired 
     private RestAuthFailureHandler authFailureHandler; 
     @Autowired 
     private RestLogoutSuccessHandler logoutSuccessHandler; 

     private String LOGIN_PATH = "/api/authenticate"; 
     private String USERNAME = "username"; 
     private String PASSWORD = "password"; 

     protected void configure(HttpSecurity http) throws Exception { 
      /*CSRF configuration*/ 
      http.csrf().disable(); 

      http 
        .antMatcher(LOGIN_PATH) 
        .authorizeRequests() 
        .anyRequest().permitAll(); 

      http 
        .antMatcher("/api/**") 
        //Stateless session creation - no session will be created or used by Spring Security 
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
        .and() 
        .exceptionHandling() 
         .authenticationEntryPoint(authenticationEntryPoint) 
        .and() 
        .formLogin().permitAll() 
         .loginProcessingUrl(LOGIN_PATH) 
         .usernameParameter(USERNAME) 
         .passwordParameter(PASSWORD) 
         .successHandler(authSuccessHandler) 
         .failureHandler(authFailureHandler) 
        .and() 
        .logout().permitAll() 
         .logoutSuccessHandler(logoutSuccessHandler); 

      http 
        .authorizeRequests().anyRequest().authenticated(); 
     } 
    } 

    //JSP Authentication+Authorization 
    @Configuration 
    @Order(4) 
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 

     @Override 
     protected void configure(HttpSecurity http) throws Exception { 
      /*CSRF configuration*/ 
      http.csrf().disable(); 

      /*Static content*/ 
      http 
        .authorizeRequests() 
        .antMatchers("/css*//**").permitAll() 
        .antMatchers("/images*//**").permitAll() 
        .antMatchers("/scripts*//**").permitAll() 
        .antMatchers("/fonts*//**").permitAll() 
        .antMatchers("/login*").anonymous(); 

     /*Login/Logout configuration*/ 
      http 
        .formLogin() 
         .loginPage("/login.htm").permitAll() 
         .defaultSuccessUrl("/index.htm?name=******") 
         .failureUrl("/login.htm?error=true") 
        .and() 
        .logout().permitAll() 
         .logoutSuccessUrl("/login.htm") 
         .invalidateHttpSession(true) 
         .deleteCookies("JSESSIONID"); 

     /*URL roles authorizations*/ 
      http 
        .authorizeRequests().anyRequest().authenticated(); 
     } 
    } 
} 

Wie Sie sehen können, ich versuche meinen Filter in der „Configure Filters“ Methode zu konfigurieren - aber ich versucht habe es auch in dem Adapter zu konfigurieren, mit/ohne @Bean Anmerkung - alles ohne Glück .

Filter:

public class TicketAndLDAPAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 
    public TicketAndLDAPAuthenticationFilter() { 
     super("/*"); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 
     //Save the password for later 
     String username = request.getParameter("username"); 
     String password = request.getParameter("password"); 

     TicketAndLDAPAuthenticationToken token = new TicketAndLDAPAuthenticationToken(username,password,null); 

     return token; 
    } 
} 

Edit: vergessen haben, zu dem Filter hinzuzufügen:

if (request.getParameter("username") == null || request.getParameter("password") == null) == null) { 
      return null; 
     } 

Jetzt bekomme ich 405 in beiden Login-Mechanismen.

Token:

public class TicketAndLDAPAuthenticationToken extends UsernamePasswordAuthenticationToken { 
    private AuthTicket otp; 
    private String restoredPassword; 


    public TicketAndLDAPAuthenticationToken(String username, String password, RestAuthLoginTicket otp) { 
     super(username, password); 
     this.otp = otp; 
    } 

    public AuthTicket getOTP() { 
     return otp; 
    } 

    public AuthTicket getOtp() { 
     return otp; 
    } 

    public void setOtp(AuthTicket otp) { 
     this.otp = otp; 
    } 
} 

Anbieter:

public class TicketAndLDAPAuthenticationProvider extends LdapAuthenticationProvider { 

    @Autowired 
    TokenUtils tokenUtils; 

    public TicketAndLDAPAuthenticationProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) { 
     super(authenticator, authoritiesPopulator); 
    } 

    @Override 
    public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
       TicketAndLDAPAuthenticationToken token = (TicketAndLDAPAuthenticationToken) super.authenticate(authentication); 
     token.setOtp(tokenUtils.getTicket(token)); 
     return token; 
    } 


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

Vielen Dank im Voraus !!

Antwort

0

So fand ich das Problem (s).

Zunächst ist der richtige Weg, um die Authentifizierungsmanager zu konfigurieren, nicht, wie ich oben konfiguriert, weil es keine antMatcher und dies verursachte meine Ressourcen und Seiten für alle offen sein.

Zweitens, das Problem, das die unendlichen Weiterleitungen und Fehler 405 verursachte, war, dass ich meinen Filter nicht definiert habe, um Post zu akzeptieren.

Nachdem ich das behoben hatte, funktionierte mein JSP-Anmeldeformular und Authentifizierungsmechanismus gut, aber die "/ api" wurde auf die Anmeldeseite statt der Ressource umgeleitet.

Was bringt mich zu meinem letzten Punkt - die http.formLogin() erstellt eine UsernamePasswordAuthenticationFilter. Ich habe zwei von ihnen - einen für jeden Login. Also musste ich http.addFilterBefore() für jeden der Logins hinzufügen, aber mit einer anderen URL. Die "/ api" -URL verwendete wieder die Standard-Weiterleitungen von Spring statt der von mir definierten, also musste ich sie überschreiben.

Dies sind die Konfigurationen und Filter, die für mich arbeiten:

Sicherheitskonfiguration:

@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled = true) //Enables @PreAuthorize on methods 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private LDAPConfigurationBean ldapBean; 

    @Autowired 
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 

     //LDAP Stuff 

     TicketAndLDAPAuthenticationProvider ticketAndLDAPAuthenticationProvider = new TicketAndLDAPAuthenticationProvider(authenticator,authoritiesPopulator); 
     auth.authenticationProvider(ticketAndLDAPAuthenticationProvider); 

     LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(authenticator,authoritiesPopulator); 
     auth.authenticationProvider(ldapAuthenticationProvider);  
    } 

    //Management Endpoints Authorization 
    @Configuration 
    @Order(1) 
    public static class EndpointsWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     protected void configure(HttpSecurity http) throws Exception { 
      http 
        .antMatcher("/manage/health") 
        .authorizeRequests() 
        .anyRequest().permitAll(); 
     } 
    } 

    //API Authentication+Authorization 
    @Configuration 
    @Order(2) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 

     @Autowired 
     private RestAuthenticationEntryPoint authenticationEntryPoint; 
     @Autowired 
     private RestAuthSuccessHandler authSuccessHandler; 
     @Autowired 
     private RestAuthFailureHandler authFailureHandler; 
     @Autowired 
     private RestLogoutSuccessHandler logoutSuccessHandler; 

     private String LOGIN_PATH = "/api/authenticate"; 

     protected void configure(HttpSecurity http) throws Exception { 
      /*CSRF configuration*/ 
      http.csrf().disable(); 

      http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(LOGIN_PATH,authSuccessHandler,authFailureHandler), UsernamePasswordAuthenticationFilter.class); 

      http 
        .antMatcher("/api/**") 
//     Stateless session creation - no session will be created or used by Spring Security 
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
        .and() 
        .exceptionHandling() 
         .authenticationEntryPoint(authenticationEntryPoint) 
        .and() 
        .logout().permitAll() 
         .logoutSuccessHandler(logoutSuccessHandler); 

      http 
        .authorizeRequests().anyRequest().authenticated(); 

     } 
    } 

    //JSP Authentication+Authorization 
    @Configuration 
    @Order(3) 
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 

     private String LOGIN_PATH = "/login.htm"; 

     @Override 
     protected void configure(HttpSecurity http) throws Exception { 
      /*CSRF configuration*/ 
      http.csrf().disable(); 

      http.addFilterBefore(new TicketAndLDAPAuthenticationFilter(LOGIN_PATH), UsernamePasswordAuthenticationFilter.class); 

      /*Static content*/ 
      http 
        .authorizeRequests() 
        .antMatchers("/css*//**").permitAll() 
        .antMatchers("/images*//**").permitAll() 
        .antMatchers("/scripts*//**").permitAll() 
        .antMatchers("/fonts*//**").permitAll() 
        .antMatchers("/login*").anonymous(); 

     /*Login/Logout configuration*/ 
      http 
        .formLogin() 
         .loginPage(LOGIN_PATH).permitAll() 
         .defaultSuccessUrl("/index.htm?name=******") 
         .failureUrl("/login.htm?error=true") 
        .and() 
        .logout().permitAll() 
         .logoutSuccessUrl("/login.htm") 
         .invalidateHttpSession(true) 
         .deleteCookies("JSESSIONID"); 

     /*URL roles authorizations*/ 
      http 
        .authorizeRequests().anyRequest().authenticated(); 
     } 
    } 
} 

Und der Filter:

public class TicketAndLDAPAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 

    public TicketAndLDAPAuthenticationFilter(String defaultProcessUrl) { 
     super(new AntPathRequestMatcher(defaultProcessUrl, "POST")); 
    } 

    public TicketAndLDAPAuthenticationFilter(String defaultProcessUrl, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) { 
     super(new AntPathRequestMatcher(defaultProcessUrl, "POST")); 
     setAuthenticationFailureHandler(authenticationFailureHandler); 
     setAuthenticationSuccessHandler(authenticationSuccessHandler); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 
     //Save the password for later 
     String username = request.getParameter("username"); 
     String password = request.getParameter("password"); 

     if (username==null || password==null) { 
      return null; 
     } 

     TicketAndLDAPAuthenticationToken token = new TicketAndLDAPAuthenticationToken(username,password,null); 

     return token; 
    } 
} 
Verwandte Themen