Servlet - Implementing Programmatic Security by using login() and logout() methods

[Updated: Aug 2, 2017, Created: Aug 1, 2017]

In this example, we will learn how to implement programmatic security by using HttpServletRequest.login() and HttpServletRequest.logout() methods.

For implementing programmatic security, we don't have to use @ServletSecurity which is a declarative approach to specify security constraints on a servlet. Also we will not specify auth-method in web.xml with value 'BASIC'. By using login() and logout() methods, we can implement a form based login which is an alternative approach to Basic Authentication.

Example

The Servlets

@WebServlet(name = "securedServlet", urlPatterns = {"/app"})
public class MySecuredServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req,
                       HttpServletResponse resp) throws ServletException, IOException {

      Principal principal = req.getUserPrincipal();
      if (principal == null || !req.isUserInRole("employee")) {
          LoginHandlerServlet.forwardToLogin(req, resp, null);
          return;
      }
      resp.setContentType("text/html");
      PrintWriter writer = resp.getWriter();
      writer.println("Welcome to the secured app!");
      writer.printf("<br/>User: " + req.getRemoteUser());
      writer.printf("<br/>time: " + LocalDateTime.now());
      writer.println("<br/><a href='/logout'>Logout</a>");
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
      doGet(req, resp);
  }
}
@WebServlet(name = "loginServlet", urlPatterns = {"/loginHandler"})
public class LoginHandlerServlet extends HttpServlet {
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {

      String theUser = req.getParameter("theUser");
      String thePassword = req.getParameter("thePassword");
      try {
          req.login(theUser, thePassword);
      } catch (ServletException e) {
          System.out.println(e.getMessage());
          forwardToLogin(req, resp, "Error: " + e.getMessage());
          return;
      }
      boolean loggedIn = req.getUserPrincipal() != null && req.isUserInRole("employee");
      if (loggedIn) {
          resp.sendRedirect("/app");
      } else {
          forwardToLogin(req, resp, "Login failed.");
      }
  }

  public static void forwardToLogin(HttpServletRequest req, HttpServletResponse resp,
                                    String errorMessage)
          throws ServletException, IOException {

      req.setAttribute("errorMsg", errorMessage);
      req.getRequestDispatcher("/login.jsp")
         .forward(req, resp);
  }
}
@WebServlet(name = "logoutServlet", urlPatterns = {"/logout"})
public class LogoutServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
      req.logout();
      Principal principal = req.getUserPrincipal();
      if (principal != null) {
          throw new RuntimeException("Cannot log out the user");
      }
      resp.sendRedirect("/app");
  }
}

JSP Page

We have to provide a custom login form for this example, which is different from the Basic Authentication case where most of the browser provide an automatic login form (as we saw in the last two examples).

src/main/webapp/login.jsp

<html>
<body>
<div style="color:red">
    <%
     Object msg = request.getAttribute("errorMsg");
        if(msg != null ){
           out.println(msg);
        }
     %>
</div>
<form action="/loginHandler" method="post">
    <table>
        <tr>
            <td> User:</td>
            <td><input type="text" name="theUser"/></td>
        </tr>
        <tr>
            <td> Password:</td>
            <td><input type="password" name="thePassword"/></td>
        </tr>
    </table>
    <input type="submit" value="Submit"/>
</form>
</body>
</html>

Adding tomcat-users.xml

As we are going to run embedded tomcat for this example, we will add tomcat-user.xml (as a realm) in the project.

src/main/webapp/config/tomcat-users.xml

<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
    <role rolename="employee"/>
    <user username="Joe" password="123" roles="employee"/>
</tomcat-users>

Specifying tomcat-user.xml location

pom.xml

<plugin>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.2</version>
  <configuration>
   <path>/</path>
   <tomcatUsers>src/main/webapp/config/tomcat-users.xml</tomcatUsers>
  </configuration>
 </plugin>

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

Output

On submitting user/password:

On clicking logout link:

On entering wrong username/password:

Example Project

Dependencies and Technologies Used :

  • javax.servlet-api 3.1.0 Java Servlet API
  • JDK 1.8
  • Maven 3.3.9

Servlet Programmatic Security Example Select All Download
  • servlet-programmatic-login-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • webapp
          • config

See Also