Wednesday, January 17, 2007

Securing Java EE 5 Web Applications

In this post I will give a brief overview of securing web applications in Java EE 5 with the help of a simple example. The example application consists of a Servlet (securityServlet) and two pages (index.jsp and secure/index.jsp). Two users (newemployee and newguest) with roles employee and guest, will be created, with the following permissions
  1. The "guest" user will have access to index.jsp
  2. The "employee" user will have access to secure/index.jsp.
  3. Both users have access to the servlet.
This example was developed on Eclipse and run on Glassfish application server. Follow these steps to implement the example

Create Users in Glassfish
  1. Go to Configuration->Security->Realms->file in the Glassfish admin console.
  2. In the file realm, click on manage users.
  3. Add new users by clicking on add there.
The Web Application
  1. The Web Deployment Descriptor: The following listing shows the complete deployment descriptor used for this example, followed by a quick explanation.
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5" 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">
    <display-name>Java5Security</display-name>

    <servlet>
    <description></description>
    <display-name>SecurityServlet</display-name>
    <servlet-name>SecurityServlet</servlet-name>
    <servlet-class>servlets.SecurityServlet</servlet-class>
    <security-role-ref>
    <role-name>emp</role-name>
    <role-link>employee</role-link>
    </security-role-ref>
    </servlet>
    <servlet-mapping>
    <servlet-name>SecurityServlet</servlet-name>
    <url-pattern>/securityServlet</url-pattern>
    </servlet-mapping>

    <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>file</realm-name>
    <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/error.jsp</form-error-page>
    </form-login-config>
    </login-config>

    <security-constraint>
    <web-resource-collection>
    <web-resource-name>Protected Area</web-resource-name>
    <url-pattern>/*</url-pattern>
    <http-method>PUT</http-method>
    <http-method>DELETE</http-method>
    <http-method>GET</http-method>
    <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
    <role-name>guest</role-name>
    <role-name>employee</role-name>
    </auth-constraint>
    </security-constraint>

    <security-constraint>
    <web-resource-collection>
    <web-resource-name>Protected Area</web-resource-name>
    <url-pattern>/secure/*</url-pattern>
    <http-method>PUT</http-method>
    <http-method>DELETE</http-method>
    <http-method>GET</http-method>
    <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
    <role-name>employee</role-name>
    </auth-constraint>
    </security-constraint>
    <!-- Security roles referenced by this web application -->
    <security-role>
    <role-name>guest</role-name>
    </security-role>
    <security-role>
    <role-name>employee</role-name>
    </security-role>

    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    </web-app>
    WEB-INF/web.xml
    • In the servlet declaration, the <security-role-ref> element maps the rolename used in the servlet to role declared in the deployment descritpor (this is needed only when the role declared in the deployment descriptor is different from the role used in the servlet (employee and emp)).
    • In the login-config, the <realm-name> element is used to declare the realm in which authentication takes place
    • Realms: A realm is a database of users and groups that identify valid users of a Web application and are controlled by the same authentication policy. Three realms, file, admin-realm, and certificate realms come preconfigured in Glassfish Application Server. For this example I use the file realm, where the user credentials are stored locally in a file.
  2. Mapping Roles to Users/Groups in Security Realm: In order to map the roles used in the application to the users defined in the security realm, you have to add the role mappings in the WEB-INF/sun-web.xml. The file is shown below.
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.1 Servlet 2.4//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_2_4-1.dtd">
    <sun-web-app>
    <context-root>/Java5Security</context-root>
    <security-role-mapping>
    <role-name>guest</role-name>
    <principal-name>newguest</principal-name>
    </security-role-mapping>
    <security-role-mapping>
    <role-name>employee</role-name>
    <principal-name>newemployee</principal-name>
    </security-role-mapping>
    </sun-web-app>
    WEB-INF/sun-web.xml
  3. The Servlet: The following is a listing of the servlet used for this example
    package servlets;

    import java.io.IOException;
    import java.io.PrintWriter;

    import javax.annotation.security.DeclareRoles;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    @DeclareRoles("emp")
    public class SecurityServlet extends javax.servlet.http.HttpServlet implements
    javax.servlet.Servlet {

    public SecurityServlet() {
    super();
    }

    protected void service(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    if (request.isUserInRole("emp"))

    out.println(request.getUserPrincipal() + " is an Authorized User");
    else
    out.println(request.getUserPrincipal() + " is not an Authorized to see this page.");
    }
    }
    SecurityServlet.java
    • The @DeclareRoles annotation is used to define the security roles in the application. This annotation is specified on a class, and it typically would be used to define roles that could be tested (i.e., by calling isUserInRole) from within the methods of the annotated class.
    • The isUserInRole() method is from J2EE.
  4. The login page: The following is the listing for the login.jsp page. There is nothing new here.
    <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core'%>
    <html>
    <head>
    <title>Login</title>
    </head>

    <body>
    <h1>Login</h1>

    <h2>Hello, please login:</h2>
    <br>
    <br>
    <form action="j_security_check" method=post>
    <table>
    <tr>
    <td>User:</td>
    <td><input type="text" name="j_username" size="25"></td>
    </tr>
    <tr>
    <td>Password:</td>
    <td><input type='password' name='j_password'></td>
    </tr>

    <tr>
    <td colspan='2'><input name="submit" type="submit"></td>
    </tr>
    <tr>
    <td colspan='2'><input name="reset" type="reset"></td>
    </tr>
    </table>

    </form>
    </body>
    </html>
    /login.jsp
  5. The index.jsp and error.jsp could be any JSP page
  6. This post did not describe how to logout. But that has been discussed earlier in the Form-based Authentication Logout post.

3 comments:

  1. how to provide different access facilities such as guest and employee to different jsp pages using tomcat server..

    my mail: ds_raghavendra@yahoo.com

    ReplyDelete
  2. In the security constraints tag, instead of * you will instead have individual JSPs and /secure/jsp1.jsp etc. and have different roles attached to them. But if you have too many such JSPs then it will be difficult to manage them through the deployment descriptor and you will be better off using a third party security manager like IBM's Tivoli Access Manager or SiteMinder.

    <security-constraint>
    <web-resource-collection>
    <web-resource-name>Protected Area</web-resource-name>
    <url-pattern>/secure/jsp1.jsp</url-pattern>
    <http-method>PUT</http-method>
    <http-method>DELETE</http-method>
    <http-method>GET</http-method>
    <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
    <role-name>employee</role-name>
    </auth-constraint>
    </security-constraint>

    ReplyDelete
  3. Hello Abhi,

    Thanks for this article, it really helped me out on solving an issue on a EJB 3 book sample.

    I have just one note regarding "sun-web.xml": instead of mapping roles to principals (i.e. usernames) I used mapping of roles to groups, as it is already configured on Glassfish realm file.

    ...
    <security-role-mapping>
    <role-name>customer</role-name>
    <group-name>bankcustomer</group-name>
    </security-role-mapping>
    <security-role-mapping>
    <role-name>employee</role-name>
    <group-name>bankemployee</group-name>
    </security-role-mapping>
    ...

    Best regards,

    Rodrigo

    ReplyDelete

Popular Posts