Я хочу додати багатофакторну автентифікацію з м'якими маркерами TOTP до програми Angular & Spring, зберігаючи все як можна ближче до стандартних параметрів Spring Boot Security Starter .
Перевірка токена відбувається локально (за допомогою бібліотеки aerogear-otp-java), без стороннього постачальника API.
Налаштування жетонів для користувача працює, але перевірка їх шляхом використання диспетчера / постачальників Spring Security Authentication Manager не робить.
TL; DR
- Який офіційний спосіб інтегрувати додатковий AuthenticationProvider в налаштовану систему Spring Boot Security Starter ?
- Які рекомендовані способи запобігти повторним атакам?
Довга версія
API має кінцеву точку, /auth/tokenз якої інтерфейс може отримати маркер JWT, надавши ім'я користувача та пароль. Відповідь також включає в себе аутентифікацію-статус, який може бути або аутентифікований або PRE_AUTHENTICATED_MFA_REQUIRED .
Якщо користувачеві потрібен MFA, маркер видається з одним наданим повноваженням PRE_AUTHENTICATED_MFA_REQUIREDта терміном дії 5 хвилин. Це дозволяє користувачеві отримати доступ до кінцевої точки, /auth/mfa-tokenде вони можуть надати код TOTP від програми Authenticator і отримати повністю автентифікований маркер для доступу до сайту.
Провайдер і токен
Я створив свій звичай, MfaAuthenticationProviderякий реалізує AuthenticationProvider:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// validate the OTP code
}
@Override
public boolean supports(Class<?> authentication) {
return OneTimePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
І OneTimePasswordAuthenticationTokenяка поширюєтьсяAbstractAuthenticationToken на вміст імені користувача (взятого з підписаного JWT) та коду OTP.
Налаштування
У мене є свій звичай WebSecurityConfigurerAdapter, куди я додаю свій звичай AuthenticationProviderчерез http.authenticationProvider(). Згідно з JavaDoc, схоже, це правильне місце:
Дозволяє додавати додатковий AuthenticationProvider для використання
Відповідні частини мого SecurityConfigвиглядають так.
@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
Контролер
AuthControllerМає AuthenticationManagerBuilderвпорскується і тягне все це разом.
@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
Однак публікація проти /auth/mfa-tokenпризводить до цієї помилки:
"error": "Forbidden",
"message": "Access Denied",
"trace": "org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for de.....OneTimePasswordAuthenticationToken
Чому Spring Security не бере свого постачальника аутентифікації? Налагодження контролера показує мені, що DaoAuthenticationProviderце єдиний постачальник аутентифікації в AuthenticationProviderManager.
Якщо я виставляю свою MfaAuthenticationProviderяк боб, це єдиний зареєстрований Постачальник, тож я отримую навпаки:
No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken.
Отже, як я можу отримати обидва?
Моє запитання
Який рекомендований спосіб інтегрувати додаткову систему AuthenticationProviderв налаштовану систему Spring Boot Security Starter , щоб я отримав DaoAuthenticationProviderі власний , і власний звичай MfaAuthenticationProvider? Я хочу зберегти стандартні налаштування Spring Boot Security і додатково мати власного постачальника.
Попередження нападу відтворення
Я знаю, що алгоритм OTP сам по собі не захищає від атак повторного відтворення в проміжок часу, в якому код дійсний; RFC 6238 робить це зрозумілим
Верифікатор НЕ МОЖЕ приймати другу спробу OTP після того, як успішна перевірка була видана для першого OTP, що забезпечує одноразове використання OTP.
Мені було цікаво, чи є рекомендований спосіб здійснення захисту. Оскільки маркери OTP засновані на часі, я думаю про збереження останнього успішного входу на модель користувача та переконайтесь, що є лише один успішний логін за 30 секунд. Це звичайно означає синхронізацію на моделі користувача. Будь-які кращі підходи?
Дякую.
-
PS: оскільки це питання про безпеку, я шукаю відповідь, отриману з надійних та / або офіційних джерел. Дякую.