Я хочу додати багатофакторну автентифікацію з м'якими маркерами 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: оскільки це питання про безпеку, я шукаю відповідь, отриману з надійних та / або офіційних джерел. Дякую.