Voglio aggiungere l'autenticazione a più fattori con i token soft TOTP a un'applicazione Angular & Spring, mantenendo tutto il più vicino possibile alle impostazioni predefinite di Spring Boot Security Starter .
La convalida del token avviene localmente (con la libreria aerogear-otp-java), nessun provider API di terze parti.
L'impostazione dei token per un utente funziona, ma la loro convalida sfruttando Gestore / provider di autenticazione Spring Security no.
TL; DR
- Qual è il modo ufficiale per integrare un altro AuthenticationProvider in un sistema configurato con Spring Boot Security Starter ?
- Quali sono i modi consigliati per prevenire gli attacchi replay?
Versione lunga
L'API ha un endpoint /auth/tokendal quale il frontend può ottenere un token JWT fornendo nome utente e password. La risposta include anche uno stato di autenticazione, che può essere AUTHENTICATED o PRE_AUTHENTICATED_MFA_REQUIRED .
Se l'utente richiede l'AMF, il token viene rilasciato con un'unica autorità concessa PRE_AUTHENTICATED_MFA_REQUIREDe un tempo di scadenza di 5 minuti. Ciò consente all'utente di accedere all'endpoint in /auth/mfa-tokencui può fornire il codice TOTP dalla propria app Authenticator e ottenere il token completamente autenticato per accedere al sito.
Provider e token
Ho creato la mia abitudine MfaAuthenticationProviderche implementa AuthenticationProvider:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// validate the OTP code
}
@Override
public boolean supports(Class<?> authentication) {
return OneTimePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
E un OneTimePasswordAuthenticationTokenche si estende AbstractAuthenticationTokenper contenere il nome utente (preso dal JWT firmato) e il codice OTP.
config
Ho la mia abitudine WebSecurityConfigurerAdapter, dove aggiungo la mia personalizzata AuthenticationProvidertramite http.authenticationProvider(). Accedendo a JavaDoc, questo sembra essere il posto giusto:
Consente di aggiungere un altro AuthenticationProvider da utilizzare
Le parti rilevanti del mio SecurityConfigassomigliano a questo.
@Configuration
@EnableWebSecurity
@EnableJpaAuditing(auditorAwareRef = "appSecurityAuditorAware")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final TokenProvider tokenProvider;
public SecurityConfig(TokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authenticationProvider(new MfaAuthenticationProvider());
http.authorizeRequests()
// Public endpoints, HTML, Assets, Error Pages and Login
.antMatchers("/", "favicon.ico", "/asset/**", "/pages/**", "/api/auth/token").permitAll()
// MFA auth endpoint
.antMatchers("/api/auth/mfa-token").hasAuthority(ROLE_PRE_AUTH_MFA_REQUIRED)
// much more config
controllore
L' AuthControllerha AuthenticationManagerBuilderiniettato e lo sta mettendo insieme.
@RestController
@RequestMapping(AUTH)
public class AuthController {
private final TokenProvider tokenProvider;
private final AuthenticationManagerBuilder authenticationManagerBuilder;
public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
this.tokenProvider = tokenProvider;
this.authenticationManagerBuilder = authenticationManagerBuilder;
}
@PostMapping("/mfa-token")
public ResponseEntity<Token> mfaToken(@Valid @RequestBody OneTimePassword oneTimePassword) {
var username = SecurityUtils.getCurrentUserLogin().orElse("");
var authenticationToken = new OneTimePasswordAuthenticationToken(username, oneTimePassword.getCode());
var authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
// rest of class
Tuttavia, la pubblicazione in contro /auth/mfa-tokenporta a questo errore:
"error": "Forbidden",
"message": "Access Denied",
"trace": "org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for de.....OneTimePasswordAuthenticationToken
Perché Spring Security non rileva il mio provider di autenticazione? Il debug del controller mi mostra che DaoAuthenticationProviderè l'unico provider di autenticazione in AuthenticationProviderManager.
Se espongo il mio MfaAuthenticationProvidercome bean, è l' unico provider registrato, quindi ottengo il contrario:
No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken.
Quindi, come ottengo entrambi?
La mia domanda
Qual è il modo consigliato per integrare un ulteriore AuthenticationProviderin un sistema configurato con Spring Boot Security Starter , in modo da ottenere sia la DaoAuthenticationProvidermia che la mia personalizzazione MfaAuthenticationProvider? Voglio mantenere le impostazioni predefinite di Spring Boot Scurity Starter e avere anche il mio provider.
Prevenzione di Replay Attack
So che l'algoritmo OTP non protegge da solo dagli attacchi di riproduzione entro l'intervallo di tempo in cui il codice è valido; RFC 6238 lo chiarisce
Il verificatore NON DEVE accettare il secondo tentativo di OTP dopo che è stata emessa la convalida corretta per il primo OTP, il che garantisce un solo utilizzo di un OTP.
Mi chiedevo se esiste un modo raccomandato per implementare la protezione. Poiché i token OTP sono basati sul tempo, sto pensando di memorizzare l'ultimo accesso riuscito sul modello dell'utente e di assicurarmi che ci sia un solo accesso riuscito per 30 secondi. Questo ovviamente significa sincronizzazione sul modello utente. Qualche approccio migliore?
Grazie.
-
PS: poiché questa è una domanda sulla sicurezza, sto cercando una risposta che attinga da fonti credibili e / o ufficiali. Grazie.