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