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/token
dal 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_REQUIRED
e un tempo di scadenza di 5 minuti. Ciò consente all'utente di accedere all'endpoint in /auth/mfa-token
cui 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 MfaAuthenticationProvider
che 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 OneTimePasswordAuthenticationToken
che si estende AbstractAuthenticationToken
per contenere il nome utente (preso dal JWT firmato) e il codice OTP.
config
Ho la mia abitudine WebSecurityConfigurerAdapter
, dove aggiungo la mia personalizzata AuthenticationProvider
tramite http.authenticationProvider()
. Accedendo a JavaDoc, questo sembra essere il posto giusto:
Consente di aggiungere un altro AuthenticationProvider da utilizzare
Le parti rilevanti del mio SecurityConfig
assomigliano 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' AuthController
ha AuthenticationManagerBuilder
iniettato 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-token
porta 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 MfaAuthenticationProvider
come 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 AuthenticationProvider
in un sistema configurato con Spring Boot Security Starter , in modo da ottenere sia la DaoAuthenticationProvider
mia 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.