Session Management in Java using Servlet Filters and Cookies

Source: https://ak0.picdn.net/shutterstock/videos/9572030/thumb/11.jpg

(If you are not familiar with Servlets and JSP, please refer my previous post on Sample Java Web Application using Servlets and JSP)

By default HTTP protocol is stateless. This means that every request is a new request to a server. Although there are advantages of being stateless, some occasions enforce to maintain a state in order to its proper functionality. For example, consider a user logging into a website. After authentication, the website needs to maintain a logged state for the user in order to execute his actions. A web server can easily achieve this by using Cookies.

What are Cookies?

A Cookie is a small piece of data that is exchanged between a server and a client. Whenever a client sends a request, the server will send a cookie containing the required data and the client can send back the cookie with its next request. In session management, Tomcat creates a session id whenever client’s first request gets to the server (However, other servlet containers may behave differently). Then it inserts this session id into a cookie with a name JSESSIONID and sends along with the response. After receiving the response with the cookie, the client can send the received cookie in its next request so that the server will identify the session using session id that resides in the JSESSIONID cookie.

In this tutorial, I will explain how to create a simple login interface that will maintain a login session. I am using IntelliJ Idea as my IDE and Maven tomcat plugin to deploy the war. (Please refer this if you are not familiar with them)

Step 1: Create a maven project in intelliJ idea

Step 2: Add the required dependencies to the pom.xml

Add the javax.servlet-api and tomcat7-maven-plugin into the pom.xml and make the packaging as “war”. After that, your pom.xml should be similar to this.

Step 3: Create the login page

3.1. Create a directory with the name “webapp” under src/main/ and insert the following loginPage.html file.

This will be the landing page for our application. When the user enters his username and password, a post request containing those parameters is send to our LoginServlet.

Step 4: Create the LoginServlet class

Create LoginServlet.java under src/main/java with a package name of com.servlet.session and insert the following code.

Inside the LoginServlet, we are comparing the received credentials with a set of stored credentials in the servlet. If they both match, the user can be successfully authenticated.

Be sure to invalidate the session that existed before authenticating the user and create a new session after authenticating.

HttpSession newSession = request.getSession(true);

Above line creates a new session and saves it in the newSession object. This will also create the JSESSIONID cookie with the new value. Note that passing the Boolean parameter “false” to the getSession() returns the existing session and returns null if no session exists. Passing the parameter “true” will create a new session if no session exists.

If we want to expire the session after some period and prompt user to log in again, we can use setMaxInactiveInterval().

We can also add new cookies to the session. Here, we are creating a cookie with the name message and inserting the value “Welcome” into the cookie.

Set the “secure” flag in a cookie if you want to stop sending a cookie to an HTTP page. Browsers will send the “secure” cookies only through HTTPS channels. “HttpOnly” flag in a cookie makes it inaccessible to JavaScript’s Document.cookie API. This can help in preventing Cross Site Scripting (XSS) attacks.

cookie.setSecure(true);
cookie.setHttpOnly(true);

Note that tomcat automatically sets the HTTPOnly flag in the JSESSIONID cookie.

After all this, we can redirect the user to Login Success page.

If the credentials don’t match, we are redirecting the user to the login page with an error message saying “Either username or password is wrong”. In this step, we are not specifying which parameter is wrong due to security reasons. If an attacker is trying to log in by brute force, we don’t want to inform him even if he enters the correct username.

We have used @WebFilter annotation to map the URL pattern /LoginServlet into our Servlet. We can also achieve this by using a deployment descriptor (web.xml)

Step 5: Create the LoginSuccess.jsp

Create a LoginSuccess.jsp file under src/main/java/webapp/admin and add the following code.

Once the user gets redirected to this LoginSuccess.jsp, we can read the cookies set by LoginServlet. Since there are multiple cookies, we have iterated through the cookies array and extracted the required cookie values. Here we display the cookie values on the Login Success page. This page contains the logout link that will send the logout request to the LogoutServlet.

Step 6: Create the Logout Servlet

Create a LogoutSevlet.java under src/main/java with a package name com.servlet.session and insert the following code.

In here we are invalidating the authenticated session and redirect the user to the login page. Note that we have added the /admin/LogoutServlet as the servlet mapping.

Now, build the war file and deploy!

Since I’m using tomcat maven plugin, I can simply enter 
mvn tomcat7:run
in the terminal and go to http://localhost:8080/Login/loginPage.html

Here /Login is my maven artifactID (see my pom.xml).

After login, you will be redirected to LoginSuccess.jsp

Once you press the logout, you will be again redirected to the login page.

However, you will notice that even after the logout, we can still browse to the LoginSuccess.jsp(http://localhost:8080/Login/admin/LoginSuccess.jsp). It will still show a success login. Whaaaaat????

So, the above authentication process is useless? No. This is where Servlet Filters come in to play (If you are not familiar with servlet filters, read my blog on How to use Servlet Filters).

Let’s use Servlet Filters

A servlet filter can block the access to the LoginSuccess.jsp when the session is null.

Step 7: Create the Authentication Filter

Create an AuthenticationFilter.java under src/main/java with a package name com.servlet.filter and insert the following code.

In order to make this filter active, we need to define the filter and the required filter mapping in the web.xml

Step 8: Create the web.xml

Create the WEB-INF directory under webapp directory and add the following web.xml file.

If there is a request for a path that starts with /admin without an existing session, this filter will log it as an unauthorized request and redirect to loginPage.html. If the session exists, the request is passed to the next filter in the filter chain. This will prevent unauthorized users accessing LoginSuccess page while allowing logged users to access. Any additional Servlets or JSPs that needs to be accessed by authorized users, can be exposed under the URL pattern /admin

Here ServletContext logs are used to log filter initialization and user actions. These logs can be viewed from %TOMCAT_HOME/logs/localhost.$(date).log file.

Now you can try to browse to the LoginSuccess.jsp before login. You will see that it gets automatically redirected to the loginPage.html. If you examine the logs, you will see the “Unauthorized access request” log message.

References