Most of my application is secured with method level security (AspectJ, but it doesn't matter) and now that I am trying to call some code from within application itself (not controllers, but e.g. EventListener) I can't help to wonder if Spring Security provides some out-of-box way of giving Authentication object to the application itself, otherwise I cannot get past my method security since application has null security objects (Authentication in SecurityContext, if it even exists - depends on situation, You might have to init it first).
Sure I can do something like this (just before running relevant code):
UserDetails ud = User.builder()
.username("APPLICATION")
.password("APPLICATION")
.roles("APPLICATION")
.build();
Authentication auth = new UsernamePasswordAuthenticationToken(ud, ud.getPassword(), ud.getAuthorities());
SecurityContextHolder.getContext()
.setAuthentication(auth);
But is it safe to do this in deployment (security-wise)?
Is there any guarantee on which thread will own this SecurityContext? What about other threads and their tasks?
Once set, can it stay there? Will it for the rest of app's run (can be days/months), context could be reloaded, etc. I lack deep Spring knowledge to know what happens Thread-wise inside Spring.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 days ago.
Improve this question
Spring Boot - Angular Application:
Why does my method return "AnonymousUser" when called from one controller, but the correct user id when called from another controller?
I have a method that returns the logged-in user:
#Override
public String getLoggedUserName() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
When I call it from a controller, it returns the name of the logged-in user, but when I call it from another controller, it returns "AnonymousUser". Why is this happening?
I don't know if it can be useful as additional information but authentication is via Keycloak
I'll answer first to what I guess your actual question is: "how to be sure to have a JwtAuthenticationToken in the security-context of a #ResController?"
Configure your app as resource-server with a JWT decoder
Protect entry-points with isAuthenticated() either form security filter-chain configuration or #PreAuthorize (or equivalent) on controller class or method (with #EnableMethodSecurity somewhere in the config)
Off course, do not explicitly replace the default Authentication implementation for successful authorizations... (when providing an authentication converter for instance)
Now a complete answer to what you formulated and is way wider as the type of Authentication implementation in the security context of controller method invocation varies depending on quite a few factors.
Runtime
Let's start with "real" invocations (spring app up and running, nothing mocked):
request is not authorized, then an AnonymousAuthenticationToken is put in the security context. Depending on the security config, this could be because of missing or invalid access token (expired, wrong issuer or audience, bad signature, ...), missing basic header, etc., or because the type of authorization is not the right one (for instance a Bearer token on a route intercepted by a security filter-chain expecting basic authentication)
request is successfully authorized => default authentication depends on the security conf
resource-server with JWT decoder, then JwtAuthenticationToken is used (can be accessed verridden by configuring http.oauth2ResourceServer().jwt().jwtAuthenticationConver(...)
resource-server with access token introspection, then BearerTokenAuthentication is used ( override with http.oauth2ResourceServer().opaqueToken().authenticationConver(...))
client with oauth2Login, then OAuth2AuthenticationToken is used
etc., the list continues for non OAuth2 authentications (just have a look at Authentication type hierarchy)
Tests
Test security context can be set for tests in plain JUnit using annotations like #WithMockUser or using MockMvc (respectively WebTestClient for reactive apps) and either annotations or request post processors (respectively WebTestClient mutators).
The type of Authentication injected depends on the annotation (or mutator / post-processor) used. For instance, #WithMockUser builds a UsernamePasswordAuthenticationToken which is rarely adapted to an OAuth2 context. Mutators from SecurityMockMvcRequestPostProcessors from spring-security-test or annotations like
#WithMockJwtAuth, #WithMockBearerTokenAuthentication or #WithOAuth2Login from spring-addons are generally better suited.
Tutorials for both runtime config and tests
I wrote some available from there: https://github.com/ch4mpy/spring-addons/tree/master/samples/tutorials
I have some perplexity about the SecurityContext propagation in Spring Integration.
Here is the point of the documentation:
http://docs.spring.io/spring-integration/reference/htmlsingle/#security-context-propagation
My perplexity are the following:
(1) To be sure that our interaction with the application is secure,
according to its security system rules, we should supply some security
context with an authentication (principal) object. The Spring
Security project provides a flexible, canonical mechanism to
authenticate our application clients over HTTP, WebSocket or SOAP
protocols (as can be done for any other integration protocol with a
simple Spring Security extension) and it provides a SecurityContext
for further authorization checks on the application objects, such as
message channels. By default, the SecurityContext is tied with the
current Thread's execution state using the
(ThreadLocalSecurityContextHolderStrategy). It is accessed by an AOP
interceptor on secured methods to check if that principal of the
invocation has sufficent permissions to call that method, for example.
This works well with the current thread, but often, processing logic
can be performed on another thread or even on several threads, or on
to some external system(s).
This means that the SecurityContext (normally) is accessible only for the current Thread. Right?
So, how to make it accessible for another thread of another application (integrated with Spring Integration) ?
(2) Standard thread-bound behavior is easy to configure if our application is built on the Spring Integration components and its
message channels. In this case, the secured objects may be any
service activator or transformer, secured with a
MethodSecurityInterceptor in their
(see Section 8.8, “Adding Behavior to Endpoints”) or even
MessageChannel (see Section D.2, “Securing channels” above). When
using DirectChannel communication, the SecurityContext is available
automatically, because the downstream flow runs on the current thread.
But in case of the QueueChannel, ExecutorChannel and
PublishSubscribeChannel with an Executor, messages are transferred
from one thread to another (or several) by the nature of those
channels. In order to support such scenarios, we can either transfer
an Authentication object within the message headers and extract and
authenticate it on the other side before secured object access.
Or, we can propagate the SecurityContext to the thread receiving the
transferred message.
This means that we have to extract the Principal manually? If yes, how?
Or it's enough to use the propagation aspect, from 4.2 version?
(3) Starting with version 4.2 SecurityContext propagation has been
introduced. It is implemented as a
SecurityContextPropagationChannelInterceptor, which can simply be
added to any MessageChannel or configured as a
#GlobalChannelInterceptor. The logic of this interceptor is based on
the SecurityContext extraction from the current thread from the
preSend() method, and its populating to another thread from the
postReceive() (beforeHandle()) method. Actually, this interceptor
is an extension of the more generic
ThreadStatePropagationChannelInterceptor, which wraps the
message-to-send together with the state-to-propagate in an internal
Message extension - MessageWithThreadState, - on one side and
extracts the original message back and state-to-propagate on another.
The ThreadStatePropagationChannelInterceptor can be extended for any
context propagation use-case and
SecurityContextPropagationChannelInterceptor is a good sample on the
matter.
"Starting with version 4.2 SecurityContext propagation has been introduced." => Ok, very well.
But: "It is implemented as a SecurityContextPropagationChannelInterceptor, which can simply be added to any MessageChannel or configured as a #GlobalChannelInterceptor."
What does it mean? I have to implement an interceptor that extends "SecurityContextPropagationChannelInterceptor" ?
What I have to "add" in my <int:channel> configuration?
And if I use <int:channel-interceptor> (the same of #GlobalChannelInterceptor), it's different from using <int:interceptors> ?
Other perplexity:
"The logic of this interceptor is based on the SecurityContext extraction from the current thread from the preSend() method, and its populating to another thread from the postReceive()
(beforeHandle()) method."
But why there are a "obtainPropagatingContext" method and a "populatePropagatedContext" method in the SecurityContextPropagationChannelInterceptor class?
Where is made the propagation? In the preSend() / postReceive() methods, or in those two methods?
Furthermore, I tried to propagate the SecurityContext to an external application, without success...
Any explanations about this argument would be appreciated.
You have a lot of questions here, but let me try to answer to them.
What does it mean? I have to implement an interceptor that extends "SecurityContextPropagationChannelInterceptor" ?
No, there is such an interceptor in the Framework out-of-the-box. What you have to do to understand how to add interceptor to MessageChannel: http://docs.spring.io/spring-integration/reference/html/messaging-channels-section.html#channel-configuration-interceptors.
Or like this:
#Bean
#GlobalChannelInterceptor(patterns = {
"#{'queueChannel'}",
"${security.channel:executorChannel}",
"publishSubscribeChannel" })
public ChannelInterceptor securityContextPropagationInterceptor() {
return new SecurityContextPropagationChannelInterceptor();
}
See their JavaDocs for more information.
But why there are a "obtainPropagatingContext" method and a "populatePropagatedContext" method in the SecurityContextPropagationChannelInterceptor class?
SecurityContextPropagationChannelInterceptor extends ThreadStatePropagationChannelInterceptor<Authentication> , where obtainPropagatingContext and populatePropagatedContext are just generic method to extract some current State in the preSend() (on Thread) and provide that State for population/manipulation in the postReceive(), which may happen in the different Thread.
Yes, SecurityContext is thread-bound in Spring Security and the logic to be sure that we can perform a secured function is fully based on the ThreadLocal variable. That's why we have to transfer it that way. The "propagation" is a process not state.
Not sure what you mean about "external application", but there is only one mechanism to do that: send credentials together with the request to that application.
In my application, when a user updates their username, I want to clear that authentication from the security context because the old username was used in basic auth calls.
In my controller doing the update, this is easy enough with
SecurityContextHolder.getContext().setAuthentication(null);
But I'm looking for a way to access the current security context without using static methods for ease of unit testing (not to mention the static call doesn't seem very "springy").
The answer here looks pretty close to what I'm looking for, but I'm hoping there's a way to do this without writing a wrapping class. I also tried to inject SecurityContextHolderStrategy into my controller constructor (as was implied I might be able to do in that answer and the related jira) and there was no bean defined of that type.
So: Is there a way to access the current SecurityContext in a Spring Controller without using SecurityContextHolder static methods?
My version of spring security is 3.2.5.RELEASE.
When i am trying to use #PreAuthorize("#accessControl.hasActivity('abc')") on spring controller method i am getting Authentication object was not found in security context.
After debugging found that DispactcherServlet is throwing this exception.
i have set SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
when i first create Authentication object and set in security context
Also tried with SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); but no luck still it does not work.
I am not able to understand why spring is servlet is throwing this exception
First, doing authentication in a Spring MVC interceptor is odd. Consider using a filter before DispatcherServlet. There is a lot of documented examples.
Secondly, SecurityContextHolder.setStrategyName re-initializes the strategy and possibly makes all previously authentications inaccessible so you must only call it once (if any time), before any authentication is made.
Thirdly, if you want to set the current authentication to be used by #PreAuthorize and are sure what you are doing, use SecurityContextHolder.getContext().setAuthentication(anAuthentication);. In most cases, there is a suitable filter in the API that already does this for you.
In my spring-3 application I have an AuthenticationInterceptor (which is basically an interceptor) that checks for the privileges for a user. I am using a Spring's MultipartResolver to try an upload a file to the server.
The problem that I now face is that I wish to perform different actions based on user privileges, in case of a MaxUploadSizeExceededException.
However I see that this exception is occurring at the DispatcherServlet level and is caught by HandlerExceptionResolver
I want to be able to call my AuthenticationInterceptor before any of this happens?
Is there a straightforward way.
The problem is that the exception occurs BEFORE the request is dispatched to a controller and because of that, your interceptor also never fires. I guess you have that part figured out already.
Want to get around that...
For starters, I would move the authentication mechanism out IN FRONT of the servlet by using servlet filters. This being said, it makes little or no sense to roll your own solution in that space when a great product like Spring Security can do that for you.
Once you transition to Spring Security (or similar), the user's SecurityContext (roles, permissions, etc.) will have been resolved by the time the exception occurs and is caught.
Now, if I'm reading your question correctly, it seems you might like to respond to the exception differently based on the user's roles, permissions, etc. That should be possible at this point. You'd implement a custom HandlerExceptionResolver that inspects the SecurityContext to see if the user has a certain role or permission and then respond accordingly.
Hope that helps!
There are two basic ways to handle doing something in-stream before the Handler code gets called:
Implement the HandlerInterceptor interface, and code the code you want to run in the preHandle method
Create an Aspect using #Aspect and configure a pointcut to run #Before the method call
In either case, you could check the logged-in user's Roles using SecurityContextHolder.getContext().getAuthentication().getAuthorities() and then decide what to do based on Role membership.