Spring Security Context Set Проверка подлинности объекта не работает

У меня есть сценарий, в котором я должен заставить пользователей сбросить пароль при первом входе в систему. Для этого я использую пользовательский successAuthenticationHandler. Все, что пытается сделать этот обработчик - это посмотреть, требует ли вошедший в систему пользователь сбросить пароль. Если да, создайте новый UsernamePasswordAuthenticationToken и установите его в SecurityContext. А затем перенаправить на resetPasswordUrl.

Вот мой метод onAuthenticationSuccess:

@Override
public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response,
        final Authentication authentication) throws ServletException, IOException {

    final AugmentedUser aUser = (AugmentedUser) SecurityContextHolder.getContext().getAuthentication()
            .getPrincipal();
    System.out.println("In password reset handler.");
    if (authorizationService.isPasswordResetRequired(aUser.getUsername(), aUser.getUsertype())) {
        LOG.debug("Password reset is required.");
        System.out.println("Password reset is required");
        final UsernamePasswordAuthenticationToken authRequest = reAssignUserWithOnlyResetPasswordRole(aUser,
                request);
        SecurityContextHolder.getContext().setAuthentication(authRequest);
        SecurityContextHolder.getContext().getAuthentication();
        System.out.println("User reassinged with only RESET_PASSWORD Authority, redirecting to resetPasswordPage");
        response.sendRedirect(resetPasswordUrl);

        //super.onAuthenticationSuccess(request, response, newAuthentication);
    } else {
        super.onAuthenticationSuccess(request, response, authentication);
    }

}

Если да, создайте еще один UsernamePasswordAuthenticationToken с теми же учетными данными, что и вошедший в систему пользователь, но просто назначьте ему одну роль "RESET_PASSWORD", чтобы он не мог получить доступ ко всему остальному, нажав любую другую ссылку / URL.

private UsernamePasswordAuthenticationToken reAssignUserWithOnlyResetPasswordRole(final AugmentedUser aUser,
        final HttpServletRequest request) {
    final String username = aUser.getUsername();
    final String password = aUser.getPassword();
    final boolean isEnabled = aUser.isEnabled();
    final boolean isAccountNonExpired = aUser.isAccountNonExpired();
    final boolean isCredentialsNonExpired = aUser.isCredentialsNonExpired();
    final boolean isAccountNonLocked = aUser.isAccountNonLocked();
    LOG.debug("Re-assigning the user: " + username + " with only RESET PASSWORD AUTHORITY");
    System.out.println("Re-assigning the user: " + username + "with only RESET PASSWORD AUTHORITY");
    final Map<String, String> userAttributesMap = new HashMap<String, String>();
    final AugmentedUser userWithResetPasswordRole = new AugmentedUser(username, password, aUser.getUsertype(),
            isEnabled, isAccountNonExpired, isCredentialsNonExpired, isAccountNonLocked,
            createResetPasswordGrantedAuhtority(), userAttributesMap);

    final UsernamePasswordAuthenticationToken authenticationRequest = new UsernamePasswordAuthenticationToken(
            userWithResetPasswordRole, userWithResetPasswordRole.getAuthorities());

    //WebAuthenticationDetails are required for sessionId and ipAddress
    final WebAuthenticationDetails webAuthenticationDetails = new WebAuthenticationDetails(request);
    authenticationRequest.setDetails(webAuthenticationDetails);

    return authenticationRequest;

}

Теперь я вижу, что новый UsernamePasswordAuthenticationToken создается только с ролью СБРОСА пароля. Но похоже, что при перенаправлении на resetPasswordURl весенний фильтр выполняет некоторые проверки, и пользователь становится не прошедшим проверку подлинности после того, как я установил свой новый UsernamePasswordAuthenticationToken.

Вот основная причина, которую я вижу в журналах:

doAuthentication - Authentication attempt using
org.springframework.security.authentication.dao.DaoAuthenticationProvider
2012-02-15 22:47:20,931 [http-8081-6] DEBUG       org.springframework.security.web.access.ExceptionTranslationFilter    org.springframework.security.web.access.ExceptionTranslationFilter handleException - Authentication exception occurred; redirecting to authentication entry point

org.springframework.security.authentication.BadCredentialsException: Bad credentials
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:67)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:139)
at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:120)

Любые комментарии, где я иду не так?

1 ответ

Трудно сказать без большего контекста из журнала (остальная часть трассировки стека плюс предыдущие сообщения журнала), но я думаю, что вы используете неправильный конструктор для UsernamePasswordAuthenticationToken, По историческим причинам это занимает Object аргументы, которые не помогают.

Предполагается, что двухаргументная версия принимает имя пользователя и учетные данные и создает токен без проверки подлинности (для запроса), который недопустим с точки зрения перехватчика безопасности. Поэтому я предполагаю, что перехватчик пытается повторно аутентифицировать токен (это должно быть очевидно из стековой трассировки, откуда поступает вызов), и он терпит неудачу, потому что параметр credentials на самом деле является списком прав доступа, а не паролем.

Так что используйте:

new UsernamePasswordAuthenticationToken(
        userWithResetPasswordRole, null, userWithResetPasswordRole.getAuthorities());

вместо.

Кроме того, вам нужно будет иметь собственного избирателя, который обрабатывает RESET_PASSWORD так как он не будет распознан конфигурацией по умолчанию. В качестве альтернативы используйте ROLE_ префикс, т.е. ROLE_RESET_PASSWORD,

Другие вопросы по тегам