On most websites, when the user is about to provide the username and password to log into the system, there's a checkbox like "Stay logged in". If you check the box, it will keep you logged in across all sessions from the same web browser. How can I implement the same in Java EE?
I'm using FORM based container managed authentication with a JSF login page.
<security-constraint>
<display-name>Student</display-name>
<web-resource-collection>
<web-resource-name>CentralFeed</web-resource-name>
<description/>
<url-pattern>/CentralFeed.jsf</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>STUDENT</role-name>
<role-name>ADMINISTRATOR</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>jdbc-realm-scholar</realm-name>
<form-login-config>
<form-login-page>/index.jsf</form-login-page>
<form-error-page>/LoginError.jsf</form-error-page>
</form-login-config>
</login-config>
<security-role>
<description>Admin who has ultimate power over everything</description>
<role-name>ADMINISTRATOR</role-name>
</security-role>
<security-role>
<description>Participants of the social networking Bridgeye.com</description>
<role-name>STUDENT</role-name>
</security-role>
Normally this is done like this:
When you log in a user you also set a cookie on the client ( and store the cookie value in the database ) expiring after a certain time (1-2 weeks usually).
When a new request comes in you check that the certain cookie exists and if so look into the database to see if it matches a certain account. If it matches you will then "loosely" log in that account. When i say loosely i mean you only let that session read some info and not write information. You will need to request the password in order to allow the write options.
This is all that is. The trick is to make sure that a "loosely" login is not able to do a lot of harm to the client. This will somewhat protect the user from someone who grabs his remember me cookie and tries to log in as him.
Java EE 8 and up
If you're on Java EE 8 or newer, put
@RememberMe
on a customHttpAuthenticationMechanism
along with aRememberMeIdentityStore
.You can find a real world example in the Java EE Kickoff Application.
Java EE 6/7
If you're on Java EE 6 or 7, homegrow a long-living cookie to track the unique client and use the Servlet 3.0 API provided programmatic login
HttpServletRequest#login()
when the user is not logged-in but the cookie is present.This is the easiest to achieve if you create another DB table with a
java.util.UUID
value as PK and the ID of the user in question as FK.Assume the following login form:
And the following in
doPost()
method of aServlet
which is mapped on/login
:(the
COOKIE_NAME
should be the unique cookie name, e.g."remember"
and theCOOKIE_AGE
should be the age in seconds, e.g.2592000
for 30 days)Here's how the
doFilter()
method of aFilter
which is mapped on restricted pages could look like:In combination with those cookie helper methods (too bad they are missing in Servlet API):
Although the
UUID
is extremely hard to brute-force, you could provide the user an option to lock the "remember" option to user's IP address (request.getRemoteAddr()
) and store/compare it in the database as well. This makes it a tad more robust. Also, having an "expiration date" stored in the database would be useful.It's also a good practice to replace the
UUID
value whenever the user has changed its password.Java EE 5 or below
Please, upgrade.
You cannot login a user completely via HttpServletRequest.login(username, password) since you shouldn't keep both username and plain text password in the database. Also you cannot perform this login with a password hash which is saved in the database. However, you need to identify a user with a cookie/DB token but log him/her in without entering password using custom login module (Java class) based on Glassfish server API.
See the following links for more details:
http://www.lucubratory.eu/custom-jaas-realm-for-glassfish-3/
Custom Security mechanism in Java EE 6/7 application