Springs returns null from SecurityContextHolder.getContext().getAuthentication(); on handling eror 404 (when not mapped url entered). But it works fine on exceptions(500) or security errors(403, Spring SecurityContext returning null authentication on error pages) thanks to ExceptionTranslationFilter.
Why is this happening and what i can change to obtains security context?
Solved by storing user principal in session attributes.
Related
Updated spring security context not available on redirect
In one of my controllers - before redirect - I execute the following code:
Credential oldCredential = (Credential) authentication.getCredentials();
Authentication authenticationToken = new AuthenticationToken(new Credential(oldCredential.getCookieValue(), oldCredential.getPassword()),
updatedAccountDetails);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
When I inspect the authentication object after setting it I see the authentication context is correctly updated. After executing the code above I redirect.
After the redirect completes the security context loaded is the old one! That is: when I inspect the security context it contains not the new authentication token.
If I do the following for test - I add the setAttributE(...) after setAuthentication(...) - I get the new authenticationToken in my session but under (obviously) a different key: test. I tried a couple of strategies for the SecurityContextHolder (MODE_THREADLOCAL, MODE_INHERITABLETHREADLOCAL, MODE_GLOBAL) although I think the default MODE_THREADLOCAL is suited for my application.
request.getSession(false).setAttribute("test", authenticationToken);
The strange thing is that if I debug and check in SecurityContextPersistenceFilter the HttpSessionSecurityContextRepository I see that after the redirect the loaded context is actually the new one! For some reason - unknown to me at this moment - this load is however at some later point replaced(?) with the old security context.
Make sure that you've called setAuthenticated(true) otherwise the security context is not updated.
I am using OAuth2 client credentials flow with Spring Security and i'm able to obtain an access token driven by the oauth_client_details table.
The issue is that when the token is issued I see that the userAuthentication is null so it returns the principal as a string. Looking at OAuth2Authentication:38 here :
public Object getPrincipal() {
return this.userAuthentication == null ? this.storedRequest.getClientId() : this.userAuthentication
.getPrincipal(); }
From the docs -
An OAuth 2 authentication token can contain two authentications: one for the client and one for the user. Since some OAuth authorization grants don't require user authentication, the user authentication may be null.
I am using my own user details service and returning a UserPrincipal. This works for form login and http basic without issues. However with OAuth2 authentication the principal is a string instead of UserDetails.
I get the currently logged in user by
SecurityContextHolder.getContext().getAuthentication() in server side and do some logging on users.
Here is the question:
Suppose I have three user logged in.
How the server side can identify the user just simply calling SecurityContextHolder.getContext().getAuthentication(); ?
Thanks for your reply.
By default there are 3 important things here:
HTTP session - stores authentication object between requests
Servlet API filter - populates SecurityContextHolder before each request from HTTP session (and stores authentication object back once the request has completed)
ThreadLocal - stores authentication object during request processing
After authentication corresponding SecurityContext object is stored in HTTP session.
Before each request processing special SecurityContextPersistenceFilter is fired. It is responsible for loading of SecurityContext object from HTTP session (via SecurityContextRepository instance) and for injecting SecurityContext object into SecurityContextHolder. Take a look at the source code of SecurityContextPersistenceFilter class for more details. Another important part is that by default SecurityContextHolder stores SecurityContext object using ThreadLocal variable (so you will have a different authentication object per thread).
EDIT. Additional questions:
HTTP session is saved in client's browser and updated between requests. No, HTTP session is stored in server side. It is linked to some user via session coockie (browser send this cookie during each request).
SecurityContext, SecurityContextHolder and SecurityContextRepository are instances in Server side. They are used on server side. But SecurityContextHolder is not an instance, it is a helper class with static methods.
ThreadLocal is a variable storing SecurityContextHolder which stores SecurityContext No, SecurityContext is stored in ThreadLocal variable. SecurityContextHolder is a helper class that may be used to get/set SecurityContext instance via ThreadLocal variable.
If there are three connections, then there will be three SecurityContext object in Server. Yep.
One SecurityContextHolder stores one SecurityContext No, the same static methods of SecurityContextHolder used by all threads to get/set corresponding SecurityContext.
And suppose there are three SecurityContext instances in Server Side, how does it knows which one refers to that corresponding client? ThreadLocal variable has different values for different threads.
For every logged-in user, there will be different sessions. Every session have its own configuration. Therefore, at server side, SecurityContext load data specific to a session. You can visualise data in SecurityContext as a map(key-value) pair.
I have an application exporting web services, with a configured Spring Security SecurityFilterChain (with SecurityContextPersistenceFilter among others, which is required for the rest).
My application also uses Spring Security to secure method invocations.
I have following error when method security is triggered:
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
The 2nd part requires an Authentication in SecurityContextHolder as showed in org.springframework.security.access.intercept.AbstractSecurityInterceptor (line 195):
SecurityContextHolder.getContext().getAuthentication();
But, SecurityContextPersistenceFilter removes it before method invocation is triggered, as shown in
org.springframework.security.web.context.SecurityContextPersistenceFilter (line 84)
SecurityContextHolder.clearContext();
What can I do to have this object in SecurityContextHolder when method invocation is triggered?
Thank you in advance.
I'm using Spring Security 3.0.8-RELEASE
SecurityContextHolder.clearContext() will be called only after request processing completion. So normally all your application logic code will be executed before this line, and there is no problem at all. But the problem may be present if you execute some new thread in your code (by default security context will be not propogated). If this is your case then you can try to force context propogation to child thread. If you use only one thread then make sure that all your code is covered by spring security filter chain (may be you have some custom filter that executed around spring security filter chain?).
OK, my application is placed over Apache CXF DOSGi 1.4 to generate REST endpoints. Apache CXF interceptors cause an unexpected behaviour and SecurityContextHolder.clearContext() is called before finishing the request processing.
More information about this bug can be found here.
I have successfully used spring security to login users. But the issue is, right now on my web page, when a new user is created, he/she has to again go back to sign in page to login which of course uses spring security. Is there a way to login the user automatically using Spring Security as soon as a new user is created?
do this
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken (userDetails, password2, userDetails.getAuthorities());
authenticationManager.authenticate(auth);
if(auth.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(auth);
}
I have never done it, but i think you should do what it is described in the doc.
Once the request has been authenticated, the Authentication will
usually be stored in a thread-local SecurityContext managed by the
SecurityContextHolder by the authentication mechanism which is being
used. An explicit authentication can be achieved, without using one of
Spring Security's authentication mechanisms, by creating an
Authentication instance and using the code:
SecurityContextHolder.getContext().setAuthentication(anAuthentication);
Note that unless the Authentication has the authenticated property set to true, it will still be authenticated by any security interceptor (for method or web invocations) which encounters it.