I use spring security to implement software, manual user input. I have a scenario in which I positively set the user ID and want to register it. I donβt know their password and therefore I canβt use the usual login code path in which you submit the form to the URL that spring intercepts through the Filter servlet, doing all this with auth + session magic.
I searched and it seems that most people create their own Authentication object and then tell spring about: via
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(user, "", user.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(authentication);
Indeed it works. spring even puts it in a session for me, making subsequent HTTP requests, keeping their auth status.
However, I feel like this is a dirty hack. I will provide some details that I hope will give specific examples of problems associated with using setAuthentication() inside the controller to achieve manual login:
To give an idea, my configuration is:
httpSecurity .authorizeRequests() .antMatchers("/test/**").permitAll() .antMatchers("/admin/**", "/api/admin/**").hasRole("USER_SUPER_ADMIN") .and() .formLogin() .loginPage("/sign-in?sp") .loginProcessingUrl("/api/auth/sign-in") .successHandler(createLoginSuccessHandler()) .failureHandler(createLoginFailureHandler()) .permitAll() .and() .logout() .logoutUrl("/api/auth/sign-out") .logoutSuccessHandler(createLogoutSuccessHandler()) .and() .sessionManagement() .maximumSessions(1) .maxSessionsPreventsLogin(true) .sessionRegistry(sessionRegistry) ;
Key points above:
- I use custom successful and fault-tolerant functions to enter the form - I want to configure the behavior for maximum simultaneous sessions per user
- I want to support spring default session commit protection (changing the session ID at login).
- I want to use the session registry
-... more if I decided to configure it.
I went through the code to see how spring handles form registration. As expected, spring does everything my HttpSecurity configurator HttpSecurity when I use the form login. But when I do my own custom / manual login via SecurityContextHolder.getContext().setAuthentication() , it does nothing. This is because spring does all this with the auth + session file inside the Filter servlet, and my program code cannot really call the filter. Now I can try to add the missing behavior myself, duplicating their code: I see that the filter uses: ConcurrentSessionControlAuthenticationStrategy , ChangeSessionIdAuthenticationStrategy and RegisterSessionAuthenticationStrategy . I can create these objects myself, configure them and call them after my user login. But, something like this to duplicate it that way. In addition, there are still other ways that I am missing - I noticed that when using the form login code path, spring fires some login events that do not fire when I make my user login. And maybe there are other things that I miss or don't understand. The whole process is quite complicated.
So, I feel like approaching this wrong. Should I use a different strategy so that I don't get around so many things spring does for me? Perhaps I should try to make my own AuthenticationProvider to complete this setup login?
* To clarify, my code works more or less. But I feel like I did it using a bad strategy because I had to write code duplicating a lot of the things spring does for me. Also, my code does not perfectly reproduce what spring does, making me wonder what negative consequences might arise. There must be a better way to programmatically reach the entrance.