SecureJavaEE6App

Contents

Securing JavaEE 6 application with JavaEE Security and LDAP

Introduction

This document is an extension from the tutorial, Develop JavaEE 6 Application with JSF2, EJB3 and JPA.

In the previous tutorial we have looked at how to develop a full-fledged JEE 6 application, but without the Security piece which is something that is not acceptable in a production system. So here, we will tackle the Security aspects of a JEE 6 application.

In the JavaEE 6 specs, there is a whole section dedicated to Security, and what we will be focusing here is the Authentication and Authorization portions which is a basic requirement for any applications because you want the user to identify himself or herself and based on that together with the roles defined, decide whether or not he/she can view or perform actions on the screens.

In this tutorial, we are going to secure the web application, CustomerApp that was developed in the previous tutorial. Basically, the application has the following functionalities:

  • View the listing of Customers
  • View the details of the selected Customer
  • Update the details of the selected Customer

So after putting the security is in place, we want to achieve the followings:

  • Everybody (including those not logged in) can View the Customer listing
  • Only Logged-in users can View the Customer details
  • Only Admin users can Update the Customer details

In the nutshell, we will define TWO roles: Admin and CustomerRep, and we will need a user/authentication source, which is a LDAP server. The following sections will detail the steps and procedure to setup the environment and modify the application to achieve the above-mentioned.

Tutorial Requirements

Before we proceed, make sure you review the requirements in this section.

Prerequisites

This tutorial assumes that you have some basic knowledge of, or programming experience with, the following technologies.

  • JavaServer Pages/Faces (JSP/JSF)
  • Basic knowledge of JEE5/6 Security, JEE6 Tutorial - Security
  • Basic knowledge of LDAP (OpenDS)
  • Basic knowledge of using Netbeans (will help to reduce the time required to do this tutorial)

Software needed for this Tutorial

Before you begin, you need to install the following software on your computer:

  • Netbeans IDE 6.8 (Java pack)
  • Glassfish Enterprise Server v3 (b73 or later)
  • Sample database installed along with Netbeans

    File:2-2-DBSetup.png
  • OpenDS 2.0 or later, http://www.opends.org. This is a free and comprehensive next generation directory service, based on LDAP and DSML standards

Notes

  • The Glassfish Enterprise Server is optionally included in the Java pack of Netbeans IDE, Glassfish can be installed separately from the IDE and added later into Servers services in the IDE
  • A copy of the working solution is included here if needed.

Setting up the LDAP Server

Glassfish v3 supports a number of different security realms out-of-the-box, e.g. File, JDBC, Certificate, Solaris and LDAP. In this tutorial, we will be using LDAP because it is the most commonly used authentication source and repository in a production system. Again, there are many LDAP servers out there, and we will be using OpenDS (http://www.opends.org) for this tutorial because of its ease of use.

The followings detail the steps required to setup OpenDS from scratch.

  1. First, we need to download the software, at the time of creating this tutorial the latest available version was v2.2.0 RC4, http://www.opends.org/promoted-builds/2.2.0-RC4
  2. To simplify things, we can use the web start installer in the page, click on the install/QuickSetup.jnlp link

  3. Upon clicking the link, the installation/setup will start. Select "Install New Server Instance" and click Next

  4. Under the Server Settings, you can use the default settings and provide the password and click Next

  5. Under the Topology Options, select "This will be a standalone server", and click Next

  6. Under the Directory Data settings, choose only to create the sample(base) entry, dc=example,dc=com, and click Next

  7. Review the settings and click Finish

  8. Make sure the installation is completed successfully as shown below, and click on the "Launch Control Panel" button

  9. Login with the password provided during the setup earlier and in the main panel, click on the Start button to start the LDAP instance. Click on the Manage Entries item under the Directory Data menu on the left

  10. In the "Manage Entries" screen, right-click on the entry, dc=example,dc=com on the left and select "New User..."
  11. In the "New User" screen, enter details for the new user, admin as shown below and click OK

    File:3-10-OpenDS_CreateUser.png

    Using the same steps, create another user with User ID, custrep, and we are done creating users, next we will create the groups.
  12. Again in the "Manage Entries" screen, right-click on the entry, dc=example,dc=com and select "New Group..."
  13. In the "New Group" screen, enter Administrator for the "Name" field and specify admin as the Static Group Member by clicking on the "Add Members" button and selecting the admin user in the "Add Members" screen



    Repeat the steps to create another group, CustomerService and specify the user, custrep as the member
  14. So we should now have 2 groups with each having 1 user as follows:

    1. Administrator
      • admin
    2. CustomerService
      • custrep

Configuring the LDAP Realm in Glassfish

Now that we have the LDAP up and running, we will now configure the Glassfish to have a LDAP realm for use by the application.

  1. Go to the Glassfish admin console, http://localhost:4848
  2. Navigate to the "Configuration->Security->Realms" page and click on the "New" button
  3. In the "New Realm" page, enter the details as shown below and click OK when done



    This will create a new Security Realm in Glassfish identified by the name ldap-realm

Modifying the CustomerApp Application

In this tutorial, or in fact in most cases, the form-based authentication in JEE security is preferred because it provides better consistency and control and yet very simple.

To secure the web application, we need to make the following changes to the application:

  1. Modify the CustomerMBean to include new properties to be used by the new pages pertaining to the authentication functions
  2. Create additional JSF pages, e.g. Logout, Logout, etc
  3. Modify the existing pages to include the Logout function
  4. Modify the security section of the deployment descriptors, i.e. web.xml and sun-web.xml

Modify CustomerMBean

Before creating the JSF pages, we need to add new methods in CustomerMBean class to provide properties pertaining to the authentication functions
    /**
     * @return Principal of the logged-in user
     */
    private Principal getLoggedInUser()
    {
        HttpServletRequest request =
                (HttpServletRequest) FacesContext.getCurrentInstance().
                    getExternalContext().getRequest();
        return request.getUserPrincipal();
    }

    /**
     * Property
     * @return true if user is logged in, false otherwise
     */
    public boolean isUserNotLogin()
    {
        Principal loginUser = getLoggedInUser();
        if (loginUser == null)
        {
            return true;
        }
        return false;
    }

    /**
     * Property
     * @return Username of the logged-in user
     */
    public String getLoginUserName()
    {
        Principal loginUser = getLoggedInUser();
        if (loginUser != null)
        {
            return loginUser.getName();
        }
        return "Not logged in";
    }

Create Additional JSF Pages

The new JSF pages to be created are:

  • Login.jsp - login page for the form-based authentication
  • LoginError.jsp - the error page for login failures
  • Logout.jsp - the page to display upon a logout
  • AccessDenied.jsp - a customized page to replace the default page displayed by the app server when user hits an unauthorized page or action (Error code - 403)

Login.jsp

For the form-based authentication to work, the Login form must adhere to the followings:

  • Form action set to "j_security_check"
  • ID for the username input field must be set to "j_username"
  • ID for the password input field must be set to "j_password"
So the content of the page should look like this:
<f:view>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <title>Login</title>
            <LINK REL="stylesheet" TYPE="text/css" MEDIA="all" HREF="css/default.css">
        </head>
        <body>
            <center><br><br><br>
            <h2><h:outputText value="Please Login"/></h2>
            <form action="j_security_check">
                <h:panelGrid columns="2" bgcolor="#eff5fa" cellspacing="5" frame="box">
                <h:outputLabel value="User ID:"/>
                <h:inputText id="j_username" tabindex="1" />
                <h:outputLabel value="Password:"/>
                <h:inputSecret id="j_password"/>
                <h:outputLabel value=""/>
                <h:commandButton id="login" value="Login"/>
            </h:panelGrid>
            </form>
            </center>
        </body>
    </html>
</f:view>

LoginError.jsp

This is the page to be displayed when login fails, e.g. wrong password. This is required for form-based login.
<f:view>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <title>Login Failure</title>
            <LINK REL="stylesheet" TYPE="text/css" MEDIA="all" HREF="css/default.css">
        </head>
        <body>
            <br><center>
            <h1><h:outputText value="Login Failed!"/></h1>
            <br><br>
            <h:outputLink value="Login.jsp">Please try again</h:outputLink>
            </center>
        </body>
    </html>
</f:view>

Logout.jsp

This page shows that the user is logged out, but its biggest responsibility is to invalidate the session
<f:view>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <title>Logout</title>
            <LINK REL="stylesheet" TYPE="text/css" MEDIA="all" HREF="css/default.css">
        </head>
        <body>
            <center>
                <h1><h:outputText value="You have logged out!"/></h1>
            <br><br><h:outputText value="What would you like to do?"/>
            <li><h:outputLink value="Login.jsp">Login again</h:outputLink></li>
            <li><h:outputLink value="CustomerList.jsp">Go to Customer Listing</h:outputLink></li>
            </center>
        </body>
    </html>
</f:view>
<%
    session.invalidate();
%>

AccessDenied.jsp

This page replaces the default page that the application server will display when user hits an unauthorized page or action (Error code - 403). Again this is optional and is included for better consistency in the look and feel.
<f:view>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <title>Access Denied</title>
            <LINK REL="stylesheet" TYPE="text/css" MEDIA="all" HREF="css/default.css">
        </head>
        <body>
            <br><center>
            <h1><h:outputText value="Sorry, you do not have permission to perform this task!"/></h1>
            <br><br>
            <h:outputLink value="javascript:history.back()"><Back</h:outputLink>
            </center>
        </body>
    </html>
</f:view>

Modify Existing Pages

Currently, there are only 2 existing pages in the app, i.e. CustomerList and CustomerDetails. If we are allowing the users to login, we should allow users to logout as well. So we will add in the logout link and optionally, the username of the logged-in user. To do that, we add the following statements in the 2 pages:
<h:outputLabel value="Logged in user is: "/><h:outputText value="#{customer.loginUserName}"/>   
<h:outputLink value="Logout.jsp" disabled="#{customer.userNotLogin}">Logout</h:outputLink>

Modify the Web App Deployment Descriptors

After adding and modifying the source codes, the last thing is to do is to make changes to the Web application's deployment descriptors: web.xml and sun-web.xml, in particular the Security sections.

  1. Open up the file web.xml in the CustomerApp-war project and navigate to the Security section by clicking on the "Security" button near the top of the editor
  2. In the Security section, go to the Login Configuration (top) and select the Form option, and provide the Login and Error pages, and the Realm Name as shown below. Also under the Security Roles section, add in the roles: Admin and CustomerRep



    Note: the Realm Name entered must match the name of the new LDAP security realm, ldap-realm created in Glassfish earlier
  3. Scroll down to the Security Constraints section, and click on the "Add Security Constraint" button to create a new constraint, "Update Customer Details", where the intention is to protect the Update action. In the constraint, add the web resource to be protected, i.e. CustomerDetails with the POST method, check the "Enable Authentication Constraint" and enter "Admin" in the Role Name(s) field



    With the above configuration, we are saying we want to protect the POST method for CustomerDetails and only authenticated users with the "Admin" roles can perform this
  4. Next, we create another constraint, "View Customer Details" where the intention is to protect the Customer Details view. Configure the constraint as shown below



    With the above configuration, we are trying to protect the POST method for CustomerList because this is how we navigate from CustomerList to CustomerDetails, and the GET method for CustomerDetails, which is simply to display the details. Also, only authenticated users with the "CustomerRep" and "Admin" roles can perform this
  5. In the same file, i.e. web.xml, go to the Pages section, change the default Welcome File and add the Error Page for code 403 to use AccessDenied.jsp as shown below



    The above configuration will make the server go to the new default page, i.e. CustomerList if no specific resource is specified, and the AccessDenied.jsp will be used for display whenever the server hits an error with code 403, which is Forbidden

    Lastly, we need to define the security role mappings so that authenticated users can belong to one or more of the JEE Security Roles defined
  6. Open up the file, sun-web.xml in the CustomerApp-war project and navigate to the Security section by clicking on the "Security" button near the top of the editor
  7. Under the Security Role Mappings section, you should already see 2 empty roles defined: Admin and CustomerRep, as a result of the creation of Security Roles in step 2. Under each of the Roles, add a group named Administrator for the Admin role, and CustomerService for the CustomerRep role as shown below



    Refer back to the section where we setup the LDAP server, OpenDS, we created 2 users: admin and custrep, and their respective groups: Administrator and CustomerService. So with the above configuration, the admin user will have the Admin role and custrep will have the CustomerRep role.

    At this point, we have completed all the tasks that needs to be done, let us next see the results of what we have done so far.

Testing the Application

We are now ready to test the outcome of securing the application.

  1. Go to the default page of the application, http://localhost:8080/CustomerApp-war/faces/CustomerList.jsp. This is not a protected page, so anybody can access it



    Notice the logged-in user is None and the Logout link is disabled
  2. Click on the Customer ID, 1 to view the details, but because the POST method of CustomerList is protected, the server redirects you to the Login page



    Login using the ID, custrep, the server authenticates with the LDAP server via the LDAP security realm created.
  3. Navigate to the CustomerDetails page again and this time, it goes through



    Notice the logged-in user now shows custrep, and the Logout link is enabled
  4. Attempt to modify the values of the fields and click the Update button and the resultant page is as shown below



    This happens because the POST method for CustomerDetails is protected and only users with role, Admin have access
  5. Go back and click on the Logout link



    You are now logged out (session invalidated).
  6. Login again but now using a different ID, admin

  7. Navigate to the CustomerDetails page again and attempt to modify some of the values and click on the Update button



    Notice this time, it goes through, the updated values are displayed

Summary

Congratulation, by now you should have a secured application that authenticates and authorizes users without having to program it. Using the same approach and methods, you can expand the application into a full-fledged enterprise application with little effort. If you cannot get your application to work like how it is supposed to be, not to worry, you can get a copy of the working solution from here.

This tutorial demonstrates the ease of securing a web application using JavaEE Security (Authentication and Authorization). By using this method, there is no need to write the modules to authenticate and authorize users which can be a complex piece in the application. There are also APIs available, http://java.sun.com/javaee/6/docs/api/, in case you need to implement something that is not out-of-the-box.

Good luck with your next JEE application!

--Christopherlam 06:29, 8 December 2009 (UTC)

See Also

For other related resources, see the followings:

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo