Spring Security Authentication Not Persisting Between Controllers

307 views Asked by At

I'm trying to manually set the authentication in order to implement a system of user permissions. My ultimate goal is to be able to use the @PreAuthorize() annotation to restrict certain methods. Below is my security configuration.

@Order(1)
    @Configuration
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    @Conditional(OpenSecurityCondition.class)
    public class OpenSecurityConfig extends WebSecurityConfigurerAdapter {

        private final PasswordEncoder passwordEncoder;

        public OpenSecurityConfig(PasswordEncoder passwordEncoder) {
            this.passwordEncoder = passwordEncoder;
        }
        
        @Bean("authenticationManager")
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
              http
                      .csrf()
                      .disable()
                      .authorizeRequests()
                      .anyRequest()
                      .permitAll();
        }
    }

Here is where I manually set the authentication object:

 UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                username, null, privileges);
        SecurityContextHolder.getContext().setAuthentication(authToken);
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        System.out.println("Principal: " + auth.getPrincipal());
        System.out.println("Name: " + auth.getName());
        System.out.println("Authorities: " + auth.getAuthorities());
        System.out.println("Credentials: " + auth.getCredentials());
        System.out.println("Class: " + auth.getClass());

I'm printing some of the attributes of the authentication object just to prove to myself that they are set correctly. This is the output of the above print statements:

Principal: John Doe
Name: John Doe
Authorities: [Calendars-R, Carrier-R, Config-R, Default-R, Holiday-R, Location-R, ShipMethodCustom-R, ShipMethodOverride-R, Shipment-R, Simulator-R, Zones-R]
Credentials: null
Class: class org.springframework.security.authentication.UsernamePasswordAuthenticationToken

Everything looks good so far. The principal, and more importantly, the proper authorities are there. This will allow me to use the @PreAuthorize annotation to check for those authorities. However, in a different controller, I'm noticing that the authentication object has lost all of the information that I just set. In this other controller, if I call the following:

System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal());

It prints

anonymousUser

...and all of the other authorities and information that I had previously set are lost. This prevents me from being able to use the @PreAuthorize annotation to secure my application. My question is, how can I get the Authentication object to persist across different requests? Why would this not be its default behavior?

For your convenience, I'll go ahead and throw some more code in here. Here is the primary controller handling the login:

@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class UserController {

    private final UserService userService;
    private final RoleService roleService;
    private final UserDetailsService userDetailsService;
    private final AuthenticationManager authenticationManager;

    @PostMapping
    public void receiveUsername(@RequestBody Map<String, Object> json_data, HttpServletRequest request, HttpServletResponse response) {
        String username = json_data.get("username").toString();

        User foundUser = userService.findByUsername(username);

        if(foundUser == null) {
            System.out.println("User not found. Creating new user.");
            foundUser = userService.create(new User(username));
            roleService.assignRole(foundUser.getId(), roleService.USER);
        }
        
        List<Role> userRoles = (List<Role>) foundUser.getRoles();

        UserDetails details = userDetailsService.loadUserByUsername(username);
        List<GrantedAuthority> privileges = details.getAuthorities().stream().collect(Collectors.toList());
        System.out.println(privileges);

        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(username, "password", privileges);
        Authentication auth = authenticationManager.authenticate(authToken);
        SecurityContext sc = SecurityContextHolder.getContext();
        sc.setAuthentication(auth);
        HttpSession session = request.getSession(true);
        session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);
    }
}
0

There are 0 answers