Using Annotations in Web Applications

By Shing Wai Chan

Java EE 5 introduced annotations, a way to simplify the development and configuration of enterprise applications. The March 31, 2007 Tech Tip Using Security Annotations in Enterprise Beans showed how you can use annotations to simplify the development of secure applications that use enterprise beans. Some of the annotations in Java EE 5 are specific to web applications. Examples of this type of annotation are @Resource, @EJB, and @WebServiceRef. Other annotations, such as @RunAs and @DeclareRoles, are related to security. The security-related annotations were introduced in the Using Security Annotations in Enterprise Beans tip.

Although you can specify annotations in various web application components, you can't specify an annotation in a JavaServer Pages (JSP) technology page. However, annotations are supported in web libraries. This means that you can specify annotations in tag libraries and servlet filters, among other places. This gives you a way of securing JSP pages and servlets, provided that you take one additional action: you need to specify appropriate security information in the web.xml file for the web application.

This tip shows you how to construct a secure web application that includes servlets and JSP pages. By configuring the web.xml file for the web application, you can protect the servlets and JSP pages over a Secure Sockets Layer connection. This is a common security approach in a web production environment.

A sample web application package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package).

The Servlet

Let's begin by examining the servlet for the web application. In this example, the servlet invokes an enterprise bean (in this case, a stateless session bean) with a local interface SlessLocal. The servlet passes a message object as a request attribute and then forwards it to a JSP page, display.jsp, for display. Here is the major part of the code for the servlet:


   @DeclareRoles({"arole"})
   @RunAs("myrole")
   public class TestServlet extends HttpServlet {
       private @EJB SlessLocal slessLocal;
       
       public void service(
           HttpServletRequest req, HttpServletResponse resp)
               throws ServletException, IOException {
           if (req.isUserInRole("arole")) {
               String message = slessLocal.hello("World");
               req.setAttribute("EJB_MESSAGE", message);
           }
   
           RequestDispatcher rd = 
               req.getRequestDispatcher("display.jsp");
           rd.forward(req, resp);
       }
   }

The @EJB annotation is used to look up an enterprise bean with the corresponding interface so that the bean can be used by the servlet. The @DeclareRoles annotation defines the role to be used by HttpServletRequest.isUserInRole(String role). The isUserInRole method determines whether the authenticated user is included in the specified role. In this case, only a user in the role "arole" will cause the servlet to retrieve the "message" String and set it as an HttpServletRequest attribute.

The @RunAs annotation specifies that the role "myrole" should be used to access the enterprise bean method SlessLocal.hello(String message).

The Enterprise Bean

Here is the major part of the code for the stateless session bean:

   @Stateless
   @Local({SlessLocal.class})
   public class SlessBean implements SlessLocal {
       @RolesAllowed(value={"myrole"})
       public String hello(String message) {
           return "Hello, " + message + ", " + new Date();
       }
   }

Notice that the hello method is protected through the use of the @RolesAllowed annotation. The annotation specifies that only authenticated users in the role "myrole" can access the hello method.

The JSP and Tag Library

The JSP page, display.jsp, invokes an action in a JSP tag library and passes the attribute EJB_MESSAGE as a parameter in the HttpServletRequest. Here is a snippet of code from the JSP page:

   <%@taglib prefix="di" 
       uri="http://java.sun.com/techtip/webann/test-taglib"%>
   ...
     <di:displayInfo ejbMessage="${requestScope.EJB_MESSAGE}"/>
   ...

The tag handler for the tag reads the value of the ejbMessage parameter and displays it in HTML. It also prints the login timeout for the DataSource. Here is the pertinent code in the tag handler:

   public class DisplayInfoTagHandler extends SimpleTagSupport {
   
      private @Resource(name="jdbc/__default") DataSource ds;
      ...
  
      public void doTag() throws JspException, IOException {
         try {
             JspWriter out = getJspContext().getOut();
             int timeout = ds.getLoginTimeout();
             if (ejbMessage != null && ejbMessage.length() > 0)
             {
                 out.println(
                     "<li> Ejb Message: " + ejbMessage);
             }
             out.println(
                 "<li> DataSource login timeout: " + timeout);
         ...
      }
      public void setEjbMessage(String ejbMessage) {
         this.ejbMessage = ejbMessage;
      }
   }

The @Resource annotation in the tag handler is used to look up the DataSource with the JNDI name, "jdbc/__default". This JNDI name corresponds to the default Derby database. If you want to access the database connection, you could add ds.getConnection() to the code in the tag handler.

Notice too that the tag handler defines a setter method for the parameter ejbMessage.

Securing the Servlet and JSP page

This example takes the approach of protecting the war file for the application by requiring a username and password and by using SSL in the transport layer. The username and password is sent in clear text over the wire. There is no need to modify any Java code or JSP page in the application. To secure the servlet and JSP page in the application all you need to do is configure the web.xml file as follows:

  1. Define a security constraint by specifying a <security-constraint> element. This protects a corresponding URL so that a given role can access it. Note that you can define one or more HTTP methods that the security constraint applies to by specifying <http-method> elements in the security constraint. If you want the security constraint element to apply to all HTTP methods, you simply omit the <http-method> elements.

  2. Indicate that SSL will be used for communication. You do this in the security constraint by specifying a <user-data-constraint> element and within it a <transport-guarantee> element. Set the value of the <transport-guarantee> element to CONFIDENTIAL.

  3. Set the authentication method. You do this by specifying an <login-config> element and within it an <auth-method> element. Set the value of the <auth-method> to BASIC.

Here is a snippet of the web.xml file:

   <security-constraint>
      < web-resource-collection>
         <web-resource-name>Servlet Application
         </web-resource-name>
         <url-pattern>/\*</url-pattern>
      </web-resource-collection>
      <auth-constraint>
         <role-name>ttrole</role-name>
      </auth-constraint>
      <user-data-constraint>
         <transport-guarantee>CONFIDENTIAL
         </transport-guarantee>
      </user-data-constraint>
   </security-constraint>
   <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>default</realm-name>
   </login-config>
   
   <security-role>
      <role-name>ttrole</role-name>
   </security-role>

In this example, only users of role "ttrole" can access the servlet and JSP page. Furthermore, only users who are also of role "arole" will cause the SlessLocal bean to be called.

The Java EE environment uses roles for authorization. However in many operating system environments, users are associated with groups. The security-role-mapping provides a link between the concepts of user roles and principals/groups. In a Java EE 5 application server implementation such as the Sun Java System Application Server in the Java EE 5 SDK, you define the security-role-mapping in the sun-application.xml file. Here is an example:

   <sun-application>
     <security-role-mapping>
       <role-name>myrole</role-name>
       <principal-name>myuser</principal-name>
     </security-role-mapping>
     <security-role-mapping>
       <role-name>ttrole</role-name>
       <group-name>ttgroup</group-name>
     </security-role-mapping> 
     <security-role-mapping>
       <role-name>arole</role-name>
       <principal-name>ttuser</principal-name>
     </security-role-mapping>
   </sun-application>

Running the Sample Code

  1. If you haven't already done so, download and install the NetBeans IDE. NetBeans IDE 5.5 with the NetBeans Enterprise Pack 5.5 is available in Java EE 5 SDK Update 2, which you can download from the Java EE Downloads Page.

  2. Download the sample package for the tip and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/webann, where <sample_install_dir> is the directory where you installed the sample package. For example, if you extracted the contents to C:\\ on a Windows machine, then your newly created directory should be at C:\\webann

  3. Start the NetBeans IDE.

  4. Open the webann project. If you see a "Resolve missing server problem" message, then the application server has not added to the server list in NetBeans. Select Tools > Server Manager to add the server to the server list.

  5. Start the Sun Java System Application Server in NetBeans. You can also start the application server by entering the following command on the command line:
      <appserv_install_dir>/bin/asadmin start-domain domain1

    where <appserv_install_dir> is the directory in which you installed the Sun Java System Application Server.

  6. Create a user. You can do this in the Admin Console (default: http://localhost:4848 ) as follows:
    • Navigate the left panel of the Admin Console:

      Configuration > Security > Realms > file,

    • Click "Manage Users" and then click "New".
    • Enter the following information:
      User Id: ttuser
      Group List: ttgroup
      New Password: ttpassword
      Confirm New Password: ttpassword
    • Click "OK".

    After creating the user, create a second user in the same group by entering the following:

    User Id: ttuser2
    Group List: ttgroup
    New Password: ttpassword
    Confirm New Password: ttpassword
  7. Build the project as follows:
    • Right click the webann node in the Projects window.
    • Select "Clean and Build Project".

    This builds an ear file, web.ear, and puts it in the webann/dist directory.

  8. Deploy the ear file as follows:

    • Right click the webann node in the Projects window.
    • Select "Deploy Project".

    You can also deploy the ear file through the Admin Console as follows:

    • Navigate the left panel of the Admin Console:

           Applications > Enterprise Applications

    • Click "Deploy".
    • Click the "Browse" button to find the ear file.
    • Click OK.

    You can also deploy the ear file by entering the followingcommand on the command line:

       asadmin deploy webann.ear

  9. Start the application by pointing your browser to https://<host>:<port>/webann, where <host> is the host name of your application server, for instance "localhost", and <port> is your HTTPS port, for instance, 8181.

    Depending on your browser, you might see a message stating that there is a problem with the web site's security certificate or web site certified by an unknown authority. That's because this example uses a self-sign certificate. The browser should offer you the option of continuing to the web site to start the application.

    The application will then prompt you to login. Recall that you created two users: ttuser and ttuser2. If you login as ttuser, you should see a response from the application that looks similar to the following:

    Hello, ttuser
    Ejb Message: Hello, World, Sat Jun 30 12:04:46 PDT 2007
    DataSource login timeout: 0

    If you login as ttuser2, then you should see a response similar to the following:

    Hello, ttuser2
    DataSource login timeout: 0

    The difference in the response is due to the roles for each user. The user ttuser has roles "ttrole" and "arole". The user ttuser2 has the role "ttrole", but not the role "arole". In this application, only users that have the role "arole" are authorized to invoke the method SlessLocal.hello(String message), the method that creates the "Hello, World" message.

When you finish the application, you can undeploy it and remove the users you created as follows:

  1. Undeploy the ear through the Admin Console as follows:

    • Navigate the left panel of the Admin Console:

           Applications > Enterprise Applications

    • Choose "webann" and then click "Undeploy".

  2. Remove the user through the Admin Console as follows:

    • Navigate the left panel of the Admin Console:

           Configuration > Security > Realms > file

    • Click "Manage Users".
    • Choose "ttuser" and "ttuser2".
    • Click "Delete".

About the Author

Shing Wai Chan is a member of the Java EE development team at Sun Microsystems. He has been a key contributor in Java EE security for the past few years.

Comments:

Post a Comment:
Comments are closed for this entry.
About

edort

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today