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
,