Spring安全上下文设置身份验证对象不起作用

时间:2012-02-16 05:01:30

标签: spring authentication spring-security security-context-token

我有一个场景,我必须强制用户在首次登录时重置密码。对于 这我正在使用自定义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”,这样他就无法通过点击任何其他链接/网址来访问任何内容。

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;

}

现在我确实看到只使用RESET密码角色创建了新的UsernamePasswordAuthenticationToken。 但看起来在重定向到resetPasswordURl时,spring过滤器会进行一些检查,并且在我设置新的UsernamePasswordAuthenticationToken后,用户将得到未经身份验证。

Heres是我在日志中看到的根本原因:

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 个答案:

答案 0 :(得分:1)

如果没有来自日志的更多上下文(堆栈跟踪的其余部分加上前面的日志消息),很难说,但我最好的猜测是你为{{1}使用了错误的构造函数}。由于历史原因,它需要UsernamePasswordAuthenticationToken个参数无效。

双arg版本应该使用用户名和凭据,并创建一个未经身份验证的令牌(对于请求),从安全拦截器的角度来看,这是无效的。所以我猜测拦截器正在尝试重新验证令牌(应该从调用来自的堆栈跟踪中显而易见)并且它失败了因为凭证参数实际上是权限列表而不是密码。

所以使用:

Object

代替。

此外,您需要有一个处理new UsernamePasswordAuthenticationToken( userWithResetPasswordRole, null, userWithResetPasswordRole.getAuthorities()); 的自定义选民,因为默认配置无法识别它。或者,使用RESET_PASSWORD前缀,即ROLE_