Spring Security deletes session form the database when user logs out - spring

I'm implementing spring security in my project and have used mysql database to store sessions. Everything works fine but when the user logs out, its session is also deleted from the database which I do not want. I only want session to be invalidated but not deleted from the database.
On debugging, I found :
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
Assert.notNull(request, "HttpServletRequest required");
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
logger.debug("Invalidating session: " + session.getId());
**session.invalidate();**
}
}
if (clearAuthentication) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(null);
}
SecurityContextHolder.clearContext();
}
This code is from SecurityContextLogoutHandler class.
Further, the code execution goes in:
private final class HttpSessionWrapper extends HttpSessionAdapter<S> {
HttpSessionWrapper(S session, ServletContext servletContext) {
super(session, servletContext);
}
#Override
public void invalidate() {
super.invalidate();
SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true;
setCurrentSession(null);
clearRequestedSessionCache();
**SessionRepositoryFilter.this.sessionRepository.deleteById(getId());**
}
}
The last line of the function deletes the session which I do not want.
My question is can I stop spring security from deleting sessions from the DB when user logs out or this is how spring security works?

Is there any specific reason why you don't want to delete session from DB once user log's out ? This is pretty much common behavior. Session is representing your logged in client. Once client log's in (provide valid credentials, password with username for example) session ID is created and sent to client. This session ID is representing valid logged in connection. On subsequent request's from this client he will only send this session ID inside header, your app will check if this session ID is stored inside valid session's (your DB for example) and if it is this request is considered authenticated (therefore client doesn't have to send his credential's which has to be verified with each request, he is only sending session ID). Once client log's out the session ID is invalidated since with logout his connection is no longer authenticated. Therefore yes this is how spring security work's, there is no need to persist invalidated session's. You would also have to implement custom mechanism for clearing session's from DB (when will be session cleared if not at time of user logout). Also you might consider to use session pool inside memory instead of DB.
Edit: i don't how spring check's valid session's in case of DB session pool but at some time it has to access DB read all session's so it can find out which session ID's are valid (i guess this is done for each after - login request at least). How could be invalidated session in your case be persisted inside database session pool when valid session's are defined by that pool at same time ?

Related

Session Invalidation occurs via Web Command after Login using SSO. After Logout and Re-Login - Able to access pages from previous session

I have a Web Application that is deployed on Websphere 9. The application has a SAML servlet (SSO Login) and using Web Commands subsequent operations are performed on the application. In one of the Web Commands, the session invalidation code runs.
invalidateAllWebAppSessions(request)
public static void invalidateAllWebAppSessions(HttpServletRequest req) {
try {
IBMSessionExt sessExt = (IBMSessionExt) req.getSession();
if (sessExt != null) {
sessExt.invalidateAll(true);
}
} catch (IllegalStateException e) {
LOG.error("Exception in invalidating Session", e);
}
}
This invalidation code runs perfectly and I have verified using request.getSession(false) == null that the session has been invalidated successfully.
Afterwards when I am logging out and logging back in (The webcommand runs again and previous session is invalidated and new session is created.) Now when I long press the browser back button and try moving to any of the screens of the previous session, I am able to directly access that screen. This should not be accessible as I have invalidated previous session.
If I directly invalidate existing session in the SAMLServlet there is no problem and my issue is resolved, but if I invalidate session in web command then the issue remains.

HTTPRequest.getSession returns a fresh session after session is invalidated

I have developed a web app currently hosted in tomcat 8.5.I5. I am trying to implement SSO with IDP and here I have used filters for this. After sucessful login I set the user name as following.
HttpSession httpSession = request.getSession();
httpSession.setAttribute(SESSION_USERNAME, subject);
When validating used the following code.
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession();
String userName = (String) session.getAttribute(SSOHelper.SESSION_USERNAME);
if (userName == null && request.getRequestURI().contains("dashboard.xhtml")) {
Logout is implemented as follwing
request.getSession().invalidate();
The problem is this only works for the first time. Second time it keeps on asking the login. Seems the session is created per requested.
The issues seems to be when you define the host name without a dot (.). For example I have used localhost for my testing. After adding a entry to hosts file with domain name malaka.com, and used to access the web app, issue was resolved.

Why does Spring the security remember-me implementation remove all active tokens upon logout?

Is there any reason why logging off from one device removes all persistent login tokens (remember-me) for a user?
In my case for example a user can be logged in from desktop and tablet, and a user logging off from the desktop should not cause the remember-me token used by the tablet to be removed.
Current implementation in JdbcTokenRepositoryImpl only accepts a username:
public void removeUserTokens(String username) {
getJdbcTemplate().update(removeUserTokensSql, username);
}
so I created a custom implementation of the RememberMeServices and PersistentTokenRepository that only allow a specific series to be deleted for a user:
public void removeUserTokens(String username, String presentedSeries) {
getJdbcTemplate().update(removeUserTokensSql, username, presentedSeries);
}
Is this safe?
Remember me is not about being remembered after log out. If the user takes explicit action to log out, the remember me token should be invalidated. Think about someone using a public computer who accidentally selects remember me. If they explicitly log out, the remember me token must be invalidated.
Remember me is only about being remembered after session time out. The reason is that historically sessions were saved in memory. If there were too many active sessions, then it would cause out of memory errors. This is really not necessary now that the session can easily be stored in am external data store using something like Spring Session.

Why the session attribute is coming as null

A HTML5 UI is connected to the backend (REST Jersey to business logic to Hibernate and DB). I need to create and maintain a session for each user login until the user logs out.
I am clueless on how to approach this problem.
I followed this approach
Initially when the User is successfully logs in , i am setting attribute under session as shown below
HttpSession session = request.getSession(true);
session.setAttribute("islogged", "islogged");
String value = (String)session.getAttribute("islogged");
System.out.println("****************** The User Logge in Value"+value);
Later in a different page i am checking if the user is logged in or not this way
public String checkIfUserLoggedIn() throws JSONException,ClassNotFoundException, SQLException
{
HttpSession session = request.getSession();
String value = (String)session.getAttribute("islogged");
if(value==null)
{
// always its coming here only
}
}
I agree with francesco foresti, please do not rely on HTTP session without Auth. this is unsafe, and quite dangerous for your app.
Have you been implementing a specific session mecanism ?
If not, jersey as it is will not store session data as it. Every call that you will make will give you a session id that is different from yours.
You have to make authentication & use the auth token in order to identify you session.
use JAX-RS
Please do use an auth mecanism as defined : https://jersey.java.net/documentation/latest/security.html
#Path("authentication")
#Singleton
public static class MyResource {
// Jersey will inject proxy of Security Context
#Context
SecurityContext securityContext;
#GET
public String getUserPrincipal() {
return securityContext.getUserPrincipal().getName();
}
}
or use another framework : Spring, Shiro.... etc.
I really prefer that solution, since another framework will implement a lot of stuff for you. You gain a lot of time doing so.
Please take a look to official jersey doc: https://jersey.java.net/documentation/latest/index.html
I wouldn't rely on the http session. My approach would be to put an "Authorization" field in the header of the response that the server returns when the user logs in, and ask the user to put the very same header in each suqsequent call. In this header you put the informations that help the server find the identity of the user
(take a look at what twitter does as an example : https://dev.twitter.com/oauth/overview/authorizing-requests). The server could save the informations about the logged in user in the database, or You could create a Map in a Singleton that would serve as the "authorization gatekeeper" for your services.

Check if a session id valid by sessionId only in tomcat?

How is it possible to check if a tomcat session is valid by knowing only the sessionid?
I want to create a REST endpoint that checks if a session is valid by passing it just the sessionId. The session cookie is not available in this request.
You can use the HttpServletRequest#isRequestedSessionIdValid method to check whether the request session is valid or not:
#GET
public Response someMethod(#Context HttpServletRequest request) {
System.out.print(request.isRequestedSessionIdValid());
}

Resources