Struts, JAAS, Tomcat: getting acquainted (part 2) html

Struts, JAAS, Tomcat: getting acquainted (part 2)

In Struts, JAAS, Tomcat: getting acquainted (part 1) it was discussed how to employ JAAS authentication for custom and/or legacy realms under Tomcat. As authorization was left unaddressed, we herewith fullfil our promise to treat it later.

JAAS authorization

As Dan Moore already mentions in his own article titled “Using JAAS for Authorization and Authentication“, extending the Struts ActionServlet for enforcing security policies is far from ideal: only actions can be protected, you may become Struts-release dependent and even worse, the Struts ActionServlet may disappear in future releases alltogether.

That’s why we have choosen to use a servlet filter to implement JAAS-based authorization. The recipe is actually quite straightforward and can be summarized as follows:

  • Create a URL permission class (when dealing with web applications)
  • Create (i.e. configure + implement) an authorization filter
  • Create a policy file and make its location known to the JVM

The URL permission class

When dealing with web applications, we need to be able to grant or deny permissions, given a URL and subject (more precisely, a role that is retrieved via the Subject object) . This is explained in Section 3.1 of Dan Moore’s article, but basically boils down to the fact that their is no standard provision for URL-based resources.

For the time being, we took over the code of the URLPermission class (including the associated URLPermissionFactory) from the included example unaltered, although it should preferarably be generalized as is suggested by the author.

The authorization filter

We have implemented an AuthorizationFilter class. Note that when the subject has authenticated, his/her Subject should be present in the HTTP session, as was shown in part 1. The code is inspired on the example code from Dan Moore’s article (where he overwrites the process() method of the ActionServlet):

public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain)
    throws IOException, ServletException
{
    HttpServletRequest request = (HttpServletRequest) req;
    HttpSession session = request.getSession();
    Subject subject = (Subject)
        session.getAttribute(Auth.SUBJECT_SESSION_KEY);

    String loginPage = request.getContextPath()+"/logon.do";
    String pageReq = request.getRequestURI();
    Permission permission =
        PermissionFactory.getInstance().getPermission(pageReq);

    if (subject == null &&
        (! request.getRequestURI().equals(loginPage)))
    {
        // subject cannot be found and person wants
        // to go to a page that is not the login page
        log.error("Unknown subject -> go to login page!");
        request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request, response);
    }
    else if (subject == null &&
         request.getRequestURI().equals(loginPage))
    {
        // subject cannot be found and person wants
        // to go to login page -> go ahead
        chain.doFilter(request, response);
    }
    else
    {
       if ( ! AuthorizationUtils.permitted(subject, permission) )
       {
           // subject is not permitted; redirect to error page
           log.error("Subject not permitted -> go to error page");
          request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request, response);
       }
       else
       {
           log.debug("Subject has permission -> continue...");
           chain.doFilter(request, response);
       }
    }
}

The code should speak for itself, only if the subject has authenticated successfully and according to the configured policy he/she has a role that permits the subject to visit this URL, the filter chain continues the normal request/response cycle, otherwise the user is either redirected to the login page (in case he/she did not authenticate yet) or an error page. Note that this error page should preferrably have been an authorization specific error page.

The actual authorization is done with the AuthorizationUtils class, which could again be incorporated from the example code unaltered.

In the web.xml deployment descriptor, we can decide when to invoke this authorization filter, e.g. only for *.do-based URLs, only for *.jsp-based files, for both, etc.

Example:

<filter>
    <filter-name>AuthorizationFilter</filter-name>
    <filter-class>nl.amis.hours.lifecycle.AuthorizationFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>AuthorizationFilter</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>
</pre>

Configuring a policy

This is basically a (short) two-step process: make your policy configuration file known to the JVM and formulate the policy for your web application. We tell the JVM to locate our policy file by adding the following entry to the $JAVA_HOME/jre/lib/security/java.security file:
auth.policy.provider=com.sun.security.auth.PolicyFile
auth.policy.url.1=file:${java.home}/lib/security/AmisHours.policy

Note that this may be configured on the command line as well.

Finally, we set up a draft AmisHours.policy policy file:

grant  Principal nl.amis.hours.auth.AmisHoursPrincipal "ONTWIKKELAAR"
{
   permission nl.amis.hours.auth.URLPermission "/AmisHours/sheet.do";
};

grant Principal * *
{
   permission nl.amis.hours.auth.URLPermission "/AmisHours/logoff.do";
   permission nl.amis.hours.auth.URLPermission "/AmisHours/logon.do";
};

Subjects who are in the role of "ONTWIKKELAAR" (Dutch for developer) can now view their time sheets, whereas e.g. project managers cannot. This doesn't make any sense, of course, but was merely meant to test if the policy file had the intended effect, which in fact it did 🙂

Concluding remarks/thoughts

After having coded the authentication with JAAS, I got some doubts on the benefits of using JAAS over e.g. coding the authentication logic completely yourself, including the communication with the legacy realm (private communication).

But now that authorization is in place, I'm very charmed by the fact that we can now change the policy without having to change anything in the code nor in the deployment descriptor.

Considering the fact that many application servers offer JAAS-based authentication & authorization capabilities by efault (JBoss) and given the fact that JAAS is the standard API for Java security, I am much more confident that JAAS can be a sound choice when providing security for both Java stand-alone and web-based applications.

25 Comments

  1. Narasimha November 16, 2006
  2. diabolo512 July 21, 2005
  3. john March 31, 2005
  4. Zeger Hendrikse March 24, 2005
  5. john March 24, 2005
  6. Thijs March 17, 2005
  7. john March 14, 2005
  8. Thijs March 9, 2005
  9. john March 7, 2005
  10. Thijs March 7, 2005
  11. john March 4, 2005
  12. Mike Luff February 21, 2005
  13. Karthic Keyan February 10, 2005
  14. mei January 7, 2005
  15. Zeger Hendrikse December 6, 2004
  16. Zeger Hendrikse December 3, 2004
  17. mei December 1, 2004
  18. Zeger Hendrikse December 1, 2004
  19. mei December 1, 2004
  20. charles gay (jGuard team) November 30, 2004
  21. Zeger Hendrikse November 23, 2004
  22. Zeger Hendrikse November 23, 2004
  23. Zeger Hendrikse November 23, 2004
  24. markus November 22, 2004
  25. Leon van Tegelen November 19, 2004