Spring Security and Action Required after login

Maksim :

I'm trying to implement an action required screen after user is logged-in in Spring Security? I have a requirement where user has to perform to complete a form (change password, accept Terms Of Use, etc.), then once user completes that action he can use the rest of the app. I'm using Spring OAuth2 with the login screen that uses Spring Security flow.

So far I have tried to use http.formLogin().successHandler() that has custom implementation of SavedRequestAwareAuthenticationSuccessHandler, which detects if user has action required, then redirects user to the page when he can fill out the form, but the problem with that is that if user navigates away from that page, he will be logged in to the app and can use it without by skipping the form. But what I'm trying to do is to block user from establishing the session until after that Action Required form is complete. Once it is complete user should be automatically logged in (ex. if user was req. to only agree with Terms of Use, he should be logged in without entering a password second time)

Here is the code that I have so far the custom handler:

public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Autowired
    UserService userService;

    public final static String TARGET_URL_SESSION_ATTR_NAME = "target-url";

    public CustomLoginSuccessHandler(String defaultTargetUrl) {
        setDefaultTargetUrl(defaultTargetUrl);
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        HttpSession session = request.getSession();


        AuthorityUser authorityUser = (AuthorityUser)authentication.getPrincipal();

        String userId = authorityUser.getUserId();

        User u = userService.getById(userId);

        Boolean changeRequiredDob = u.getChangeRequiredDob();
        Boolean changeRequiredPwd = u.getChangeRequiredPwd();
        Boolean changeRequiredTou = u.getChangeRequiredTou();

        if(changeRequiredDob || changeRequiredPwd || changeRequiredTou){

            String targetUrl = determineTargetUrl(request, response);
            session.setAttribute(TARGET_URL_SESSION_ATTR_NAME, targetUrl);
            getRedirectStrategy().sendRedirect(request, response, "/action-required");
        } else {
            super.onAuthenticationSuccess(request, response, authentication);
        }
    }
}

And then once it is successfully complete I'm redirecting user to TARGET_URL_SESSION_ATTR_NAME that was stored to the session.

It would be also helpful to know how to detect and redirect user to the action required screen during the established sessions (if user logged in and later while he is logged in admin sets action required flag on his account).

so-random-dude :

https://github.com/king-julien/spring-oauth2-customfilter Here is a working sample with Authorization and Resource Server. This Resource Server (vanilla) is a basic stateless application which will not proceed any further until you accept Terms of Service (to accept TOS, Just a do a POST on /tos end point) after authentication.

Create a filter

@Component
public class TosFilter extends OncePerRequestFilter{

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        System.out.println(request.getRequestURI());

        // In realworld scenario HelloWorldController.acceptedTOS is a persisted value rather than a static variable
        if(!HelloWorldController.acceptedTOS){
            //response.sendRedirect("/no-tos");
            request.getRequestDispatcher("error-no-tos").forward(request, response);
        }
        filterChain.doFilter(request,response);
    }
}

Register that filter

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    TosFilter rolesFilter;

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception{

        httpSecurity
                .addFilterAfter(rolesFilter, AbstractPreAuthenticatedProcessingFilter.class)
                .csrf().disable()
                .authorizeRequests().anyRequest().permitAll();
    }
}

Annotate your main with @EnableResourceServer.

@SpringBootApplication
@EnableResourceServer
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=455083&siteId=1