Issue
I have added spring authentication manually in rest/soap services calls by intercepting incoming rest/soap requests using HandlerInterceptor and SoapHandler. I send my logged in username from client to web service by adding it in soap/rest header. I intercept incoming request and set manual authentication. When I found authentication is already there, I skip setting it. I am assuming that for every new rest/soap request there will be no authentication on web service(server side). It's giving me username which is not of current user for new request.
public UserDetails getUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
UserDetails user= null;
if (auth != null && !(auth instanceof AnonymousAuthenticationToken)) {
// userDetails = auth.getPrincipal()
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = null;
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
user= (UserDetails ) principal;
} else {
username = principal.toString();
}
}
return user;
}
public void setUser(String username) {
// creating spring security context manually
try {
// Must be called from request filtered by Spring Security,
// otherwise SecurityContextHolder is not updated
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
Authentication authentication;
authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && !(authentication instanceof AnonymousAuthenticationToken)) {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails user;
String uname;
if (principal instanceof UserDetails) {
user= (User) principal;
uname = user.getUsername();
} else {
uname = principal.toString();
}
LOGGER.info("Found username in Spring context: " + uname);
} else {
LOGGER.info("Spring context not found: ");
LOGGER.info("Setting manual authentication.. Username: " + username);
// grantedAuthorities.add(new SimpleGrantedAuthority("USER"));
UserDetails contextUser = new User(username, username, true, true, true, true,
grantedAuthorities, null);
authentication = new UsernamePasswordAuthenticationToken(contextUser, username, grantedAuthorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
LOGGER.error("Failure in creating spring security context authentication", e);
}
}
Solution
It is because SecurityContext
is stored in the ThreadLocal
and you have never clear it from the ThreadLocal
after the web service thread completes processing the request , which means if the same thread is used to process the next request , it still keeps SecurityContext
of the previous request.To be precise , it always keep the user who is the first to use that thread in your case.
The quick fix is that you have to clear SecurityContext
after completing each request :
SecurityContextHolder.clearContext();
Answered By - Ken Chan