This issue is driving me insane, so maybe someone could help me understand what the issue is. I have a tomcat web application being fronted by HAProxy. HAProxy is also doing SSL offloading, and is configured to use sticky sessions. I am using Tomcat's session replication feature which seems to be working just fine. The sessions appear on both appservers.
For some reason, Tomcat is generating a new JSESSIONID for every single web request, and then copying the contents of the old session into the new session. That is to say, my session contents are still there within the new session, but a new ID is generated and sent back to the client. But it only does this for my web application. It does not do this for the /manager application.
I have tried every trick in the book, such as setting this in my context.xml:
<Valve className="org.apache.catalina.authenticator.BasicAuthenticator" changeSessionIdOnAuthentication="false" />
And setting these attributes on my Context element:
<Context path="/myapp" reloadable="false" override="true" useNaming="false" allowLinking="true" useHttpOnly="false" sessionCookiePath="/" sessionCookiePathUsesTrailingSlash="false">
And still, the result is the same. Tomcat generates a new session id with every request and copies the contents of the old session into the new id.
I would suspect it had something to do with HAProxy, except that the /manager application is also behind HAProxy and it does not exhibit this behavior.
Why is Tomcat doing this, and what can I do to prevent it?
Turns out that it was cause by Spring Security. We are using Spring Security 3.1x, and by default it stores the authenticated credentials in the user's session. And to counter session fixation attacks, it automatically copies the contents of the user's session to a new session id and invalidates the old session.
The fix was to add the following to the http element in the security configuration, since we don't need to use the session in our application:
create-session="stateless"
Hopefully this helps someone else down the line.
I got the same problem with new id session when I refresh page
On tomcat7 server, I only add into the context.xml this code :
<Valve className="org.apache.catalina.authenticator.BasicAuthenticator" changeSessionIdOnAuthentication="false" />
<Context path="/myapp" reloadable="false" override="true" useNaming="false" allowLinking="true" useHttpOnly="false" sessionCookiePath="/" sessionCookiePathUsesTrailingSlash="false">
This work fine for me.
Not sure exactly what your problem is, but there are two things I would check. First, did you specify the jvmRoute in tomcat?
Tomcat server.xml
<Engine name="Catalina" defaultHost="localhost" jvmRoute="machine1">
Haproxy.cfg (references jvmRoute)
server machine1 SERVER_IP cookie machine1 check
Tomcat appends the name of the server to the cookie, so not setting that can cause issues.
The other thing to check is to make sure that you added this line to your web.xml in the web-app section
<distributable />
Related
The session is not working with mod_jk load balancer (from httpd web server). However, the same code is working fine in the application server.
Following is worker.properties:
worker.list=loadbalancer,status,web
worker.node0.port=8009
worker.node0.host=10.50.26.19
worker.node0.type=ajp13
worker.node0.lbfactor=1
worker.node0.socket_keepalive=false
worker.node0.connect_timeout=10000
worker.node0.prepost_timeout=10000
worker.node0.socket_timeout=60
worker.node0.connection_pool_timeout=600
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=node0
worker.loadbalancer.sticky_session=1
Java Code in Portlet 1:
PortletSession portletSession = actionRequest.getPortletSession();
portletSession.setAttribute("username",reg.getFname(), PortletSession.APPLICATION_SCOPE);
JSP Code in Portlet 2:
PortletSession portletSessionobject = renderRequest.getPortletSession();
userName=(String)portletSessionobject.getAttribute("username",PortletSession.APPLICATION_SCOPE);
In both the portlet the following property have been applied in the liferay-portlet.xml
<private-session-attributes>false</private-session-attributes>
But unable to get username in the Portlet 2 JSP page in web server it is returning null. But in the application server the value is coming as expected. Please suggest.
After doing much research found the solution. Hence posting it to help others. There are two things that cause the issue.
i) The sessions were overwritten by the httpd server. Following header tag was added in the httpd.conf which actually caused the issue. Removed it and JSESSION started to appear.
Header set Set-Cookie HttpOnly;Secure
ii) Session Affinity was not working properly due to jvmRoute was not defined. As a result, the session gets terminated intermittently. So added the instance-id for subsystem web in the standalone.xml of each instance,
For node0,
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" instance-id="node0" native="false">
For node1,
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" instance-id="node1" native="false">
I have been looking at solutions for sharing session data between mutliple war files. I came across the following solution http://www.fwd.at/tomcat/sharing-session-data-howto.html
The basic idea of it is that if you have more than one war file, you can set a cookie using the sessionid of the first context that is used.
The cookie can be set using a path that will apply to all contexts/applications.
For example, if I have the following configuration for 3 applications
/myapp/app1
/myapp/app2
/myapp/app3
I can set a cookie as follows
/myapp sessionid.
The sessionid cookie will then be sent to any request with /myapp in the address. This allows the session id to then be used by any of the contexts.
The only problem with this approach is that it was written in 2003 and tested on Tomcat 4.
What are your opinions of this approach? Is there a better way of doing it?
Thanks
That article is indeed heavily outdated.
On Tomcat 5.5 and 6.0 you can just set emptySessionPath attribute to true in the <Connector> element in /conf/server.xml.
<Connector ... emptySessionPath="true">
On Tomcat 7.0 this has changed because this is now configureable from the Servlet 3.0 API on. It's then on Tomcat's side configureable by setting sessionCookiePath to / in <Context> element in any responsible context.xml file.
<Context ... sessionCookiePath="/">
As said, there's a new Servlet 3.0 API which allows you to configure the session cookie through the standard API. You can do it either declaratively by adding the following to the web.xml:
<session-config>
<cookie-config>
<path>/</path>
</cookie-config>
</session-config>
or programmatically by SessionCookieConfig which is available by ServletContext#getSessionCookieConfig().
getServletContext().getSessionCookieConfig().setPath("/");
You could do this in ServletContextListener#contextInitialized() or HttpServlet#init().
See also:
Tomcat 5.5 HTTP connector documentation
Tomcat 6.0 HTTP connector documentation - mentions potential security hole
Tomcat 7.0 context documentation
To my knowledge there is no direct way to do this, you can however use a domain level cookie if these contexts share the same domain.
You can either put the data in the cookie (I don't recommend that).
Or put a secured session Id that you can use to access some form of storage (DB or distributed cache etc) to retrieve the data you need.
If the amount of data is not astronomical and the data itself isn't changing too rapidly, you might want to consider using JNDI. This solution was designed exactly for what you are looking for.
You can have a look at official documentation or this post to tomcat-user mailing list for references & examples.
For Tomcat 8 I use the following configuration to share a session across 2 webapps:
conf/context.xml
<Context sessionCookiePath="/">
<Valve className="org.apache.catalina.valves.PersistentValve"/>
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore" directory="${catalina.base}/temp/sessions"/>
</Manager>
...
</Context>
I deploy the same simple webapp twice log.war and log2.war:
/log
/log2
I can now log-in to /log and have the user displayed in /log2, this does not work with the tomcat default configuration.
The session value is set and read:
HttpSession session=request.getSession();
session.setAttribute("name",name);
HttpSession session=request.getSession(false);
String name=(String)session.getAttribute("name");
I used this project as example: https://www.javatpoint.com/servlet-http-session-login-and-logout-example
Most examples/solutions use a in-memory database which requires more setup work:
redis
hazelcast
i have my (spring) web application 'mywebapp' configured in tomcat as follows:
$CATALINA_HOME/conf/Catalina/localhost/mywebapp.xml
<Context path="/mywebapp" docBase="<absolute path to my web application>"
debug="0" privileged="true" reloadable="true">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Context>
on my local machine, i can access my application from browser at the following url:
http://localhost:8080/mywebapp/
no issues whatsoever up to this point
to support mobile devices we have recently implemented a separate set of views which are organised under path m/. this mapping is done via spring's #RequestMapping annotation. basically, now there are two sets of resources that are served via the following urls:
http://localhost:8080/mywebapp/
and
http://localhost:8080/mywebapp/m/
where the former is for desktop / laptop users and the latter is for mobile users
now, is there a way that i can configure a subdomain to make this work? in other words, how can i configure tomcat so that requests to
http://m.localhost:8080/mywebapp/
are forwarded to
http://localhost:8080/mywebapp/m/
please keep in mind that there is only a single web application. so both the urls should actually reach the same application 'mywebapp'
i thought configuring an additional Host element in tomcat's server.xml would be the way to go. but i still couldn't figure out how it can be done
i am on a windows machine and have already added the following entry in C:\Windows\System32\drivers\etc\hosts file
127.0.0.1 m.localhost
I have been looking at solutions for sharing session data between mutliple war files. I came across the following solution http://www.fwd.at/tomcat/sharing-session-data-howto.html
The basic idea of it is that if you have more than one war file, you can set a cookie using the sessionid of the first context that is used.
The cookie can be set using a path that will apply to all contexts/applications.
For example, if I have the following configuration for 3 applications
/myapp/app1
/myapp/app2
/myapp/app3
I can set a cookie as follows
/myapp sessionid.
The sessionid cookie will then be sent to any request with /myapp in the address. This allows the session id to then be used by any of the contexts.
The only problem with this approach is that it was written in 2003 and tested on Tomcat 4.
What are your opinions of this approach? Is there a better way of doing it?
Thanks
That article is indeed heavily outdated.
On Tomcat 5.5 and 6.0 you can just set emptySessionPath attribute to true in the <Connector> element in /conf/server.xml.
<Connector ... emptySessionPath="true">
On Tomcat 7.0 this has changed because this is now configureable from the Servlet 3.0 API on. It's then on Tomcat's side configureable by setting sessionCookiePath to / in <Context> element in any responsible context.xml file.
<Context ... sessionCookiePath="/">
As said, there's a new Servlet 3.0 API which allows you to configure the session cookie through the standard API. You can do it either declaratively by adding the following to the web.xml:
<session-config>
<cookie-config>
<path>/</path>
</cookie-config>
</session-config>
or programmatically by SessionCookieConfig which is available by ServletContext#getSessionCookieConfig().
getServletContext().getSessionCookieConfig().setPath("/");
You could do this in ServletContextListener#contextInitialized() or HttpServlet#init().
See also:
Tomcat 5.5 HTTP connector documentation
Tomcat 6.0 HTTP connector documentation - mentions potential security hole
Tomcat 7.0 context documentation
To my knowledge there is no direct way to do this, you can however use a domain level cookie if these contexts share the same domain.
You can either put the data in the cookie (I don't recommend that).
Or put a secured session Id that you can use to access some form of storage (DB or distributed cache etc) to retrieve the data you need.
If the amount of data is not astronomical and the data itself isn't changing too rapidly, you might want to consider using JNDI. This solution was designed exactly for what you are looking for.
You can have a look at official documentation or this post to tomcat-user mailing list for references & examples.
For Tomcat 8 I use the following configuration to share a session across 2 webapps:
conf/context.xml
<Context sessionCookiePath="/">
<Valve className="org.apache.catalina.valves.PersistentValve"/>
<Manager className="org.apache.catalina.session.PersistentManager">
<Store className="org.apache.catalina.session.FileStore" directory="${catalina.base}/temp/sessions"/>
</Manager>
...
</Context>
I deploy the same simple webapp twice log.war and log2.war:
/log
/log2
I can now log-in to /log and have the user displayed in /log2, this does not work with the tomcat default configuration.
The session value is set and read:
HttpSession session=request.getSession();
session.setAttribute("name",name);
HttpSession session=request.getSession(false);
String name=(String)session.getAttribute("name");
I used this project as example: https://www.javatpoint.com/servlet-http-session-login-and-logout-example
Most examples/solutions use a in-memory database which requires more setup work:
redis
hazelcast
I would like to disable page "People" in Hudson. I don't want users to see other users. Is it possible to do?
I don't know if you can do it directly with Hudson, but you certainly be able to do it if you run Hudson within a Tomcat instance (I run mine in a Tomcat 7 without any problem).
You would define a JSP security-constraint, a bit like those ones (note: adapted for LDAP because I defer all user authentication to the webapp container of Hudson: in my case, Tomcat)
The OP asks:
You're suggesting to make changes to hudson/WEB-INF/web.xml? Could you please explicitly mention the file I have to change?
#Vincenzo: I don't! I never touch one bit of the hudson.jar. I only use it within a Tomcat instance, meaning:
I declare in <tomcat>/conf/Catalina/localhost a context for each Hudson I want to manage:
hudson-xxx -> /home/me/context/hudson-xxx.xml
(it is a link because I want to upgrade Tomcat easily, so I externalize the context definition outside of Tomcat). I define my Realm for ACL purposes:
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="/home/me/hudson/hudson.war" path="/hudson-xxx">
<Realm className="org.apache.catalina.real.CombinedRealm" >
<Realm className="org.apache.catalina.real.JNDIRealm" debug="99"
connectionURL="ldap://xxxxx:389"
alternateURL="ldap://xxxxx:389"
connexionName="yyyy"
connectionPassword="zzzz"
userPattern="CN={0},OU=...,DC=..."
userRoleName="memberOf"
useSubtree="false"
roleBase="OU=...,DC=..."
roleName="cn"
roleSearch="(member={0})"
roleSubtree="false"
/>
</Realm>
<Environment name="HUDSON_XXX" value="/home/me/hudson/hudson-xxx-home" type="java.lang.String" override="false" />
</Context>
(With that context, a hudson.war stored outside of Tomcat is automatically deployed with the </tomcat>/webapps directory, and access from http://tomcat-server/hudson-xxx, with an LDAP-based authentication)
I suggests modifying the </tomcat>/conf/web.xml to add security-constraint which would prevent anybody to access the user page while letting only certain tomcat users (as defined in /conf/tomcat-users.xml.
(I haven't tested it yet)