Bug 60824 - Subject incorrectly removed from user session
Summary: Subject incorrectly removed from user session
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 7
Classification: Unclassified
Component: Catalina (show other bugs)
Version: trunk
Hardware: All All
: P2 normal with 1 vote (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-03-06 16:53 UTC by Jan Engehausen
Modified: 2017-03-06 20:54 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Engehausen 2017-03-06 16:53:49 UTC
In our setup we have global security enabled, and we're using Spring Security with a pre-authenticated scenario in the web application.
We're seeing a (very likely platform-indepedent) issue with unexpected javax.security.auth.Subject instances and unexpected java.security.Principal instances contained in those Subject instances. We see each request exposes a new Subject instance, and under load (same user session, concurrent requests) a Principal created by Spring is present in the set of principals of the Subject instance, whilst the Tomcat-managed one is not present.

The problem has been observed on Linux and Windows. We're using the following Java versions:
- Linux: Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
- Windows: Java(TM) SE Runtime Environment (build 1.8.0_31-b13)

Tomcat Connector
Linux:  <Connector URIEncoding="UTF-8" scheme="http" protocol="HTTP/1.1" connectionTimeout="20000" port="..."/>
Windows: Embedded Tomcat 7.0.47 via Maven Tomcat plugin

Tomcat is not used behind Apache HTTPD or any other web server.

We have debugged the issue and believe the cause lies in org.apache.catalina.connector.Request.setUserPrincipal(Principal)
The code in this method tries to cache the Subject in the user session, but (accidentally?) removes it from the session at the beginning of every request.
This is because the variable "subject" is always "null" when "session.setAttribute(Globals.SUBJECT_ATTR, subject);" is called, unless the session did not carry a subject yet.

Further code in Tomcat uses the session to obtain and cache the Subject in the session, e.g. org.apache.catalina.security.SecurityUtil.execute(Method, Object, Object[], Principal). In there, if no Subject is found in the session, a new instance is created with the Principal of the current request, stored in the session and used as the current JAAS subject.
Concurrent requests from the same user session may cause race conditions, as the Subject is removed from the session but also cached by these parts of the code.

We have created a simple reproduceable test, see below, which verifies that the Tomcat-managed principal is found in the Principal set of the current Subject. In error cases, only a Spring-managed Principal is found.
In our actual real-life case, our code relies on Principal objects created by a custom login module, which are sometimes not found, thus causing the real application to fail.

Overview
If global security is enabled and a session exists, the Subject is removed from the session at the beginning of each request.

Reproducer
Find details and how to run at https://github.com/smurf667/test-tomcat-broken-subject
The test setup uses an integration test with an embedded Tomcat to send a number of concurrent requests for a single user session.
A Spring filter in the application makes sure that a Tomcat-managed Principal created is present in the subject. If not, the application fails.

Expected: The Subject present for each request of the same user session contains a Tomcat-managed Principal.
Actual: Sometimes the Subject only contains a Spring-managed Principal.

We're suggesting a potential fix for the issue in the README.md of the repository.
As we're no experts, we leave it to the person handling our bug report to judge if the fix is appropriate or not (we believe so). Please ask if you have any further questions, thanks!

Kind regards,
Sebastian Hähnel (sebastian.haehnel@gmail.com) and Jan Engehausen (smurf667@gmail.com)
Comment 1 Chuck Caldarale 2017-03-06 17:15:26 UTC
Tomcat 7.0.47 is over three years old, and many, many changes have gone in since then.

Please update to a current version of Tomcat and see if the problem persists.
Comment 2 Jan Engehausen 2017-03-06 17:25:53 UTC
Hi Chuck,

I understand. We're seeing this in production with 7.0.54, and have a standalone reproduceable scenario with 7.0.47 (embedded). We believe the issue to be in org.apache.catalina.connector.Request.setUserPrincipal(java.security.Principal) and looking at the code of 7.0.63 or 8.0.24 it seems to be still in there as well.

http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/7.0.63/org/apache/catalina/connector/Request.java#Request.setUserPrincipal%28java.security.Principal%29

http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/8.0.24/org/apache/catalina/connector/Request.java#Request.setUserPrincipal%28java.security.Principal%29

Kind regards,
Jan
Comment 3 Jan Engehausen 2017-03-06 17:51:30 UTC
I've now upgrade the reproduceable scenario to use Tomcat 7.0.63. The problem also manifests in this version.

Kind regards,
Jan
Comment 4 Chuck Caldarale 2017-03-06 19:11:11 UTC
(In reply to Jan Engehausen from comment #3)
> I've now upgrade the reproduceable scenario to use Tomcat 7.0.63. The
> problem also manifests in this version.

7.0.63 is still over 1.5 years old.  Please try with the _current_ release (7.0.75).
Comment 5 Jan Engehausen 2017-03-06 19:20:34 UTC
I've update the demonstration to use 7.0.75. The problem is showing.
Comment 6 Mark Thomas 2017-03-06 20:50:49 UTC
Confirmed. The current code is affected.

I do wonder if Request.subject is required although I can think of some (slightly odd) use cases where it might be.

Fixed in:
- trunk for 9.0.0.M18 onwards
- 8.5.x for 8.5.12 onwards
- 8.0.x for 8.0.42 onwards
- 7.0.x for 7.0.76 onwards
Comment 7 Jan Engehausen 2017-03-06 20:54:20 UTC
Hey guys, most impressive! THANK YOU!

Regards,
Jan