3

I have a scenario where I have to force the users to reset password on first login. For this I am using a custom successAuthenticationHandler. All this handler trying to do is see if logged in user requires to reset password. If yes create a new UsernamePasswordAuthenticationToken and set it onto SecurityContext. And then redirect to resetPasswordUrl.

Here is my onAuthenticationSuccess method:

@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);
    }

}

If yes create another UsernamePasswordAuthenticationToken with same credentials as logged in user, but just assign him a single role "RESET_PASSWORD", so that he cannot access anything alse by hitting any other link/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;

}

Now I do see the new UsernamePasswordAuthenticationToken being created with just a RESET password role. But looks like while doing redirect to the resetPasswordURl the spring filter do some checks and user is getting unauthenticated after I set my new UsernamePasswordAuthenticationToken .

Heres is the root cause that I see in the logs:

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)

Any comments where I am going wrong ?

4

1 回答 1

1

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

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

所以使用:

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

反而。

此外,您将需要一个自定义投票器来处理RESET_PASSWORD,因为默认配置不会识别它。或者使用ROLE_前缀,即ROLE_RESET_PASSWORD.

于 2012-02-21T19:06:21.513 回答