Spring Security ApplicationListener<HttpSessionDestroyedEvent> is called on login - spring-security

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

Related

JSESSIONID use existing session cookies

Spring Session uses a different format for its session cookies than Tomcat does. So if you implement Spring Session, even if you would name the session cookie JSESSIONID, all the users have to login again.
This is a point where you potentially lose users, because nobody likes to login. Perhaps this is an edge case, and certainly it's not worth a huge amount of trouble, but I'm curious if it's possible for existing users to use their already stored Tomcat session cookies?
You can implement your own org.springframework.session.web.http.CookieSerializer that matches Tomcat's default cookie serialization and register it as a bean.
Spring Session configuration will then pick it up and use it - see org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration#setCookieSerializer for more details.

Getting sessionId without accessing the session

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.

Jetty with JDBCSessionManager and spring web security

In my application I have an embedded jetty server (version 8.1.2) running a web application that uses spring web security.
The jetty server is configured to use the JDBCSessionManager
One of the security filters that spring employs is a subclass of AbstractAuthenticationProcessingFilter, in it, it has a SessionAuthenticationStrategy which by default is a SessionFixationProtectionStrategy. This protection strategy creates a new session, as a copy of the original session and invalidates the old one.
Now when I try to login to the web application, I see that a new session is created, but the authentication attributes that are added to the new session are not written back to the database. Moreover, I see that the old session is written to the database with new attributes even though it was invalidated.
Finally, when a new http request arrives as part of the new session, it does not pass authentication because of the above.
After some investigation, I found that this behavior does not happen in older versions of jetty (I tried 7.1.4), and I see that the new session data is written to the database.
I could of course solve this issue by any of the following:
Use an older version of jetty
Disable the session fixation protection strategy
Use the default session manager instead of the JDBCSessionManager
But assuming non of the above options are valid for me, I was wondering if there is any solution to this problem.
Thanks!
Resolved in newer releases of jetty 8, at least 8.1.6 :)

ASP.NET MVC: A PreAuthorize-like event, Good throttle point for concurrent logons?

I want to allow a new login to 'kick' a prior login session by the same account, in ASP.NET MVC.
It seems pretty clear that I'll give each browser a cooking representing the session ID. I'll track the currently active session ID in a server-side cache. If an already-active user attempts to log in, I'll verify the business logic (username, password, has been at least 15 minutes since last activity), and then update the active session ID cached at the server.
Now my issue is, a browser is holding an invalid session ID. What is the best point for me to inject a rejection or redirect to sign-in for this scenario?
I could modify the AuthorizeAttribute, but it seems like there should be a cleaner place to do this that won't require me to search and replace all my Authorize attributes, for example via a Global.asax event, or a controller event (I've already extended Controller in my project).
For example, if PreAuthorize existed, I would write some code there to test the request's cookies for a valid user/session ID pair, and if it didn't exist, I could simply remove the authentication cookie from the request, which would result in a standard unauthorized redirection.
So after a bit of research, it seems that a custom AuthorizeAttribute would typically be the correct approach. However, in my case, since I already had a custom role provider implemented, it was just a line of code to do it there. This also benefited me because I only wanted session concurrency for a single role. A side effect is that any use of web.config to control access to static files by role is also in-effect for session concurrency.

External authentication using Spring Security

We got our own central session management. Generally user can authenticate over it with an username and password, and as a result he gets an session_id. All other operations are done with that session_id. Let's say that the session management is accessed by a XML RPC.
I have two cases to implement:
Central web application made in Spring, which has login form
External web applications also made in Spring, which are relying on
passed session_id only.
Few more notices regarding system:
- session_id is stored in a cookie (after successful login, I have to add cookie to a response)
- every page request has to check session_id validity in session management system
I'm quite new to Spring, so I'm struggling to understand where and how to implement my custom logic.
My questions are:
What parts of a system I have to implement to have my own login
logic (got to have access to a response object too - to set cookie)?
I tryed something with extending UsernamePasswordAuthenticationFilter and implementing my own
AuthenticationManager, but I'm not sure that I'm going the right
way.
Is there point where/how can I implement my "every request session
check" in Spring Security manner?
session_id is stored in a cookie (after successful login, I have to add cookie to a response)
Do this in a AuthenticationSuccessHandler that is configured into your <form-login> element:
<form-login authentication-success-handler-ref="authenticationSuccessHandler"/>
External web applications also made in Spring, which are relying on passed session_id only.
Create a new filter where you check for the session_id cookie. If the cookie is not present or if it is invalid redirect to the central web application for the user to log in. If the cookie is present and valid and the user isn't already authenticated then create a new Authentication and add it to the SecurityContextHolder.
Take a look at RememberMeAuthenticationFilter.doFilter() for an example of what you want to do in your filter.
Add this filter to the filter chain using the <custom-filter> element.

Resources