Servlet 3.0 logout doesn't work - java

I've got a problem with the authentication features of Servlet 3.0:
With this code in a Servlet v3:
log.info(""+request.getUserPrincipal());
log.info(""+request.getAuthType());
log.info("===^===");
request.logout() ;
log.info(""+request.getUserPrincipal());
log.info(""+request.getAuthType());
request.authenticate(response) ;
log.info("===v===");
log.info(""+request.getUserPrincipal());
log.info(""+request.getAuthType());
I would always expect to see the Username/login windows, because of the logout() function. Instead, it seems to be a 'cache' mechanism which repopulate the credential and cancel my logout ...
Admin
BASIC
===^===
null
null
===v===
Admin
BASIC
Is it a problem with my firefox, or something I'm missing in the Servlet code?

I would always expect to see the Username/login windows, because of the logout() function. Instead, it seems to be a 'cache' mechanism which repopulate the credential and cancel my logout ...
That's the way HTTP BASIC AUTH was designed, it allows all authenticate state to be kept in the client. In other words, its impossible to logout with basic/digest authentication, the server cannot stop a client from caching and resending a BASIC auth authenticator on subsequent requests to the server.
My suggestion is to use form based authentication and the login method of HTTPServletRequest.
References
New Security Features in Glassfish v3 (Java EE 6) - Part II
New Security Features in Glassfish v3 (Java EE 6) - Part III
Easiest and most portable way to authenticate programatically
How to log users out from Glassfish server - need help from SUN

It's neither. Once logged in, the browser will always pass your user id and password to the url. Until you restart your browser. As far as I know each browser does that. And as far as I know there's currently no way to tell the browser to forget about the credentials.
However, you'll see your session will be different once you logged out. The usual solution is to add a variable of some kind to the session. Say "loggedin". If this variable is missing you know the user has to log in first and you'll redirect to say login.jsp. And once the user passed this jsp you set this variable again.
Using filters you can enforce this system-wide.

Related

What is the best solution for lost JSESSIONID cookie on Java Web App Redirect?

The Problem
When redirecting from a servlet using response.sendRedirect(redirect_url);, the JSESSIONID cookie is not passed by the browser to the destination. A new JSESSIONID is created for every redirect, and it is impossible to track the user.
Note: This problem is only occurring on my new server implementing https and a domain name; the session ID is properly tracked when I run the web app locally or on another server without SSL or a domain name. Edit: I have set up another site on my server without SSL, and the issue persists. This seems to narrow the issue down to having a reverse proxy Apache.
An Example
The Login servlet on my web app attempts to store the user information in a session attribute then redirects to the MyCards servlet. I am using a redirect so that the URL will display mydomain.com/MyCards instead of mydomain.com/Login. The MyCards servlet attemtps to access the session attribute but finds nothing, and therefore redirects back to the Login servlet. This worked perfectly before deploying the project on my new server with SSL and domain name.
My Setup
Ubuntu 20.04 on DigitalOcean droplet
Apache Web Server (apache2) ... I have enabled mod_sessions, not sure if that's relevant.
Tomcat 9
Reverse proxy in Apache VirtualHost to Tomcat (I can post my .conf file if requested)
A redirect in Apache VirtualHost from HTTP to HTTPS
JDK 11
Possible Solutions
Using a forward instead of a redirect. The session ID is not lost when using requestDispatcher.forward(request, response);. As I mentioned above, I want the URL to reflect the destination for an intuitive user experience, which does not occur when using a forward.
Implementing your own session cookie, as in this answer, and manually storing sessions with a map, as in this answer, which strongly advises against such a facility. Based on my understanding, doing so poses security threats to user data. Also, if the browser is not passing the JSESSIONID cookie, I don't understand why it would choose to pass the manually implemented cookie unless the SameSite attribute is set to None (also bad).
Verifying that the webapp's context.xml does not have cookies="false" configured. Done that.
Using encoded URLs with response.sendRedirect(response.encodeRedirectURL(url));. Again, for the sake of having a clean URL (which the user could bookmark or type in) is preferable, and encoding the session ID into the URL is not.
Using relative URLs instead of absolute URLs...
"A session is only maintained if the redirection is being sent on the same port, host and webapp [and protocol?]. If redirection is done within the same application, using relative paths is the best practice." I tried both redirect_url = "/MyCards" and redirect_url = "MyCards", no luck.
Possible Reasons
Perhaps I am unknowingly switching between HTTP and HTTPS, which is a change in protocol and will not preserve the session ID. Of course, my intention is to remain secure and stay exclusively in HTTPS. Edit: I have set up another site on my server without SSL, and the issue persists. This seems to narrow the issue down to having a reverse proxy Apache. When accessing the web app directly on Tomcat (i.e. with <server_ip>:8080/MyWebApp), the session is tracked properly on redirect. However when using mydomain.com, the session ID is lost on every redirect.
Something to do with naked domains.
Other?
Edit: Maybe the issue is occurring because of the way the client, Apache, and Tomcat interact via the reverse proxy. Does the proxy cause the domain/port to change on every request/response?
My Questions
Why exactly is the session ID lost when using a redirect to a relative URL to a servlet in the same web app on the same server? Shouldn't the redirect occur entirely on the server-side, preventing a new request/session from being created? Since the relative URLs (which I thought would preserve the session) did not solve the issue, does this indicate some problem with my server setup (e.g. unintentional switching between protocols)?
What is the best practice for maintaining the user session ID, even when the user has cookies disabled? Is there no way around URL encoding when cookies are disabled? Or should the app be implemented exclusively with forwards rather than redirects? If so, is there a workaround to changing the URL to reflect the destination?
Note: this is my first post, so I don't have the reputation to comment. I will edit the post with any needed information.

How to fix User Impersonation in Java Web Application?

I have java web application using struts 1.x. Recently my application has gone through penetration testing and our testers found some security holes. Let me explain. In my application i have 2 users called ‘Admin’ and ‘user’. First our PenTester logged to my application as ‘Admin’ and they use ‘Burp tool’ to intercept the request and copy the whole request content into notepad and then forward the request. Now My application log in as ‘Admin’. They use another browser instance to login as “user” and use burp tool to intercept the request. This time they removed the whole request content and copy back the whole request content of ‘Admin’ and then forward the request. Now my application logged in as ‘Admin’ without asking any user id/password? How to restrict this situation? I already stored userid in my session variable after successful login of each user. The moment they intercept the request and copy the ‘admin’ request content, my session variable userid also changed to ‘admin’. How to validate this situation? Your help is really appreciated.
That is not really that much of an issue since the first part "copy the whole request content" is not easily doable if you have a proper HTTPS / SSL connection. That only works if the PC the user is logged in on as an admin is compromised in which case: nothing you can do about it anyway because they can just sniff the keystrokes and get the plain password.
If on the other hand you communicate without the S, namely just HTTP then the solution is: get a certificate and switch to HTTPS.
Apart from that your application can pin a session to an IP which means if the session id / cookie is stolen and someone else uses it you can detect an IP mismatch and ask for credentials again.
To prevent direct replay attacks like copying the request and sending it again you can introduce a hash that incorporates the timestamp or alternative measures, see. How do I prevent replay attacks? . The problem however is that copying the entire request means copying the cookies as well and if the "admin" cookie is copied this measure will not prevent you from "generating" a new hash based on the now admin user.

How can a servlet pass back to the browser the entire content of a proxied login result?

I promised to do something, but my managers want assurance that it can be done. What seems like a simple task is surprisingly hard to find example of. It consists of:
The browser asks a Java servlet for access to a remote site.
The servlet opens a HttpUrlConnection to that remote site.
The servlet sends a login request to that remote site.
The servlet receives a login form.
The servlet populates the login form from user session data, then
POSTs it.
The servlet receives the "welcome" from the remote site, complete
with headers and cookies.
The request of step 1 is finally filled by the content, headers, and cookies from step 6.
I'm having trouble getting code examples, leading me to think that what I want to do can't be accomplished. Can someone point me to an example?
Thanks,
Jerome.
The main problem is the domain of the session cookie.
More accurately, the question is what you're planning next after step 7.
Say your servlet is at "https://mycompany.com/loginServlet", and the remote site is a toy store "https://toys.com". Were you hoping that after step 7, the browser could be redirected to "https://toys.com" and get a proper service befitting a logged-in user? This won't work because when the browser received a session cookie from "mycompany.com" (in step7), this cookie will be attached to further requests for "mycompany.com" - but not to "toys.com", it's a security feature for excellent reason.
In short, this approach might work if both the servlet and the toys site are on the same domain. Though it makes me a bit uncomfortable in terms of security and password management, but never mind.
Obviously this approach would also work in the (unrealistic) case of letting your server proxy all further requests from the browser to "toys.com", but that's unrealistic for a typical commercial site (due to relative/absolute links, ajaxes etc.).
If it's different domains, then I second the wise comment made by "Rahul B" above: please look into SSO, and/or check with "toys.com" what login mechanisms they offer - maybe they already have something like "login with google" that's convenient enough.

Transparent authentication with LDAP and Servlet

We have Windows Active Directory, where all users are registered and use to login in Windows.
We have an Apache server configured to use LDAP to authenticate users in that Active Directory. It's setup so that, in PHP, all we have to do is call $_SERVER['REMOTE_USER']. Browser verifies user login in Windows and sends this data to Apache, which talks to LDAP to verify authentication. When LDAP authenticates, that code returns user's login, otherwise it returns null.
This way we can safely and easily authenticate users inside PHP and use their AD login to control access to our softwares. Another advantage is that we don't need a login page and not even have to handle passwords in variables: authentication is handled transparently to users and they are automatically logged to our softwares all the time, and their password never comes into our code.
I'd like to do the same thing with Servlet. I see no reason for it not happen if it works with PHP. But I can't find how to do it. I googled but couldn't find anything. Has anybody done something like that and could point me a way?
Standard authentication with login and password is working in Java. If I have domain, login and password, (that in Servlet would come from a login page) I can authenticate any user.
What you're looking to do is plug a SSO provider into your web app. There are several options, you will have to do your own research into what will work best in your environment. You might want to investigate the following security frameworks, which all enable SSO:
Apache Shiro
Spring Security
JCIFS
There are also commercial products like CA SiteMinder that do the same thing.
the HttpServletRequest object you have in the doGet and doPost methods on the servlet has the equivalent of PHP $_SERVER['REMOTE_USER'], it is called getRemoteUser().
Your post is tagged as Tomcat. You could add a "realm" in tomcat to do the Authentication.
I have no idea how you can not prompt for a password unless you are using some sort of SASL plugin to verify the user against LDAP.
$_SERVER['REMOTE_USER'] implies you are using "HTTP Authentication" header which would (AFIK) require a popup for the credentials. Perhaps this is transparent if only using IE against a Windows server.
There is an example of how to configure tomcat

CAS SSO with multiple web applications

I've spent the last day or so looking in CAS and have managed to get the server working with a simple test application. When I enter a protected area, I'm redirect to a login page - when I log in, I'm taken back to my previous page.
From there, the next step would be deploy two client applications, log into client A, visit the client B protected area and have the system handle the authentication for me (since I'm already logged into client A).
This isn't actually working however. I have to log into the client B site whether I'm logged into the client A site or not.
CAS is running on Tomcat, client A and B are the same project deployed as separate wars on a single instance of JBoss AS 6.
Any ideas how I can achieve the suggested behavior?
EDIT: Yes, both are using CAS. The issue is that it doesn't seem to be recognizing that the user is already logged in. It's as if the CAS isn't able to determine that there is a 'link' between the two services and that when one service has been authenticated, the other service should be automatically authenticated.
I should note that at this stage, I am not using SSL within the application. I'm focused on getting a simple example up and going using HTTP before I look at introducing SSL.
Both of your applications need to be configured to use the CAS server for authentication. The normal procedure would be that application A redirects you to your CAS login page, lets you log in and redirects you back to A. If you then try to log into B, it checks with the CAs server whether you're already logged in and, if so, sends back information about the logged in user.
Again, both your applications need to support CAS as a login mechanism, which I am not sure about from your description.
Detailed description of the CAS protocol can be found here.
CAS was working without SSL in that it would take you to the login site and authenticate you correctly. The issue was if you tried to access via another site, it would ask you to sign in again.
Once I enabled SSL and tried it, it was working correctly. Once logged into client A, it would automatically authenticate you in client B. I had spent some time on the wiki and while it spoke of the importance of using SSL, I do not recall it explicitly stating that SSO will not work without SSL enabled. Maybe a warning should be added to the wiki?
If you want to focus on your applications and make your life easier, use a cloud provider for the CAS server: http://www.casinthecloud.com (free servers are available for tests).

Categories