Akshay Bande
Akshay Bande

Reputation: 2587

Spring security context manual authentication giving strange results

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

Upvotes: 0

Views: 2535

Answers (1)

Ken Chan
Ken Chan

Reputation: 90517

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

Upvotes: 2

Related Questions