13 min read

In this article series, we will develop a secure Java EE application based on Java EE and GlassFish capabilities. In course of the article, we will cover following topics:

  • Analyzing Java EE application security requirements
  • Including security requirements in Java EE application design
  • Developing secure Business layer using EJBs
  • Developing secure Presentation layer using JSP and Servlets
  • Configuring deployment descriptors of Java EE applications
  • Specifying security realm for enterprise applications
  • Developing secure application client module
  • Configuring Application Client Container

Read Designing Secure Java EE Applications in GlassFish here.

Developing the Presentation layer

The Presentation layer is the closest layer to end users when we are developing applications that are meant to be used by humans instead of other applications. In our application, the Presentation layer is a Java EE web application consisting of the elements listed in the following table. In the table you can see that different JSP files are categorized into different directories to make the security description easier.

Element Name

Element Description

Index.jsp

Application entry point. It has some links to functional JSP pages like toMilli.jsp and so on.

auth/login.html

This file presents a custom login page to user when they try to access a restricted resource. This file is placed inside auth directory of the web application.

auth/logout.jsp

Logging users out of the system after their work is finished.

auth/loginError.html

Unsuccessful login attempt redirect users to this page. This file is placed inside auth directory of the web application

jsp/toInch.jsp

Converts given length to inch, it is only available for managers.

jsp/toMilli.jsp

Converts given length to millimeter, this page is available to any employee.

jsp/toCenti.jsp

Converts given length to centimeter, this functionality is available for everyone.

Converter Servlet

Receives the request and invoke the session bean to perform the conversion and returns back the value to user.

auth/accessRestricted.html

An error page for error 401 which happens when authorization fails.

Deployment Descriptors

The deployment descriptors which we describe the security constraints over resources we want to protect.

Now that our application building blocks are identified we can start implementing them to complete the application. Before anything else let’s implement JSP files that provides the conversion GUI. The directory layout and content of the Web module is shown in the following figure:

Implementing the Conversion GUI

In our application we have an index.jsp file that acts as a gateway to the entire system and is shown in the following listing:

<html>
    <head><title>Select A conversion</title></head>
    <body><h1>Select A conversion</h1>
        <a href="auth/login.html">Login</a>        <br/>
        <a href="jsp/toCenti.jsp">Convert Meter to Centimeter</a>
        <br/>
        <a href="jsp/toInch.jsp">Convert Meter to Inch</a>
        <br/>
        <a href="jsp/toMilli.jsp">Convert to Millimeter</a><br/>
        <a href="auth/logout.jsp">Logout</a>
    </body>
</html>

Implementing the Converter servlet

The Converter servlet receives the conversion value and method from JSP files and calls the corresponding method of a session bean to perform the actual conversion. The following listing shows the Converter servlet content:

@WebServlet(name="Converter", urlPatterns={"/Converter"})
public class Converter extends HttpServlet {
    @EJB
    private ConversionLocal conversionBean;

protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
System.out.println(“POST”);
response.setContentType(“text/html;charset=UTF-8”);
PrintWriter out = response.getWriter();
try{
int valueToconvert =
Integer.parseInt(request.getParameter(“meterValue”));
String method = request.getParameter(“method”);
out.print(“<hr/> <center><h2>Conversion Result is: “);
if (method.equalsIgnoreCase(“toMilli”)) {

out.print(conversionBean.toMilimeter(valueToconvert));
} else if (method.equalsIgnoreCase(“toCenti”)) {

out.print(conversionBean.toCentimeter(valueToconvert));
} else if (method.equalsIgnoreCase(“toInch”)) {
out.print(conversionBean.toInch(valueToconvert));
}
out.print(“</h2></center>”);

}catch (AccessLocalException ale) {

response.sendError(401);
}finally {
out.close();
}
}
}

Starting from the beginning we are using annotation to configure the servlet mapping and servlet name instead of using the deployment descriptor for it. Then we use dependency injection to inject an instance of Conversion session bean into the servlet and decide which one of its methods we should invoke based on the conversion type that the caller JSP sends as a parameter. Finally, we catch javax.ejb.AccessLocalException and send an HTTP 401 error back to inform the client that it does not have the required privileges to perform the requested action. The following figure shows what the result of invocation could look like:

Each servlet needs some description elements in the deployment descriptor or included as deployment descriptor elements.

Implementing the conversion JSP files is the last step in implementing the functional pieces. In the following listing you can see content of the toMilli.jsp file.

<html>
    <head><title>Convert To Millimeter</title></head>
    <body><h1>Convert To Millimeter</h1>
        <form method=POST action="../Converter">Enter Value to 
          Convert: <input name=meterValue>
            <input type="hidden" name="method" value="toMilli">
              <input type="submit" value="Submit" />
        </form>

</body>
</html>

The toCenti.jsp and toInch.jsp files look the same except for the descriptive content and the value of the hidden parameter which will be toCenti and toInch respectively for toCenti.jsp and toInch.jsp.

Now we are finished with the functional parts of the Web layer; we just need to implement the required GUI for security measures.

Implementing the authentication frontend

For the authentication, we should use a custom login page to have a unified look and feel in the entire web frontend of our application. We can use a custom login page with the FORM authentication method. To implement the FORM authentication method we need to implement a login page and an error page to redirect the users to that page in case authentication fails. Implementing authentication requires us to go through the following steps:

  • Implementing login.html and loginError.html
  • Including security description in the web.xml and sun-web.xml or sun-application.xml

Implementing a login page

In FORM authentication we implement our own login form to collect username and password and we then pass them to the container for authentication. We should let the container know which field is username and which field is password by using standard names for these fields. The username field is j_username and the password field is j_password. To pass these fields to container for authentication we should use j_security_check as the form action. When we are posting to j_security_check the servlet container takes action and authenticates the included j_username and j_password against the configured realm. The listing below shows login.html content.

<form method="POST" action="j_security_check">
    Username: <input type="text"     name="j_username"><br />
    Password: <input type="password" name="j_password"><br />
    <br />
    <input type="submit" value="Login">
    <input type="reset" value="Reset">
</form>

The following figure shows the login page which is shown when an unauthenticated user tries to access a restricted resource:

Implementing a logout page

A user may need to log out of our system after they’re finished using it. So we need to implement a logout page. The following listing shows the logout.jsp file:

<%
session.invalidate();
%>
<body>
    <center>
    <h1>Logout</h1>
    You have successfully logged out.
    </center>
</body>

Implementing a login error page

And now we should implement LoginError.html, an authentication error page to inform user about its authentication failure.

<html>
    <body>
        <h2>A Login Error Occurred</h2>
        Please click <a href="login.html">here</a> for another try.
    </body>
</html>

Implementing an access restricted page

When an authenticated user with no required privileges tries to invoke a session bean method, the EJB container throws a javax.ejb.AccessLocalException. To show a meaningful error page to our users we should either map this exception to an error page or we should catch the exception, log the event for audition purposes, and then use the sendError() method of the HttpServletResponse object to send out an error code. We will map the HTTP error code to our custom web pages with meaningful descriptions using the web.xml deployment descriptor. You will see which configuration elements we will use to do the mapping. The following snippet shows AccessRestricted.html file:

<body>
      <center>  <p>You need to login to access the requested 
        resource. To login go to <a href="auth/login.html">Login
        Page</a></p></center>
</body>

Configuring deployment descriptors

So far we have implemented required files for the FORM-based authentication and we only need to include required descriptions in the web.xml file. Looking back at the application requirement definitions, we see that anyone can use meter to centimeter conversion functionality and any other functionality that requires the user to login. We use three different HTML pages for different types of conversion. We do not need any constraint on toCentimeter.html therefore we do not need to include any definition for it. Per application description, any employee can access the toMilli.jsp page. Defining security constraint for this page is shown in the following listing:

<security-constraint>
    <display-name>You should be an employee</display-name>
    <web-resource-collection>
      <web-resource-name>all</web-resource-name>
      <description/>
      <url-pattern>/jsp/toMillimeter.html</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
      <http-method>DELETE</http-method>
    </web-resource-collection>
    <auth-constraint>
      <description/>
      <role-name>employee_role</role-name>
    </auth-constraint>
</security-constraint>

We should put enough constraints on the toInch.jsp page so that only managers can access the page. The listing included below shows the security constraint definition for this page.

<security-constraint>
    <display-name>You should be a manager</display-name>
    <web-resource-collection>
      <web-resource-name>Inch</web-resource-name>
      <description/>
      <url-pattern>/jsp/toInch.html</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
      <description/>
      <role-name>manager_role</role-name>
    </auth-constraint>
</security-constraint>

Finally we need to define any role we used in the deployment descriptor. The following snippet shows how we define these roles in the web.xml page.

<security-role>
    <description/>
    <role-name>manager_role</role-name> 
</security-role>
<security-role>
    <description/>
    <role-name>employee_role</role-name>
</security-role>

Looking back at the application requirements, we need to define data constraint and ensure that username and passwords provided by our users are safe during transmission. The following listing shows how we can define the data constraint on the login.html page.

<security-constraint>
    <display-name>Login page Protection</display-name>
    <web-resource-collection>
        <web-resource-name>Authentication</web-resource-name>
        <description/>
        <url-pattern>/auth/login.html</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <user-data-constraint>
        <description/>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

One more step and our web.xml file will be complete. In this step we define an error page for HTML 401 error code. This error code means that application server is unable to perform the requested action due to negative authorization result. The following snippet shows the required elements to define this error page.

<error-page>
    <error-code>401</error-code>
    <location>AccessRestricted.html</location>
</error-page>

Now that we are finished with declaring the security we can create the conversion pages and after creating these pages we can start with Business layer and its security requirements.

Specifying the security realm

Up to this point we have defined all the constraints that our application requires but we still need to follow one more step to complete the application’s security configuration. The last step is specifying the security realm and authentication. We should specify the FORM authentication and per-application description; authentication must happen against the company-wide LDAP server.

Here we are going to use the LDAP security realm LDAPRealm. We need to import a new LDIF file into our LDAP server, which contains groups and users definition required for this article. To import the file we can use the following command, assuming that you downloaded the source code bundle from https://www.packtpub.com//sites/default/files/downloads/9386_Code.zip and you have it extracted.

import-ldif --ldifFile path/to/chapter03/users.ldif
 --backendID userRoot --clearBackend --hostname 127.0.0.1 --port 4444
 --bindDN cn=gf cn=admin --bindPassword admin --trustAll --noPropertiesFile

The following table show users and groups that are defined inside the users.ldif file.

Username and password

Group membership

james/james manager, employee
meera/meera employee

We used OpenDS for the realm data storage and it had two users, one in the employee group and the other one in the manager group. To configure the authentication realm we need to include the following snippet in the web.xml file.

<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>LDAPRealm</realm-name>
    <form-login-config>
        <form-login-page>/auth/login.html</form-login-page>
        <form-error-page>/auth/loginError.html</form-error-page>
    </form-login-config>
</login-config>

If we look at our Web and EJB modules as separate modules we must specify the role mappings for each module separately using the GlassFish deployment descriptors, which are sun-web.xml and sun-ejb.xml. But we are going to bundle our modules as an Enterprise Application Archive (EAR) file so we can use the GlassFish deployment descriptor for enterprise applications to define the role mapping in one place and let all modules use that definitions. The following listing shows roles and groups mapping in the sun-application.xml file.

<sun-application>
    <security-role-mapping>
        <role-name>manager_role</role-name>
        <group-name>manager</group-name>
    </security-role-mapping>
    <security-role-mapping>
        <role-name>employee_role</role-name>
        <group-name>employee</group-name>
    </security-role-mapping>
    <realm>LDAPRealm</realm>
</sun-application>

The security-role-mapping element we used in sun-application.xml has the same schema as the security-role-mapping element of the sun-web.xml and sun-ejb-jar.xml files.

You should have noticed that we have a realm element in addition to role mapping elements. We can use the realm element of the sun-application.xml to specify the default authentication realm for the entire application instead of specifying it for each module separately.

Summary

In this article series, we covered the following topics:

  • Analyzing Java EE application security requirements
  • Including security requirements in Java EE application design
  • Developing secure Business layer using EJBs
  • Developing secure Presentation layer using JSP and Servlets
  • Configuring deployment descriptors of Java EE applications
  • Specifying security realm for enterprise applications
  • Developing secure application client module
  • Configuring Application Client Container

We learnt how to develop a secure Java EE application with all standard modules including Web, EJB, and application client modules.

LEAVE A REPLY

Please enter your comment!
Please enter your name here