The 'standard' way (AFAIK) to get a Spring Security Context to, say, determine the current logged in user is:
User user = (User) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
However if I run this same code in a JMS Message Driven Pojo (MDP), the context is null.
This make sense because a JMS event doesn't necessarily happen within a session, which is where the security context would live.
But since that's the case, is there a (standard) way for the security to be propagated through to the MDP, or, a way for it to be injected into the MDP?
Thanks,
Roy
Looks like you can't. Anything you need from the session / security has to be put on to the message itself, probably in the headers.
Related
I am using Spring Security and I have created a ApplicationListener for HttpSessionDestroyedEvent (for logout and session expiry events). But this listener's onApplicationEvent method is called on login also which looks like a inappropriate behavior. How do I make this working. Below is the code:
public class MySessionDestroyListener implements ApplicationListener<HttpSessionDestroyedEvent> {
#Override
public void onApplicationEvent(HttpSessionDestroyedEvent httpSessionDestroyedEvent) {
httpSessionDestroyedEvent.getSecurityContexts();
// business logic
}
}
You should be prepared to that. The servlet container generally creates a session before the user is connected. When spring-security authenticates the user, it first close that previous session and creates a new one.
That means that an event HttpSessionDestroyedEvent is triggered both on login and logout. You can differentiate those 2 kinks on event by storing for example the user name in session. If it is present, the session was a regular one and it makes sense to call your business logic, if not it was just a technical one and you shoud just ignore it
If your login page uses a HTTP session in a Servlet 3.0 or older container, the Session Fixation Attack Protection will destroy this session and create a new one (migrateSession), see Spring Security Reference:
Session Fixation Attack Protection
Session fixation attacks are a potential risk where it is possible for a malicious attacker to create a session by accessing a site, then persuade another user to log in with the same session (by sending them a link containing the session identifier as a parameter, for example). Spring Security protects against this automatically by creating a new session or otherwise changing the session ID when a user logs in. If you don’t require this protection, or it conflicts with some other requirement, you can control the behavior using the session-fixation-protection attribute on <session-management>, which has four options
none - Don’t do anything. The original session will be retained.
newSession - Create a new "clean" session, without copying the existing session data (Spring Security-related attributes will still be copied).
migrateSession - Create a new session and copy all existing session attributes to the new session. This is the default in Servlet 3.0 or older containers.
changeSessionId - Do not create a new session. Instead, use the session fixation protection provided by the Servlet container (HttpServletRequest#changeSessionId()). This option is only available in Servlet 3.1 (Java EE 7) and newer containers. Specifying it in older containers will result in an exception. This is the default in Servlet 3.1 and newer containers.
When session fixation protection occurs, it results in a SessionFixationProtectionEvent being published in the application context. If you use changeSessionId, this protection will also result in any javax.servlet.http.HttpSessionIdListener s being notified, so use caution if your code listens for both events. See the Session Management chapter for additional information.
There are some solutions for that problem:
don't use session for login page (in most cases not possible)
update to Servlet 3.1 container
change the Session Fixation Attack Protection to none(not recommended)
adopt your business logic
I am working on bringing WebSockets functionality to my Grails application. I use Atmosphere Meteor plugin 0.7.1 for this purpose.
The workflow is simple:
User logs in the system.
User open page with WebSockets functionality
User clicks a Connect button to establish the connection... and the server doesn't recognize him.
I would like to know which user connected my webSocket.
Usually it's quite easy to detect current user by calling springSecurityService.getPrincipal() in any controller. I managed to inject springSecurityService to my MeteorHandler, however it says that the principal is null. It feels strange for me, as the handler has access to JSESSIONID cookie, so I expect it to retrieve the correct session data.
Also, request.session command returns different HttpSession object, compared to the same command performed in regular controller action.
So is there any way to retrieve current logged in user on webSockets connection?
Thanks in advance.
The Principal object could be easily retrieved from request.userPrincipal.principal
It is exactly the same object as in springSecurityService.getPrincipal()
Find more here: https://github.com/kensiprell/grails-atmosphere-meteor/issues/28#issuecomment-34629462
I'm using System.Net.Http.HttpClient to talk to a RESTful service in an MVC4 application on the back end. Depending on the user making the request the authentication header will be different for communication with the RESTful service, so the values to set in the header should be cached for each user. These values may change during a session's lifetime.
I am using StructureMap for DI. Some questions:
According to this it sounds like there should be a single instance of HttpClient for all requests. Although some say directly injecting the HttpClient may be a bad idea due to it being IDisposabe, others say that it's not necessary to dispose it. So, what is the best way to inject HttpClient?
Is it possible that the single instance of HttpClient can become disposed of or invalidated during run time (maybe the REST server reboots)? If so, then I think there is no choice in directly injecting HttpClient and it must be wrapped in a manager class that will check if the HttClient instance is valid and instantiate a new client if there's a problem. The issue is that I don't see a way make that test.
Where is the best place to cache the user specific authentication header information? I don't think that passing the information to the service layer from the controller is clean, as it seems to be suggested here, so I'm thinking an HttpSession scoped injected object in the data layer is the way to go here, but would love to hear other ideas.
Create the HttpClient when your MVC4 application starts and dispose it when it shuts down. If the server you are calling with the HttpClient reboots that will not require you to create a new instance of HttpClient. TCP connections are managed independently under the covers by the ServicePointManager.
I don't understand your question regarding user specific auth information. Are you trying to get your MVC site to impersonate the user when you call to the RESTful service? If so, then just set the Auth header on each request.
In my grails application I'm using the spring security core plugin.
Is there any method that returns me a jsessionid for a given user simply by providing username and password
Something like this jsessionid:
def myjsessionid = getJessessionidFromUser("username1", "password1")
I'm not familiar with grails, but Spring Security itself provides Concurrent Session Control that can maintain a SessionRegistry. This registry will contain info about all user sessions that you can query e.g. for getting the sessoin id(s) of a given principal.
Use SessionRegistry.getAllSessions() to obtain a list of SessionInformations related to a given principal/user, and then getSessionId() on those objects.
The concurrency control feature is normally used to limit the number of sessions a user may have, but it can be configured not to enforce such restrictions (just maintain the registry). See more about that in the Session Management chapter.
When I create a new entity I would like to grant ACL permissions (aka ACL entry) to this new entity. So far so easy :-)
The problem arises in the following scenario:
An end user can create the entity without being authenticated on the web site.
The service that persists this new entity hence runs without an authentication context.
But: to grant ACEs one needs to have an active authentication context.
Spring's JdbcMutableAclService uses SecurityContextHolder.getContext().getAuthentication() to obtain the current authentication, so there seems to be no way to circumvent this requirement.
Any ideas are greatly appreciated!
Found the answer myself:
In a web application there always is an authentication context. If a user is not authenticated the authentication is org.springframework.security.authentication.AnonymousAuthenticationToken which has a single granted authority: ROLE_ANONYMOUS.
Hence it is simple to grant this user the right to create ACLs. Just configure the PermissionGrantingStrategy to use this role to authorize requests.
The main answer does not work in the current version of Spring (5.3.22) and Spring Security (5.7.3). I doubt it even worked back in 2012, when the answer was posted since it does not make sense.
PermissionGrantingStrategy is a class that only contains the method bool isGranted(Acl, List<Permission>, List<Sid>, boolean) which decides if the principals in the List<Sid> can access the object with the corresponding Acl with any of permissions in List<Permission>.
This is the function that is called when a user want to access an object with a certain permission. This method determines if access is granted or denied.
This has nothing to do with allowing anonymous users to modify existing Acls. The actual problem comes from calling MutableAcl aclService.createAcl(ObjectIdentity) when the authentication context is empty. This is implemented by JdbcMutableAclService, provided by Spring. The problem is that MutableAcl JdbcMutableAclService.createAcl(ObjectIdentity) has this call Authentication auth = SecurityContextHolder.getContext().getAuthentication(); which forces the access to authorization context even though the Sid could be passed to the createAcl method, so the business logic would be able to createAcls for the chosen users passed in the arguments.
Instead, we have this call which makes it impossible to use Acls from an unauthenticated context if we want to keep using the Spring Classes.
So, the solution would be reimplement the JdbcMutableAclService so the createAcl method does not call the authentication context, instead it has an extra arguments to indicate the Sid of the user we want to create the Acls.
If anyone has any idea on how to do that it would be greatly appreciated.
I am trying to initialize my Acl tables programmatically when my web app starts, but I cannot do it because my initialization code does not have any authantication.