Srikanth Technologies

Implementing Security using Web and EJB tiers in GlassFish V2

The following steps show how to implement authentication in Web tier and authorization in EJB tier using GlassFish V2.

Following are the major steps to be taken.

Creating Users and Groups

Follow the steps given below to create users in file realm of Glassfish.
  1. Go to Admin Console.
  2. Select Configuration -> Security-> Realms -> File . Because file realm is the default realm used in GlassFish.
  3. Click on Manage Users button on the right side pane.
  4. Click on New button to add one user at a time. For each user, provide the details as given in the following table.
Create the following users with these settings.

Username Password Group
jason jason users
steve steve users
ben ben admin
cathy cathy guest

This completes the task of creating users and placing them in groups in GlassFish.

Creating enterprise application

Create an enterprise application in NetBeans 6.1 as follows.

  1. Go to NetBeans 6.1
  2. Select File->New Project
  3. Select Enterprise under categories and Enterprise Application under Projects
  4. Enter security as project name
  5. Select GlassFish V2 as the server
  6. Click on finish
NetBeans creates two applications – security-ejb and security-war.

Implementing authentication in Web Tier

Now let us implement authentication – identifying users – in web tier using declarative security provided by Java EE. First we have to map groups of GlassFish to roles to be used in web application. This is done using sun-web.xml as follows.

sun-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Servlet 2.5//EN" "http://www.sun.com/software/appserver/dtds/sunweb-
app_2_5-0.dtd">
<sun-web-app error-url="">
 <context-root>/security-war</context-root>
 <security-role-mapping>
  <role-name>admin</role-name>
  <group-name>admin</group-name>
 </security-role-mapping>
 <security-role-mapping>
   <role-name>users</role-name>
   <group-name>users</group-name>
 </security-role-mapping>
 <security-role-mapping>
   <role-name>guest</role-name>
   <group-name>guest</group-name>
 </security-role-mapping>
 <class-loader delegate="true"/>
 <jsp-config>
   <property name="keepgenerated" value="true">
      <description>Keep a copy of the generated servlet class' java code.</description>
   </property>
 </jsp-config>
</sun-web-app>

Now, modify web.xml as follows to restrict access to all resources to only users of roles- admin, users and guest.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <session-config>
   <session-timeout>30</session-timeout>
 </session-config>
 <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 <security-constraint>
    <display-name>All pages</display-name>
    <web-resource-collection>
       <web-resource-name>Everything</web-resource-name>
       <description/>
       <url-pattern>/*</url-pattern>
       <http-method>GET</http-method>
   </web-resource-collection>
   <auth-constraint>
    <description/>
    <role-name>users</role-name>
    <role-name>admin</role-name>
    <role-name>guest</role-name>
   </auth-constraint>
 </security-constraint>
 <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Srikanth Technologies</realm-name>
 </login-config>
 <security-role>
   <description/>
   <role-name>users</role-name>
 </security-role>
 <security-role>
   <description/>
   <role-name>admin</role-name>
 </security-role>
 <security-role>
   <description/>
   <role-name>guest</role-name>
 </security-role>
</web-app>

The above configuration file specifies that all resources are restricted and access is allowed only to users of roles guest, users and admin.

Implementing authorization in EJB tier

Create Account EJB to perform the required operations. Use declarative security to specify which methods are allowed to which roles. Roles from Web tier are propagated to EJB tier. As it is to demonstrate security only, we do not write any code to perform the operations in EJB. Each method displays a message to console, which can be seen from GlassFish tab in NetBeans IDE.

AccountLocal.java

package security;
import javax.ejb.Local;
@Local
public interface AccountLocal {
  void deposit(int acno, double amount);
  void close(int acno);
  double getBalance(int acno);
}

AccountBean.java

package security;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
@Stateless
public class AccountBean implements AccountLocal {
  @RolesAllowed("users") // only members of users role can access
  public void deposit(int acno, double amount) {
    System.out.println("Deposit method called");
  }

  @RolesAllowed("admin") // only members of admin role can access
  public void close(int acno) {
    System.out.println("Closed account " + acno);
  }
  @PermitAll // anyone can access
  public double getBalance(int acno) {
     System.out.println("Getting balance for " + acno);
  return 1000;
 }
}

Creating Servlets to call EJB methods

The following are the servlets created in web application to call different methods of EJB. We use dependency injection to access EJB from Servlet.

index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Account Menu</title>
</head>
<body>
<h2>Account Menu</h2>
<a href="balance">Get Balance </a>
<p/>
<a href="deposit">Deposit Amount </a>
<p/>
<a href="close">Close An Account </a>
</body>
</html>

BalanceServlet.java

import java.io.*;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import security.AccountLocal;
public class BalanceServlet extends HttpServlet {
  @EJB
  private AccountLocal account;
  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
        out.println("<p/>Calling getBalance()...");
        double amount = account.getBalance(1);
        out.println("<p/>Called getBalance()");
    } finally {
        out.close();
    }
  }
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
     processRequest(request, response);
  }
  protected void doPost(HttpServletRequest request,HttpServletResponse response)
             throws ServletException, IOException {
      processRequest(request, response);
  }
}

CloseServlet.java

import java.io.*;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import security.AccountLocal;
public class CloseServlet extends HttpServlet {
  @EJB
  private AccountLocal account;
  protected void processRequest(HttpServletRequest request,  HttpServletResponse response)
     throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
      out.println("<p/>Calling close");
      account.close(1);
      out.println("<p/>Called close");
    } finally {
      out.close();
    }
 }
 protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
   processRequest(request, response);
 }

 protected void doPost(HttpServletRequest request,HttpServletResponse response)
   throws ServletException, IOException {
  processRequest(request, response);
 }
}
DepositServlet.java

import java.io.*;
import javax.ejb.EJB;
import javax.servlet.*;
import javax.servlet.http.*;
import security.AccountLocal;
public class DepositServlet extends HttpServlet {
  @EJB
  private AccountLocal account;
  protected void processRequest(HttpServletRequest request,HttpServletResponse response)
       throws ServletException, IOException {
     response.setContentType("text/html;charset=UTF-8");
     PrintWriter out = response.getWriter();
     try {
       out.println("<p/>Calling deposit");
       account.deposit(1,1000);
       out.println("<p/>Called deposit");
     } finally {
          out.close();
     }
  }

  protected void doGet(HttpServletRequest request,HttpServletResponse response)
        throws ServletException, IOException {
       processRequest(request, response);
  }

  protected void doPost(HttpServletRequest request,HttpServletResponse response)
           throws ServletException, IOException {
        processRequest(request, response);
  }
}
The complete web.xml with entries related to servlets and security confirmation is given below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <servlet>
   <servlet-name>DepositServlet</servlet-name>
   <servlet-class>DepositServlet</servlet-class>
 </servlet>
 <servlet>
   <servlet-name>CloseServlet</servlet-name>
   <servlet-class>CloseServlet</servlet-class>
 </servlet>
 <servlet>
   <servlet-name>BalanceServlet</servlet-name>
   <servlet-class>BalanceServlet</servlet-class>
 </servlet>
 <servlet-mapping>
   <servlet-name>DepositServlet</servlet-name>
   <url-pattern>/deposit</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
  <servlet-name>CloseServlet</servlet-name>
  <url-pattern>/close</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
  <servlet-name>BalanceServlet</servlet-name>
  <url-pattern>/balance</url-pattern>
 </servlet-mapping>
 <session-config>
    <session-timeout>30</session-timeout>
 </session-config>
 <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 <security-constraint>
    <display-name>All pages</display-name>
    <web-resource-collection>
    <web-resource-name>Everything</web-resource-name>
     <description/>
     <url-pattern>/*</url-pattern>
     <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint>
     <description/>
     <role-name>users</role-name>
     <role-name>admin</role-name>
     <role-name>guest</role-name>
    </auth-constraint>
 </security-constraint>
 <login-config>
   <auth-method>BASIC</auth-method>
   <realm-name>file</realm-name>
 </login-config>
 <security-role>
   <description/>
   <role-name>users</role-name>
 </security-role>
 <security-role>
   <description/>
   <role-name>admin</role-name>
 </security-role>
 <security-role>
   <description/>
   <role-name>guest</role-name>
   </security-role>
 </web-app>

Testing Security

Deploy the entire application by using Undeploy and Deploy option from context menu of the project. Once project is successfully deployed, take the following steps to test security.
  1. Invoke browser and enter user http://localhost:8080/security-war/index.jsp.
  2. This will prompt you to enter username and password.
  3. Enter username – jason and password - jason.
  4. As user jason, you belong to users group, which is mapped to users role in your application. So you can invoke deposit() and getBalance() methods.
  5. Click on links for Get Balanace and Deposit Amount. You must be successful.
  6. However, if you click on Close Account link, you must see javax.ejb.AccessLocalException: Client not authorized for this invocation in GlassFish console as members of users role are not allowed to call close() method.
  7. Close browser and enter http://localhost:8080/security-war/index.jsp again.
  8. Login as ben with password ben.
  9. As ben you belong to admin group, which is mapped to admin role. So you can call close() and getBalance() methods, but NOT deposit() method.
  10. Close browser and enter http://localhost:8080/security-war/index.jsp again.
  11. Login as cathy with password cathy.
  12. As cathy you belong to guest group, which is mapped to guest role. So the only method that you can is getBalance(), which is allowed to all.
  13. If you try to call any other method (like deposit() or close()), you will see an error displayed in GlassFish console window.