SessionTimeout: web.xml vs session.maxInactiveInterval() - java

I'm trying to timeout an HttpSession in Java. My container is WebLogic.
Currently, we have our session timeout set in the web.xml file, like this
<session-config>
<session-timeout>15</session-timeout>
</session-config>
Now, I'm being told that this will terminate the session (or is it all sessions?) in the 15th minute of use, regardless their activity.
I'm wondering if this approach is the correct one, or should I programatically set the time limit of inactivity by
session.setMaxInactiveInterval(15 * 60); //15 minutes
I don't want to drop all sessions at 15 minutes, only those that have been inactive for 15 minutes.
Are these methods equivalent? Should I favour the web.xml config?

Now, i'm being told that this will terminate the session (or is it all sessions?) in the 15th minute of use, regardless their activity.
This is wrong. It will just kill the session when the associated client (webbrowser) has not accessed the website for more than 15 minutes. The activity certainly counts, exactly as you initially expected, seeing your attempt to solve this.
The HttpSession#setMaxInactiveInterval() doesn't change much here by the way. It does exactly the same as <session-timeout> in web.xml, with the only difference that you can change/set it programmatically during runtime. The change by the way only affects the current session instance, not globally (else it would have been a static method).
To play around and experience this yourself, try to set <session-timeout> to 1 minute and create a HttpSessionListener like follows:
#WebListener
public class HttpSessionChecker implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
System.out.printf("Session ID %s created at %s%n", event.getSession().getId(), new Date());
}
public void sessionDestroyed(HttpSessionEvent event) {
System.out.printf("Session ID %s destroyed at %s%n", event.getSession().getId(), new Date());
}
}
(if you're not on Servlet 3.0 yet and thus can't use #WebListener, then register in web.xml as follows):
<listener>
<listener-class>com.example.HttpSessionChecker</listener-class>
</listener>
Note that the servletcontainer won't immediately destroy sessions after exactly the timeout value. It's a background job which runs at certain intervals (e.g. 5~15 minutes depending on load and the servletcontainer make/type). So don't be surprised when you don't see destroyed line in the console immediately after exactly one minute of inactivity. However, when you fire a HTTP request on a timed-out-but-not-destroyed-yet session, it will be destroyed immediately.
See also:
How do servlets work? Instantiation, sessions, shared variables and multithreading

Now, i'm being told that this will terminate the session (or is it all sessions?) in the 15th minute of use, regardless their activity.
No, that's not true. The session-timeout configures a per session timeout in case of inactivity.
Are these methods equivalent? Should I favour the web.xml config?
The setting in the web.xml is global, it applies to all sessions of a given context. Programatically, you can change this for a particular session.

Related

Prevent session's last access time update in Jetty

Is it possible to instruct a Jetty server not to update the session's last access time when a particular servlet is accessed?
Our use case is an HTML page that sends asynchronous requests in the background every 5 miniutes to refresh its contents. The session's timeout is set to 30 minutes.
The unfortunate problem with this configuration is that when a user leaves that page open in a browser's tab, the session never expires because the access time of the session is updated by every asynchronous request.
For correctness' sake I have to admit that I didn't try anything yet because I wasn't able to find any help for my issue on the Internet. If what I'm asking for is not possible, I'm thinking of storing the access time in a session's variable that is controlled directly by the application. This value would have to be checked early before a request is processed (in the doGet and doPost methods of the servlets) and the session would need to be invalidated manually. Is there a better solution?
Servlet can't distinguish if the request is generated by some script or human, since both requests come from a same browser, consequently sending the same JSESSIONID. So you have to mark those requests in order to distinguish its source. You can mark them by some header or request parameter.
I like your idea of storing access time in session's variable (it will piggy back on servlet session expiry)
Your algorithm will be in this case:
if isUser(request){
session.lastRobotAccess == null
}else{
if (session.lastRobotAccess == null) {
session.lastRobotAccess = current_time
} else {
if(current_time - session.lastRobotAccess > session.timeout){
session.invalidate
}
}
}
When request arrives at servlet container it is first processed by the filters (if you have defined) and then by the servlet. Filters are useful for:
A common scenario for a filter is one in which you want to apply
preprocessing or postprocessing to requests or responses for a group
of servlets, not just a single servlet. If you need to modify the
request or response for just one servlet, there is no need to create a
filter—just do what is required directly in the servlet itself.
Since you can reach session from filter, they are more suitable place for your logic. You won't pollute servlet's logic with additional checking, and you can apply it to other servlets. Filters are also part of servlet specification so this will work in any container.
You already knew this things, but I've just put them on "paper" :-D

JSESSIONID not expired, SPRING_SECURITY_REMEMBER_ME expired

So, I have in my application spring security and have introduced remember me functionality when the checkbox is checked in.
I wanted to know what is the exact behavior:
if I set </remember-me> tag and specify for the rememberMeServices tokenValiditySeconds to 20 seconds, shouldn't the session expire and and ask me to log in again?
Do I have to set:
<session-config>
<session-timeout>XX</session-timeout>
</session-config>
So it matches the SPRING_SECURITY_REMEMBER_ME cookie tokenValiditySeconds ?
UPDATE
Does it matter if I've implemented my own PersistentTokenBasedRememberMeServices?
I had to override the default PersistentTokenBasedRememberMeServices coming from spring, because the PersistentRememberMeToken did not have any no-arg constructor, thus unable to use hibernate for that, so what I did I just wrote my own PersistentRememberMeToken, PersistentTokenBasedRememberMeServices (which, by the way, do no have anything special beside me introducing the no-arg constructor in PersistentRememberMeToken, beside that, it's copy paste from spring's source)
Having a remember-me token which is valid for less than the session-timeout will have no effect on your authentication during that session, if that's what you are asking.
Once you are authenticated during a session, your authentication is valid for the duration of that session, unless you log out or the session expires.
The remember-me token is only considered if you are unauthenticated, otherwise it will be ignored.

Can Servlets have multi-step interactions?

Is there any way to start executing java Servlet code (specifically, in Websphere Application Server) (one session, one thread on the Servlet) and then pause to get more information from the calling client at various points? I require that the current session, and ongoing Servlet thread, not die until specified, and instead keep waiting (open) for information from the client.
Is this kind of ongoing conversation possible? Or can the Servlet call to "doPost" only be started - and then the Servlet ignores the client until it finishes?
As suggested, I would use an object stored in session to maintain the state needed. You can also modify the session on a servlet by servlet basis if you need certain actions to extend the session timeout beyond the webapp defaults using the following method in the HttpSession API:
public void setMaxInactiveInterval(int interval) Specifies the time, in seconds, between client requests before the servlet container will invalidate this session. A negative time indicates the session should never timeout.
You just need to establish your logic for your object setting/retrieval from session. Typically something like this:
HttpSession session = req.getSession();
MyBeanClass bean;
Object temp = null;
temp = session.getAttribute("myBean");
if(temp !=null) {
bean = (MyBeanClass) temp;
} else {
bean = new MyBeanClass();
}
// Logic
session.setAttribute("myBean", bean);
You can save/update your session state between requests and when the next request comes, you can restore and continue whatever you were doing.
I have not done this with directly, but the underlying support is somewhat related to Jetty's continuation model and Servlet 3.0 Suspend/Resume support.
Web frameworks that work like the post description (actually, they are resumed across different connections) are sometimes called Continuation-Based frameworks. I am unsure of any such frameworks in Java (as the Java language is not conducive to such models) but there are two rather well known examples of the general principle:
Seaside (for Smalltalk) and;
Lift (for Scala).
Hope this was somewhat useful.

Session-timeout configuration doesn't work?

In web.xml I have this
<session-config>
<session-timeout>2</session-timeout>
</session-config>
<listener>
<listener-class>myapplication.SessionListener</listener-class>
</listener>
In the SessionListener.java I have
public void sessionDestroyed (HttpSessionEvent event){
System.out.println("Visitor Removed!!");
}
But it seems System.out.println("Visitor Removed!!") has never been executed. I am new to Tomcat 6 and JSP. Any suggestion please?
This can have at least 3 causes:
The session has never been created. Listen on sessionCreated() as well.
You are a bit impatient. Session destroy happens lazily and at intervals. It does not happen immediately. If you fire a new request in the same session while it has been expired, then sessionDestroyed() will be called. Or if you have a bit more patience, the server will run its low-prio timer job to reap all expired sessions.
You are not using the myapplication.SessionListener class in the classpath as you think you're using, maybe the one actually in the classpath doesn't have a sysout line.

Can I turn off the HttpSession in web.xml?

I would like to eliminate the HttpSession completely - can I do this in web.xml? I'm sure there are container specific ways to do it (which is what crowds the search results when I do a Google search).
P.S. Is this a bad idea? I prefer to completely disable things until I actually need them.
I would like to eliminate the HttpSession completely
You can't entirely disable it. All you need to do is to just not to get a handle of it by either request.getSession() or request.getSession(true) anywhere in your webapplication's code and making sure that your JSPs don't implicitly do that by setting <%#page session="false"%>.
If your main concern is actually disabling the cookie which is been used behind the scenes of HttpSession, then you can in Java EE 5 / Servlet 2.5 only do so in the server-specific webapp configuration. In for example Tomcat you can set the cookies attribute to false in <Context> element.
<Context cookies="false">
Also see this Tomcat specific documentation. This way the session won't be retained in the subsequent requests which aren't URL-rewritten --only whenever you grab it from the request for some reason. After all, if you don't need it, just don't grab it, then it won't be created/retained at all.
Or, if you're already on Java EE 6 / Servlet 3.0 or newer, and really want to do it via web.xml, then you can use the new <cookie-config> element in web.xml as follows to zero-out the max age:
<session-config>
<session-timeout>1</session-timeout>
<cookie-config>
<max-age>0</max-age>
</cookie-config>
</session-config>
If you want to hardcode in your webapplication so that getSession() never returns a HttpSession (or an "empty" HttpSession), then you'll need to create a filter listening on an url-pattern of /* which replaces the HttpServletRequest with a HttpServletRequestWrapper implementation which returns on all getSession() methods null, or a dummy custom HttpSession implementation which does nothing, or even throws UnsupportedOperationException.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
#Override
public HttpSession getSession() {
return null;
}
#Override
public HttpSession getSession(boolean create) {
return null;
}
}, response);
}
P.S. Is this a bad idea? I prefer to completely disable things until I actually need them.
If you don't need them, just don't use them. That's all. Really :)
If you are building a stateless high load application you can disable using cookies for session tracking like this (non-intrusive, probably container-agnostic):
<session-config>
<tracking-mode>URL</tracking-mode>
</session-config>
To enforce this architectural decision write something like this:
public class PreventSessionListener implements HttpSessionListener {
#Override
public void sessionCreated(HttpSessionEvent se) {
throw new IllegalStateException("Session use is forbidden");
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
throw new IllegalStateException("Session use is forbidden");
}
}
And add it to web.xml and fix places where it fails with that exception:
<listener>
<listener-class>com.ideas.bucketlist.web.PreventSessionListener</listener-class>
</listener>
In Spring Security 3 with Java Config, you can use HttpSecurity.sessionManagement():
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
Xml looks like this;
<http create-session="stateless">
<!-- config -->
</http>
By the way, the difference between NEVER and STATELESS
NEVER:Spring Security will never create an HttpSession, but will use
the HttpSession if it already exists
STATELESS:Spring Security will never create an HttpSession and it will
never use it to obtain the SecurityContext
I use the following method for my RESTful app to remove any inadvertent session cookies from being created and used.
<session-config>
<session-timeout>1</session-timeout>
<cookie-config>
<max-age>0</max-age>
</cookie-config>
</session-config>
However, this does not turn off HttpSessions altogether. A session may still be created by the application inadvertently, even if it disappears in a minute and a rogue client may ignore the max-age request for the cookie as well.
The advantage of this approach is you don't need to change your application, just web.xml. I would recommend you create an HttpSessionListener that will log when a session is created or destroyed so you can track when it occurs.
I would like to eliminate the HttpSession completely - can I do this in web.xml? I'm sure there are container specific ways to do it
I don't think so. Disabling the HttpSession would be a violation of the Servlet spec which states that HttpServletRequest#getSession should return a session or create one. So I wouldn't expect a Java EE container to provide such a configuration option (that would make it non compliant).
Is this a bad idea? I prefer to completely disable things until I actually need them.
Well, I don't really get the point, just don't put anything in the session if you don't want to use it. Now, if you really want to prevent the use of the session, you can use a Filter to replace the request with a implementation of HttpServletRequestWrapper overriding getSession(). But I wouldn't waste time implementing this :)
Update: My initial suggestion was not optimal, the "right" (cough) way would be to replace the request.
As of Servlet 3.0, you can make it so sessions are not tracked by the servlet container in any way, by adding code like this to the contextInitialized method of a ServletContextListener:
servletContext.setSessionTrackingModes(Collections.emptySet());
Javadoc.
Rather than disabling you can rewrite the URL using a URL rewrite filter eg tuckey rewrite filter. This will give Google friendly results but still allow cookie based session handling.
However, you should probably disable it for all responses as it's worse than just search engine unfriendly. It exposes the session ID which can be used for certain security exploits.
Example config for Tuckey filter:
<outbound-rule encodefirst="true">
<name>Strip URL Session ID's</name>
<from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
<to>$1$2$3</to>
</outbound-rule>
One cannot avoid the session creation. But you can check if you violate your own requirement at the end of a request cycle. So, create a simple servlet filter, which you place as first and after chain.doFilter throw an exception if a session was created:
chain.doFilter(request, response);
if(request.getSession(false) != null)
throw new RuntimeException("Somewhere request.getSession() was called");
For RESTful application, I simply invalidate it every time the request's lifecycle ends. There may be some web server that always creates new session when new client access whether you call request.getSession() or not.

Categories

Resources