[ Team LiB ] Previous Section Next Section

Checking Security Roles Programmatically

Role-based authentication is nice when you can partition pages based on a role, but you can rarely make this kind of authentication seamless. Suppose you want to set up pages that can be run only by someone in a manager role. Obviously you can group the pages into a separate Web resource collection and specify a role name of manager in the <auth-config> tag for the collection. The problem is, where do you put the links to the manager-only pages?

If you put them on a page that everyone can access, the non-manager users might click the link and see an error page. Although this mechanism does secure your application, it doesn't make it pretty.

Error Pages Should Be for Errors

graphics/bytheway_icon.gif

If you want your site to look professional, a user should never see an error page as part of the normal operation of the site.


Rather than presenting the user with an ugly error page, you can check the user's role programmatically by calling the isUserInRole method in the request object.

For example, in a JavaServer Page that links to pages for managers, you might have the following code:


<% if (request.isUserInRole("manager")) { %>
<a href="managers/mgrreport.jsp">Manager Report</a>
<a href="managers/personnel.jsp">Personnel Records</a>
<% } %>

By checking the user's role in a JSP or servlet, you can customize the Web page to show the user only the items she can access.

If you need the user's name as it was entered in the authentication form, you can call getRemoteUser in the request object.

Listing 23.6 shows the source for a custom tag that lets you specify a required role for all the text contained in the tag body. The beauty of the custom tag is that it is more compact and more readable than using Java code embedded inside <% %> tags.

Listing 23.6 Source Code for RequireRoleTag.java
package examples.taglibs;

Import java.io.*;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import javax.servlet.http.*;
import java.util.*;

public class RequireRoleTag extends SimpleTagSupport
{
    protected String role = null;

    public int doTag()
        throws JspException , IOException

    {
        PageContext context = (PageContext)getJspContext();
        HttpServletRequest request =
            (HttpServletRequest) context.getRequest();

        if ((role != null) && request.isUserInRole(role))
        {
            getJspBody().invoke(null);
        }
    }

    public String getRole() { return role; }
    public void setRole(String aRole) { role = aRole; }
}

Listing 23.7 shows a JavaServer Page that tests the custom tag in Listing 23.6.

Listing 23.7 Source Code for CheckRole.jsp
<%@ taglib uri="/rolecheck" prefix="rc" %>
<html>
<body>

<h1>Welcome</h1>

Here are the things you can do:<br>
<a href="complain.jsp">Complain</a><br>
<a href="checkstocks.jsp">Check Your Stocks</a><br>
<a href="clock.jsp">Look At The Clock</a><br>
<rc:require-role role="manager">
    <a href="fire.jsp">Fire Someone At Random</a><br>
    <a href="meeting.jsp">Call A 10-Hour Meeting</a><br>
</rc:require-role>
</body>
</html>

Listing 23.8 shows the rolecheck.tld file used to define the custom tag library.

Listing 23.8 Source Code for rolecheck.tld
<?xml version="1.0" encoding="ISO-8859-1"?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation=
              "http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
      version="2.0">

    <tlibversion>1.0</tlibversion>
    <shortname>rolecheck</shortname>
    <info>
        A tag to require a specific authentication role for its body
    </info>

    <tag>
        <name>require-role</name>
        <tagclass>examples.taglibs.RequireRoleTag</tagclass>
        <body-content>scriptless</body-content>
        <attribute>
            <name>role</name>
            <required>yes</required>
        </attribute>
    </tag>
</taglib>

Listing 23.9 shows the web.xml file that describes the application.

Listing 23.9 web.xml File for rolecheck Application
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
    <display-name>roletest</display-name>
    <description>A test of authentication</description>
    <taglib>
        <taglib-uri>/rolecheck</taglib-uri>
        <taglib-location>/WEB-INF/tld/rolecheck.tld</taglib-location>
    </taglib>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>RoleTest</web-resource-name>
            <url-pattern>/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <user-data-constraint>
            <description>SSL not required</description>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
        <auth-constraint>
            <description>Let managers and users use this app</description>
            <role-name>manager</role-name>
            <role-name>user</role-name>
        </auth-constraint>
    </security-constraint>
    <security-role>
        <description>The role of manager is one that can use our application.
        </description>
        <role-name>manager</role-name>
    </security-role>
    <security-role>
        <description>A regular user can also use (parts of) our application.
        </description>
        <role-name>user</role-name>
    </security-role>
    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>
</web-app>

Package Your Applications!

graphics/watchout_icon.gif

This example can be used to point out some container behavior that almost always causes a few hour of frustration. In Listing 23.5, you'll note that the tag handler implementation is packaged in examples.taglibs. If you didn't bother to package it, you'd have a rather cryptic message when your application ran; the container would complain about not being able to locate RequireRoleTag when it was translating the JSP that uses it. This occurs because most containers package the JSP and assume that any unpackaged classes belong to the same package as the JSP—which is rarely the case.

Consequently, the container can't find the class and can't compile the JSP, even though you've made sure that the class is in a place that the container will find at runtime. To avoid this behavior, always package your classes.


    [ Team LiB ] Previous Section Next Section