6

Ho un'applicazione di avvio a molla in esecuzione con sicurezza Spring che utilizza l'autenticazione di base. Quando vengono fornite le credenziali di autenticazione di base corrette, tutto è buono, ma per le credenziali di autenticazione errate, spring genera un'eccezione HttpRequestMethodNotSupportedException: Request method 'POST' not supported.Spring Security con autenticazione di base che reindirizza a/errore per credenziali non valide

Secondo i registri, l'errore di autenticazione è stato identificato in primavera, ma non è quello che viene fuori.

2015-08-12 09:33:10.922 INFO 16988 --- [nio-8080-exec-4] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Wed Aug 12 09:33:10 AEST 2015, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}] 2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Bound request context to thread: FirewalledRequest[ [email protected]] 2015-08-12 09:33:10.927 DEBUG 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing POST request for [/myapplication/error] 2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [[email protected]331bb032] in DispatcherServlet with name 'dispatcherServlet' 2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.w.s.handler.SimpleUrlHandlerMapping : No handler mapping found for [/error] 2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.s[email protected]69e79b9b] in DispatcherServlet with name 'dispatcherServlet' 2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework[email protected]27cc0354] in DispatcherServlet with name 'dispatcherServlet' 2015-08-12 09:33:10.927 DEBUG 16988 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error 2015-08-12 09:33:10.928 DEBUG 16988 --- [nio-8080-exec-4] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported

Con i registri di cui sopra & dopo il debug la fonte di primavera, ho scoperto che su di identificazione che le credenziali non sono corrette, la primavera crea un'eccezione BadCredentials e poi tenta di reindirizzare a “/ errore”, il reindirizzamento è ciò che causa l'eccezione HttpMethodNotAllowed. (la mia applicazione non ha un endpoint/errore).

Ho cercato di dire la primavera di non usare/errore configurando quanto segue,

`ServerCustomization public class estende ServerProperties {

@Override 
public void customize(ConfigurableEmbeddedServletContainer container) { 

    super.customize(container); 
    container.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED, null)); 

}` 

Questo farà tappa primaverile sputare fuori la HttpMethodnotallowed eccezione e rendere venire con un 401 (non autorizzato), MA questa mia eccezione non viene catturata dal mio gestore di eccezioni (configurato usando @ControllerAdvice).

Ho anche provato a configurare un punto di ingresso di autenticazione personalizzato come di seguito senza alcuna fortuna.

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

AlwaysSendUnauthorized401AuthenticationEntryPoint alwaysSendUnauthorized401AuthenticationEntryPoint = 
     new AlwaysSendUnauthorized401AuthenticationEntryPoint(); 


@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.headers().httpStrictTransportSecurity().xssProtection().and().authorizeRequests().anyRequest().fullyAuthenticated() 
      .and().csrf().disable(); 

    http.exceptionHandling().authenticationEntryPoint(alwaysSendUnauthorized401AuthenticationEntryPoint); 
} 

public class AlwaysSendUnauthorized401AuthenticationEntryPoint implements AuthenticationEntryPoint { 
    @Override 
    public final void commence(HttpServletRequest request, HttpServletResponse response, 
      AuthenticationException authException) throws IOException { 
     response.sendError(HttpServletResponse.SC_UNAUTHORIZED); 
    } 
} 

}

C'è un modo siamo in grado di specificare di primavera non per reindirizzare a/errore e ritornare le credenziali Bad eccezione?

risposta

8

Ho creato un'applicazione di esempio Primavera di avvio, con la seguente configurazione di sicurezza:

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

    @Autowired 
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
     auth.inMemoryAuthentication().withUser("test").password("password").roles("USER"); 
    } 

    @Bean 
    public AuthenticationEntryPoint authenticationEntryPoint() { 
     return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.headers().httpStrictTransportSecurity().xssProtection() 
       .and().authorizeRequests().anyRequest().fullyAuthenticated() 
       .and().csrf().disable(); 

     http.httpBasic().authenticationEntryPoint(authenticationEntryPoint()); 
     http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()); 

    } 
} 

Quando si entra in un invalido nome utente/password (qualcosa di diverso da test/password), ottengo la seguente risposta:

{"timestamp":1439381390204,"status":401,"error":"Unauthorized","message":"Bad credentials","path":"/"} 

Questo errore viene restituito da org.springframework.boot.autoconfigure.web.BasicErrorController classe, che se si dispone di uno sguardo non definire due metodi con @RequestMapping("/error")-errorHtml e error. Dato che stai costruendo un'API, è la seconda che dovrebbe essere invocata e direi che è il comportamento "corretto"!

Quindi, per prima cosa, controllare di arrivare allo BasicErrorController quando l'autenticazione fallisce. In questo caso, assicurati di utilizzare il metodo error NOT errorHtml.

Se nessuno dei precedenti risulta utile, controllare se qualcuno ha annullato il comportamento predefinito del controllore degli errori. Un'estensione comune (e valida) è quella di implementare il proprio org.springframework.boot.autoconfigure.web.ErrorAttributes per modificare il carico utile di errore predefinito. Ma è altrettanto facile sostituire l'intero BasicErrorController con un'implementazione non standard, quindi verificane l'aspetto nell'applicazione.

Se tutto il resto fallisce e si è fermamente convinto che si desidera disabilitare la gestione degli errori di default di primavera (che non consiglio), prova ad aggiungere questo alla vostra configurazione:

@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})

Ciò volontà fare è assicurarsi che i controller degli errori non vengano caricati nel contesto dell'applicazione.

+0

Grazie a @grigori per avermi indicato nella giusta direzione. C'era effettivamente un'implementazione non standard del BasicErrorController che stava causando il problema. L'utilizzo di un controller errori corretto ha risolto il problema. – DilanD

+0

Grazie, per me il mvc-exclude lo ha risolto, a volte amo le impostazioni predefinite di SpringBoot, e talvolta no :) Ma questo mi ricorda di non fare una magia @EnableAutoConfiguration ma invece solo un sottoinsieme di specifiche * Configurazioni necessarie. –

1

Penso che invece di http.exceptionHandling().authenticationEntryPoint si dovrebbe usare http.httpBasic().authenticationEntryPoint. Per l'autenticazione modulo basato, questo sta lavorando per me:

http 
    .formLogin() 
     .failureHandler(authenticationFailureHandler()) 
     ... 
    ... 

per il gestore di errore di autenticazione, di primavera SimpleUrlAuthenticationFailureHandler può essere utilizzato. Quando un'istanza senza alcun parametro, sarebbe fare quello che vogliamo:

@Bean 
public AuthenticationFailureHandler authenticationFailureHandler() { 
    return new SimpleUrlAuthenticationFailureHandler(); 
} 

This è il mio completo file di protezione di configurazione, nel caso in cui è utile.

+0

Grazie a @Sanjay, proveremo un po 'e ti faccio sapere come è andata – DilanD

+0

Ho provato entrambe le soluzioni, ma ancora senza fortuna. il 'formLogin()' non sembra corretto poichè il mio è un'API di restrul. l'altro suggerimento su "authenticationEntryPoint" sembrava promettente ma non ha dato alcun risultato. – DilanD