We use Spring-session. And we use JavaMelody for monitoring sessions.
JavaMelody uses net.bull.javamelody.SessionListener for monitoring sessions. It is implementation of HttpSessionListener from servlet API.
Spring-session have SessionEventHttpSessionListenerAdapter for capability with servlet api session listeners. It listens Spring session events and submit http session events. Wherein it creates ExpiringSessionHttpSession (wrapper for spring session).
private HttpSessionEvent createHttpSessionEvent(AbstractSessionEvent event) {
ExpiringSession session = event.getSession();
HttpSession httpSession = new ExpiringSessionHttpSession<ExpiringSession>(session,
this.context);
HttpSessionEvent httpSessionEvent = new HttpSessionEvent(httpSession);
return httpSessionEvent;
}
We use SessionEventHttpSessionListenerAdapter for working net.bull.javamelody.SessionListener. Spring sessions successful displays in JavaMelody sessions view.
But we have a problem. JavaMelody button "invalidate session" doesn't work correct. JavaMelody uses http session method invalidate for handling this button. The implementation method in ExpiringSessionHttpSession (part of Spring) looks like dummy:
public void invalidate() {
checkState();
this.invalidated = true;
}
In facts, it only set invalidate = true in adapter, but it is not invalidate session in Spring session registry. Real spring session continues be valid, and user can be used this session.
Could you have solution for this problem?
I found some solution but I don't think that it's good. We can override spring SessionEventHttpSessionListenerAdapter and ExpiringSessionHttpSession. And we can override method invalidate (adding call session registry). In this case, JavaMelody will invalidate session in registry.
Probably exists solution is better. I would be glad to get it.
Related
I want to perform a custom event when a user is logged out from a session timeout. The user is successfully logged out after exactly the length of time specified by my application.properties:
server.servlet.session.timeout=10
server.servlet.session.cookie.max-age=10
I have found a few similar solutions which involve a SessionDestroyedEvent, for example:
#Slf4j
#Component
public class SessionExpiredListener implements ApplicationListener<SessionDestroyedEvent> {
#Override
public void onApplicationEvent(SessionDestroyedEvent event) {
for (SecurityContext securityContext : event.getSecurityContexts()) {
Authentication authentication = securityContext.getAuthentication();
UserPrincipal user = (UserPrincipal) authentication.getPrincipal(); // UserPrincipal is my custom Principal class
log.debug("Session expired!" + user.getUsername());
// do custom event handling
}
}
}
The problem is the SessionDestroyedEvent is not triggered at the same time as the session timeout, in my tests it has triggered up to 5 minutes after the session has expired.
I have also tried using sessionDestroyed in HttpSessionListener but with similar results.
Is there an event that will trigger exactly when the session expires, or is there some way to achieve this?
The sessionDestroyed() method is called when the web container expires the session.
In Tomcat, session expirations happens every minute, and I think it is the case with other servlet containers.
So, even after the session times out there could be a delay until the next detection of expirations.
Session management is done by servlet container, and your application is getting notification from it.
And there is no way to be notified at the exact time of session expiration.
I also had handle the event when the user is logged out by session timeout. For me, this solution was helpfull: https://stackoverflow.com/a/18128496/4074871
Additionally I had to register the HttpSessionEventPublisher as mentioned in https://stackoverflow.com/a/24957247/4074871 because I had no web.xml for listener registration.
Can someone give me insight of how do I implement session management in Dropwizard 0.8.x or above. I was using Dropwizard 0.7.0 till now and working perfectly in it. But I really confused by change docs provided when I migrated to 0.8.x.
In Dropwizard 0.7.0 (which I was using previously) it was done like the following
/*MainApplication.class session handler */
environment.jersey().register(HttpSessionProvider.class);
environment.servlets().setSessionHandler(new SessionHandler());
/*Resource.class session check*/
HttpSession session = httpServletRequest.getSession(true);
But it does not seems working anymore, precisely saying HttpSessionProvider.class is not there and replaced by some other implementations.
It would be really helpful someone show to what this is changed to.
Thanks.
The reason this isn't working for you is because you need to set the cookie in the response. I noticed this while looking into enabling session state for a dropwizard application where the underlying cookie gets created on the Jetty Response object but it never makes it's way onto the Jersey Response object and therefor gets dropped.
What I've done to work around this issue is to implement a Filter that extracts the "Set-Cookie" information from Jetty and puts it onto the outbound response object.
String cookie = HttpConnection.
getCurrentConnection()
.getHttpChannel()
.getResponse()
.getHttpFields().get(HttpHeader.SET_COOKIE.asString());
if (LOG.isDebugEnabled()) {
LOG.debug("Adding session cookie to response for subsequent requests {}", cookie);
}
httpServletResponse.addHeader(HttpHeader.SET_COOKIE.asString(), cookie);
#Yashwanth Krishnan
I know this is old but I noticed that the session was not maintained from one URL to another, simply add this code when you init the application, session handling is mostly a container thing and not specific to DropWizard.
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.getSessionManager().setMaxInactiveInterval(SOME_NUMBER);
/**
* By default the session manager tracks sessions by URL and Cookies, we
* want to track by cookies only since
* we are doing a validation on all the app not URL by URL.
*/
sessionHandler.getSessionManager().setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));
environment.servlets().setSessionHandler(sessionHandler);
I'm trying to integrate Hazelcast (lasted version - 3.3) session replication.
Our infrastructure consists of :
Apache 2.0 server for the load balancing
Tomcat 7 servers serving our web application
Our main reasons are:
Duplicate user session for high availability
Atmosphere web-socket PubSub servlet need share the same data in order to make full
broadcasting
integrating Hazelcast to our Environment:
each of the tomcat servers will serve as Hazelcast member
basically Hazelcast WebFilter is the first one that executes and its
wrap with : WebFilter->HazelcastSession->setAttribute() implements
HttpSession interface
each time setAttribute is called Hazelcast sync the session attribute
with the rest of the cluster members.
now - its seems like every spring bean we injecting scoped as session bean don't get replicated .
as a workaround :
Save only basic session information via #Context annotation
Dont use Spring session scope , only Singletons and inject the HazelcastInstance
I can Wrap the relevant data as Hazelcast structures
Also, when i looked on other stackoverflow i saw the following : Spring "session" scope of a bean?
The Spring session does not exactly match the HttpSession, and even
the Spring documentation on the #SessionAttributes annotation says
that it might be stored in the session or "some conversational
storage". I got that from [The Spring docs for 2.5][1] I've basically
quit trying to make sense of it, and just got on with my life, if I
want something stored in the HttpSession, I just have Spring inject
the HttpSession to me, assuming you're using Spring MVC its pretty
easy, instructions on the same page.
[1]:
http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html
Its seems strange , Does Spring session beans not exactly match the HttpSession.setAttribute ?
How spring know how to #Inject the proper bean ?
Maybe Spring save the Beans in an internal data storage and only in
the Injection phase Spring getting the proper element using the same
session id attribute and bind the proper bean.
is there any way to control this behavior ?
Update :
debugging spring-web -> ServletRequestAttributes-> is using the
Server impl HTTPSession (For example - in Dev Jetty - org.eclipse.jetty.server.session.HashedSession)
this way the Bean is update in the HTTPSession but skipping the
HazelcastSession :-(
/**
* Update all accessed session attributes through {#code session.setAttribute}
* calls, explicitly indicating to the container that they might have been modified.
*/
#Override
protected void updateAccessedSessionAttributes() {
// Store session reference for access after request completion.
this.session = this.request.getSession(false);
// Update all affected session attributes.
if (this.session != null) {
try {
for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {
String name = entry.getKey();
Object newValue = entry.getValue();
Object oldValue = this.session.getAttribute(name);
if (oldValue == newValue) {
this.session.setAttribute(name, newValue);
}
}
} catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
this.sessionAttributesToUpdate.clear();
}
thanks in advance ,
elad.
We need a functionality of killing a specific session (by session ID) from some kind of an admin panel.
I attempted using the following approach:
public static void killSession(String sid) {
HttpSessionContext sc = FacesUtil.getSession().getSessionContext();
HttpSession session=sc.getSession(sid);
session.invalidate();
}
However
HttpSessionContext, and getSessionContext() and
getSession(sessionId) methods of a session are all deprecated (for seemingly paranoid security reasons)
The above code also gets a null session when invoked in an ApplicationScoped JSF managed bean
I'm seeking an alternative way of achieving the functionality.
Yes, you can't invalidate session from another session due to security reasons. What you can do is to manually store all sessions in some static attribute available to admin. So user logs in, you add him and his session to this attribute (usually a Map/HashMap with user as a key and session as value).
Look at my older answer here and you will get an idea.
I'm maintaining a Java web application.
Looking into the login code it gets an HttpSession out of HttpServletRequest via the getSession() method of HttpServletRequest. (It uses some values in the session for authentication purposes)
However I'm worried about session fixation attacks so after I have used the initial session I want to either start a new session or change the session id. Is this possible?
The Servlet 3.0 API doesn't allow you to change the session id on an existing session. Typically, to protect against session fixation, you'll want to just create a new one and invalidate the old one as well.
You can invalidate a session like this
request.getSession(false).invalidate();
and then create a new session with
getSession(true) (getSession() should work too)
Obviously, if you have an data in the session that you want to persist, you'll need to copy it from the first session to the second session.
Note, for session fixation protection, it's commonly considered okay to just do this on the authentication request. But a higher level of security involves a tossing the old session and making a new session for each and every request.
Since Java EE 7 and Servlet API 3.1 (Tomcat 8) you can use HttpServletRequest.changeSessionId() to achieve such behaviour. There is also a listener HttpSessionIdListener which will be invoked after each change.