Can I turn off the HttpSession in web.xml? - java

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.

Related

How does Spring Security handle JSESSIONID with various Session Creation and Session Fixation combinations?

I have a J2EE REST-based app using Spring Security 4.0.1.RELEASE. Needless to say, Spring documentation on sessionCreationPolicy and sessionFixation is sparse, aside from targeted questions here on StackOverflow.
I'm using a Java-based config for Spring Security like this:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(secureEnabled=true, prePostEnabled=true, jsr250Enabled=true, order=1)
public class DefaultSecurityBeansConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.sessionFixation().migrateSession()
.and()...; // additional config omitted for brevity
}
}
I'd really just like to know what behavior to expect from Spring, as it relates to JSESSIONID, given all possible combinations of sessionCreationPolicy and sessionFixation.
Possible values in the SessionCreationPolicy enum are ALWAYS, NEVER, IF_REQUIRED, and STATELESS.
Possible values for session fixation are newSession, migrateSession, changeSessionId, and none.
Thank you.
NOTE: What prompted this question is that I am not seeing a new JSESSIONID on every request when I have sessionCreationPolicy set to IF_REQUIRED and sessionFixation set to changeSessionId. A JSESSIONID is correctly created, but is maintained across requests thereafter. I generalized my question about all combinations to hopefully help others in a similar situation with slightly different settings.
It's important to keep in mind that Spring Security doesn't always have full control of the HttpSession. It can create one itself, but it can also be provided a Session object by the container.
For SessionCreationPolicy.IF_REQUIRED, the docs state:
Spring Security will only create an HttpSession if required
In your particular case, you're not seeing a new JSESSIONID for every request for at least 2 possible reasons:
With your current configuration, Spring has the option of creating a Session if it needs one.
SessionCreationPolicy.IF_REQUIRED also appears to allow Spring Security to use the Session it is provided with. Your container might be providing this object if this is the case, and so the session is maintained across multiple requests (as is expected if you're in a session).
If you wanto to disable #1, use SessionCreationPolicy.NEVER:
Spring Security will never create an HttpSession, but will use the HttpSession if it already exists
The only SessionCreationPolicy that will ensure that Spring Security uses NO SESSIONS is SessionCreationPolicy.STATELESS.
As regards SessionFixation, it only comes into play when you have multiple sessions for one user, after authentication. At this point, the SessionCreationPolicy is somewhat irrelevant.
SessionCreationPolicy: used to decide when (if ever) to create a new session
SessionFixation: once you have a session for a user, what to do with the session if the user logs in again
Hope this helps!

Sending information from a servlet back to a Filter

I have an old web application, running on Tomcat 7, that uses a very rudimentary open-session-in-view mechanism provided by a filter:
#Override public void doFilter (ServletRequest req, ServletResponse resp, FilterChain fc)
throws IOException, ServletException
{
try {
HibernateUtil.beginTransaction();
fc.doFilter(req, resp);
HibernateUtil.commitTransaction();
} catch (Throwable t) {
Logger.exception(t, "processing servlet request");
HibernateUtil.rollbackTransaction();
throw new ServletException(t);
}
}
I'm stuck with this now, and I think I'm running into one of the many flaws with OSIV (or at least this implementation of it) which is that I now want to be able to rollback transactions even without an exception being thrown. I want servlets to be able to control that, and I don't think I have much choice except to hack this functionality on somehow.
My question is: How can I communicate some sort of "rollback" flag from an arbitrary servlet back up to this filter? I want to be able to do something like this in the filter:
HibernateUtil.beginTransaction();
fc.doFilter(req, resp);
if (/* something that was set by a servlet/jsp */)
HibernateUtil.rollbackTransaction();
else
HibernateUtil.commitTransaction();
I'm not really sure what a reliable way to propagate information like that from a servlet back out to this filter is.
I don't advise using request attributes or thread-local variables, which has the following issues:
Your transaction is dependent on someone else having set a flag. If you work for a bank, I really don't wanna be a customer there.
Resource leaking if you don't clean up thread-local storage.
You can't write multithreaded code without manually copying stuff between thread-local storage.
If using request attribute, you'll have to extract the value in a Servlet and pass all the way to your DAO, assuming you're using a common multi layered architecture.
Instead, you can simply get the current transaction from the Hibernate session object and ask it to rollback. Session.getTransaction().rollback(). Best, scrap that code or find the person who wrote it and ask for a refund.

cookies with <path>/</path> and JSESSIONID

I am experimenting with setting the cookie path in my application's web.xml (as suggested here) to:
<session-config>
<cookie-config>
<path>/</path>
</cookie-config>
</session-config>
So I deploy two identical web applications to localhost:8080/application-a and localhost:8080/application-b respectively.
Each application is a single servlet:
public class ControllerServlet extends HttpServlet{
#Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
HttpSession session = req.getSession(false);
if (session == null) {
session = req.getSession(true);
System.out.printf("No session was present - new one created with JSESSIONID=[%s]\n", session.getId());
} else {
System.out.printf("JSESSIONID cookie was present and HttpSession objects exists with JSESSIONID=[%s]\n", session.getId());
}
}
}
I deploy the apps to a Tomcat 8.5 container (tried with Tomcat 9 as well the behavior is the same). When I visit with my browser the application-a, here's what I see:
… and on the Tomcat logs I read:
No session was present - new one created with JSESSIONID=[A227B147A4027B7C37D31A4A62104DA9]
So far so good. When I then visit application-b here's what I see:
… and the Tomcat logs show:
No session was present - new one created with JSESSIONID=[5DC8554459233F726628875E22D57AD5]
This is also very well as explained here and also in this answer and I quote:
SRV.7.3 Session Scope
HttpSession objects must be scoped at the application (or servlet
context) level. The underlying mechanism, such as the cookie used to
establish the session, can be the same for different contexts, but the
object referenced, including the attributes in that object, must never
be shared between contexts by the container.
So even though on the request the JSESSIONID cookie was present, my application (the one deployed in application-b) was unable to find an HttpSession object in its own servlet context scope and so a new session object was created and a new value was assigned to the JSESSIONID cookie.
However, when I now go back to my application-a I find out that because of the / value configured for the cookie path, it is now trying to use the JSESSIONID value set by application-b and of course its servlet doesn't find such a session object in its own context (application-a) and so a new value for the JSESSIONID cookie is created which will in turn invalidate the session of the application-b application and so on and so forth ad infinitum as I switch back and forth between the two applications.
So my questions are:
1 given the above behavior it would seem impossible for two applications to use the same JSESSIONID cookie value as the key to their respective HttpSession objects. So in fact not only are the HttpSession objects always different and scoped at the application (servlet context) level but also, in practice, the JSESSIONID values have to be different. Is that correct?
2 If so, then why does the servlet specification use the wording:
The underlying mechanism, such as the cookie used to establish the
session, can be the same for different contexts [...]
The only way I can imagine the above could be accomplished would be to have a way to hardcodedly provide the JSESSIONID value to use when a new session object is created? But I don't see an API for that.
3 Is there a way I can have some other cookies be shared among applications using the / path in the <session-config> XML element but not have the / path apply to the JSESSIONID cookie? In other words does the <session-config> apply to all cookies of an application or only the cookie used for session tracking? (JSESSIONID) ?
Upon further experimentation and taking a cue from this answer it would appear that for the same JSESSIONID to be used for all web applications it is necessary to set the following attribute in context.xml:
<Context ... sessionCookiePath="/">
Either the Tomcat-wide context.xml or the WAR-specific context.xml will do. The <cookie-config><path> value configured in the WAR's web.xml is apparently ignored.
Regarding point 3 of my question I 've found that the way to set paths for other cookies is to programmatically create many of them, one for each path, and add them in the response object with the addCookie method. The configurations in web.xml or context.xml are appicable to other cookies beyond the session cookie.

Access GWT POST parameters via servlet?

I'm creating a GWT application that will be accessed by a POST request, which contains parameters I care about (user id, etc.).
All the reading I've done so far has led me to believe that I should create a servlet (I'm using tomcat) that will handle the POST parameters and then forward to my GWT application. I've gotten this working, but I'm still having trouble passing this data to my application. I've seen 3 suggested approaches:
Save data to context: I have this working right now, but I'm not happy with it. When the servlet is accessed, I parse the parameters and update the context of my GWT web application and then forward to the application where I make an RPC call to read the context. This does what I want it to, but this creates a race condition when multiple users try to access the application at the same and the context is rapidly changing.
Store data in session: I've tried saving the data to the request session in my servlet, and then accessing the session in my RPC, but I always get a new/different session, so I assume I'm mucking this up somewhere.
Save session on servlet
HttpSession session = request.getSession();
session.setAttribute("test", "testValue");
response.sendRedirect(response.encodeRedirectURL("/GWT_Application"));
Access session in RPC
HttpSession session = this.getThreadLocalRequest().getSession();
session.getAttribute("test");
This returns a different session, which results in the "test" attribute being null.
Pass data in URL: My application will be opened in an iframe, meaning Window.location.getParameter() will not be usable.
Any help would be greatly appreciated! I'm still learning GWT and web development in general so don't be afraid to call me out on any obvious or silly mistakes.
Thanks!
SOLUTION
I figured out what the issue was with my session approach: the servlet in which I was previously trying to save the session data was in a separate tomcat web app from my GWT application. Moving them to the same web app solved my problems and it now works. I'm not sure, but I'm guessing that this was a problem because redirecting to another web app switches the context. I'll outline my whole approach in the hopes this saves someone else some time later:
Put your servlet code in the server folder of your GWT project:
package GWTApplication.server;
public class myServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
session.setAttribute("myAttribute", request.getParameter("myParam");
// handle rest of POST parameters
response.sendRedirect(response.encodeRedirectURL("/GWTApplication");
}
}
Map servlet in your GWT application's web.xml:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>GWTApplication.myServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
This servlet should now be accessible at .../GWTApplication/myServlet
Next make a standar RPC. Within whatever method you will be calling in the ServiceImpl class on the server:
HttpSession session = this.getThreadLocalRequest().getSession();
return session.getAttribute("myAttribute");
Finally, make your RPC call in the onModuleLoad() method of you GWT application. As a recap:
Send the original POST request to the servlet
Save POST parameters to session variables
Redirect to GWT application
Make RPC call in onModuleLoad()
Read session variables in ServiceImpl class
You can talk with servlets through RPC call in GWT
You need to make a RPC call in the starting point of GWT application.
Set that data to serverside session and get the session data in servceImpl call of GWT which extends to RemoteServiceServlet.
Example :
YourServiceImpl extends RemoteServiceServlet {
#ovveride
doGet(){
//you can access session here
}
#ovveride
doPost(){
//you can access session here
}
#ovveride
doPut(){
//you can access session here
}
----your other methods
}
A brief Example I wrote here:How to make an GWT server call(GWT RPC?)
Since RemoteServiceServlet extends HttpServlet, you can just override doPost() method to access your POST requests. Don't forget to call super.doPost() EDIT: This doesn't work because the method is finalized in AbstractRemoteServiceServlet so it cannot be overridden.
Also, GWT Servlets POST data using the proprietary GWT RPC format. Read more about that format and how to interpret it here: GWT RPC data format
EDIT
There are several methods you can override in your ServiceImpl class that extends RemoteServiceServlet:
public String processCall(String payload) will give you a String representation of the incoming request.
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) will give you a RPCRequest object that has an array of parameters, along with the method that was called.
public void service(ServletRequest request, ServletResponse response) will give you all the Attributes of the HTTP request.

How can I get HttpServletRequest when in an HttpSessionListener?

How can I access request headers from a SessionListener?
I need to set a timeout on the current session when it is created. The timeout needs to vary based on a header in the HttpServletRequest. I already have a SessionListener (implements HttpSessionListener) that logs the creation and destruction of new sessions, and it seems to be the most logical place to set the timeout.
I've tried the following, but it always sets ctx to null.
FacesContext ctx = FacesContext.getCurrentInstance();
The HttpSessionListener does not have access to the request because it is invoked when no request has been made—to notify of session destruction.
So, a Filter or Servlet would be better places to examine the request and specify the session timeout.
FacesContext ctx = FacesContext.getCurrentInstance();
JSF contexts are per-request and thread-local. So, this method call will probably return null outside the JSF controller invocations (e.g. FacesServlet.service) - so, other threads and any requests that don't pass through the Faces servlet mapping.
It is technically possible to set this time-out using a JSF mechanism - you could use a phase listener to check for a session after RENDER RESPONSE, though you would still have to cast to the servlet API to set the time-out. The advantage of phase listeners is that they can be registered either globally in faces-config (see spec) or for specific views. A global phase listener defined in a JAR with a META-INF/faces-config.xml can be dropped into multiple WARs, allowing you to easily reuse the functionality.
(You could also override how the session is provisioned to JSF, but the amount of work is excessive.)
For a one-off, erickson's suggestion of a Filter is really straightforward.
You can't ( see the API ). The request allows you to access the session, but not the other way around.
You might even have concurrent requests for the same session, so this is not feasible.

Categories

Resources