18 Developing Authorization

This chapter explains how to develop and configure custom authorization in applications in the following sections:

Prior to using this information, it is strongly recommended to be familiar with the context it is used. For details, see Section 14.3.3, "Programmatic Authorization."

18.1 Authorization Overview

This section compares and contrasts the authorization available in the JavaEE and the JAAS models.

18.1.1 The JavaEE Authorization Model

The JavaEE authorization model uses role membership to control access to EJB methods and web resources that are referenced by URLs; the JAAS authorization model uses permissions (instead of role memberships) to control access decisions.

In the JavaEE model, authorization is implemented in either of the following ways:

  • Declaratively, where authorization policies are specified in deployment descriptors; the container reads those policies from deployment descriptors and enforces them. No special application code is required to enforce authorization.

  • Programmatically, where authorization policies are specified in application code; the code checks whether a subject has the appropriate permission to execute specific sections of code. If the subject fails to have the proper permission, the code throws an exception.

Table 18-1 shows the advantages and disadvantages of each approach.

Table 18-1 Comparing Authorization in the Java EE Model

Authorization Type Advantages Disadvantages

Declarative

No coding needed; easy to update by modifying just deployment descriptors.

Authorization is coarse-grained and specified at the URL level or at the method level (for EJBs).

Programmatic

Specified in application code; can protect code at a finer levels of granularity.

Not so easy to update, since it involves code changes and recompilation.


18.1.2 The JAAS Authorization Model

Java 2 authorization is based on permissions, rather than roles, and access control decisions are evaluated by calls to the SecurityManager or the AccessController. When used in combination with the JAAS model, the model allows a programmatic authorization approaches, thus providing fine-grained control to resources.

In this model, an authorization policy specifies the following information:

  • Application and enterprise groups.

  • Members of a role, which can be other roles or users.

  • Permissions granted to users, groups, and code sources. For users and groups, they determine what a user or the member of a group is allowed to access. For code sources, they determine what actions the code is allowed to perform.

When programming with this model, sensitive lines of code are preceded with calls to check whether the current user is granted the appropriate permissions to access the code. If the user has the appropriate permissions, the code is run. Otherwise, the code throws and exception.

For details about Java 2 standard permissions, see http://java.sun.com/javase/6/docs/technotes/guides/security/permissions.html.

18.2 Authorization for EJBs and Servlets (JavaEE Model)

The JavaEE authorization model is based on roles and managed by the container; policies assign permissions to users and roles, and they are enforced by the container to protect resources.

A container can provide authorization to applications running in it in two ways: declaratively and programmatically. These topics and an example is found in the following sections:

18.2.1 Declarative Authorization

This authorization approach allows the control access to URL-based resources (such as servlets and pages) and methods in EJBs.

The basic steps to configure declarative authorization are the following:

  1. In standard deployment descriptors, specify the resource to protect, such as a web URL or an EJB method, and a logical role that has access to the resource.

    Alternatively, since JavaEE 1.5 supports annotations, use code annotations instead of deployment descriptors.

  2. In proprietary deployment descriptors (such as web.xml), map the logical role defined in step 1 to an enterprise group.

For details, see the chapter Using Security Services in Oracle Fusion Middleware Enterprise JavaBeans Developer's Guide for Oracle Containers for Java EE.

18.2.2 Programmatic Authorization

Programmatic authorization provides a finer grained authorization than the declarative approach, and it requires that the application code invoke the method isUserInRole (for servlets and JSPs) or the method isCallerInRole (for EJBs), both available from standard Java APIs.

Although these methods still depend on role membership to determine authorization, they give finer control over authorization decisions since the controlling access is not limited at the resource level (EJB method or URL).

18.2.3 JavaEE Code Example

This example illustrates a servlet calling the method isUserInRole. It is assumed that the EAR file packing the servlet includes the configuration files web.xml and weblogic-application.xml, and that these files include the following configuration fragments:

web.xml

 <!-- security roles -->
 <security-role>
   <role-name>sr_developer</role-name>
 </security-role>

weblogic-application.xml

The following snippet shows the mapping between the user weblogic and the security role sr_developer:

<wls:security-role-assignment>
  <wls:role-name>sr_developer</wls:role-name>
  <wls:principal-name>weblogic</wls:principal-name>
</wls:security-role-assignment>

Code Example Invoking isUserInRole

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

public class PolicyServlet extends HttpServlet {
 
 public PolicyServlet() {
        super();
    }

 public void init(ServletConfig config)
            throws ServletException {
        super.init(config);
    }

 public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        final ServletOutputStream out = response.getOutputStream();
 
        response.setContentType("text/html");
        out.println("<HTML><BODY bgcolor=\"#FFFFFF\">");
        out.println("Time stamp: " + new Date().toString());
        out.println( "<br>request.getRemoteUser = " + request.getRemoteUser() + "<br>");
        out.println("request.isUserInRole('sr_developer') = " + request.isUserInRole("sr_developer") + "<br>");
        out.println("request.getUserPrincipal = " + request.getUserPrincipal() + "<br>");
        out.println("</BODY>");
        out.println("</HTML>");
    }
}

18.3 Authorization Using Permissions (JAAS/OPSS Model)

JAAS/OPSS authorization is based on controlling the operations that a class can perform when it is loaded into a running environment.

This section is divided into the following sections:

18.3.1 Using the Method checkPermission

Oracle Fusion Middleware supports the use of the method checkPermission in the following standard classes:

  • java.lang.SecurityManager

  • java.security.AccessController

In addition, Oracle Fusion Middleware also supports the use of the method checkPermission in the following class:

  • oracle.security.jps.util.JpsAuth

Oracle recommends the use of checkPermission in the class JpsAuth (instead of the previous two) because it provides better debugging support, better performance, and audit support.

The static method AccessController.checkPermission uses the default access control context (the context inherited when the thread was created). To check permissions on some other context, call the instance method checkPermission on a particular AccessControlContext instance.Here is an example illustrating the use of this method:

//create permission
FilePermission perm = new FilePermission("/home/developer/foo.txt","read");
//check permission
AccessController.checkPermission(perm);

The method checkPermission behaves according to the value of the JAAS mode (see JAAS mode in Chapter 15, "Configuring the Servlet Filter and the EJB Interceptor"), as listed in the following table:

Table 18-2 Behavior of checkPermission According to JAAS Mode

JAAS Mode Setting checkPermission

off or undefined

Enforces code-based security based on the security policy in effect, and there is no provision for subject-based security.

doAs

Enforces a combination of code-based and subject-based security according to the new access control context created through the doAs block.

doAsPrivileged

Enforces a combination of code-based and subject-based security, but is uses a null access control context. This setting implies subject-based security only.

subjectOnly

Takes into consideration grants involving principals only (and it disregards those involving codebase) when evaluating a permission.


18.3.2 Debugging and Auditing Support

The class oracle.security.jps.util.JpsAuth provides for auditing support, so applications can audit permission check failures and successes.

In addition, the following system property settings:

-Djps.auth.debug.enable=true
-Djps.auth.debug.enable.verbose =true 

provide information on which principals or codesources failed a permission check, and details on those that passed is provided even when the container is not started with a security manager.

18.3.3 Using the Methods doAs and doAsPrivileged

Oracle Fusion Middleware supports the methods doAs and doAsPrivileged in the standard class javax.security.auth.Subject.

Oracle recommends, however, the use of these methods in the class oracle.security.jps.util.JpsSubject because they render better performance and provide auditing.

18.3.4 JAAS/OPSS Code Examples

This section presents code examples that illustrate permission checking and policy management.

18.3.4.1 Checking Permissions

The following example illustrates a servlet checking a permission. It is assumed that the EAR file packing the servlet includes the configuration files jazn-data.xml and web.xml.

jazn-data.xml

The application includes the following policies:

<policy-store>
 <applications>
  <application>
   <!-- application name or application context -->
    <name>PolicyServlet</name>
     <app-roles>
      <app-role>
       <name>developer</name>
       <display-name>application role developer</display-name>
       <class>oracle.security.jps.service.policystore.ApplicationRole</class>
       <members>
        <member>
        <class>weblogic.security.principal.WLSUserImpl</class>
        <name>weblogic</name>
       </member>
      </members>
     </app-role>
    </app-roles>
   <!-- application specific jaas policy -->
   <jazn-policy>
     <grant>
      <grantee>
       <principals>
        <principal>
         <class>oracle.security.jps.service.policystore.ApplicationRole</class>
         <name>developer</name>
        </principal>
       </principals>
      </grantee>
      <permissions>
       <permission>
        <class>java.lang.RuntimePermission</class>
        <name>getClassLoader</name>
       </permission>
     </permissions>
    </grant>
   </jazn-policy>
  </application>
 </applications>
</policy-store>

web.xml

The filter JpsFilter is configured as follows:

<web-app>
 <display-name>PolicyTest: PolicyServlet</display-name>
 <filter>
  <filter-name>JpsWlsFilter</filter-name>
  <filter-class>oracle.security.jps.ee.http.JpsFilter</filter-class>
   <init-param>
    <param-name>application.name</param-name>
    <param-value>PolicyServlet</param-value>
   </init-param>
  </filter>
  <filter-mapping>
   <filter-name>JpsWlsFilter</filter-name>
   <servlet-name>PolicyServlet</servlet-name>
   <dispatcher>REQUEST</dispatcher>
  </filter-mapping>...

Code Example

In the following example, Subject.doAsPrivileged may be replaced by JpsSubject.doAsPrivileged:

import javax.security.auth.Subject;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.*;
import java.util.Date;
import java.util.PropertyPermission;
import java.io.FilePermission;

public class PolicyServlet extends HttpServlet {
 
 public PolicyServlet() {
        super();
    }

 public void init(ServletConfig config)
            throws ServletException {
        super.init(config);
    }

 public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        final ServletOutputStream out = response.getOutputStream();
 
        response.setContentType("text/html");
        out.println("<HTML><BODY bgcolor=\"#FFFFFF\">");
        out.println("Time stamp: " + new Date().toString());
        out.println( "<br>request.getRemoteUser = " + request.getRemoteUser() + "<br>");
        out.println("request.isUserInRole('sr_developer') = " + request.isUserInRole("sr_developer") + "<br>");
        out.println("request.getUserPrincipal = " + request.getUserPrincipal() + "<br>");

 Subject s = null;
        s = Subject.getSubject(AccessController.getContext());
 
        out.println("Subject in servlet " + s);
        out.println("<br>");
        final RuntimePermission rtPerm = new RuntimePermission("getClassLoader");
 try {
 Subject.doAsPrivileged(s, new PrivilegedAction() {
                public Object run() {
                    try {
                        AccessController.checkPermission(rtPerm);
                        out.println("<br>");
                        out.println("CheckPermission passed for permission: " + rtPerm+ " seeded in application policy");
                        out.println("<br>");
                    } catch (IOException e) {
                        e.printStackTrace();
                        printException ("IOException", e, out);
                    } catch (AccessControlException ace) {
                        ace.printStackTrace();
                        printException ("Accesscontrol Exception", ace, out);
                    }
                    return null;
                }
            }, null);

} catch (Throwable e) {
            e.printStackTrace();
            printException("application policy check failed", e, out);
        }
        out.println("</BODY>");
        out.println("</HTML>");
    }

 void printException(String msg, Throwable e, ServletOutputStream out) {
        Throwable t;
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw, true);
            e.printStackTrace(pw);
 
            out.println("<p>" + msg + "<p>");
            out.println("<code>");
            out.println(sw.getBuffer().toString());

 t = e;
            /* Print the root cause */
            while ((t = t.getCause()) != null) {
                sw = new StringWriter();
                pw = new PrintWriter(sw, true);
                t.printStackTrace(pw);
 
                out.println("<hr>");
                out.println("<p>  Caused By ... </p>");
                out.println(sw.getBuffer().toString());
            }
            out.println("</code><p>");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

18.3.4.2 Managing Policies

The following code example illustrates the management of policies:

import oracle.security.jps.JpsContext;
import oracle.security.jps.JpsContextFactory;
import oracle.security.jps.service.policystore.ApplicationPolicy;
import oracle.security.jps.service.policystore.PolicyStore;
import oracle.security.jps.service.policystore.info.AppRoleEntry;
 
import javax.security.auth.AuthPermission;
import javax.security.auth.Subject;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.AccessController;
import java.security.Permission;
import java.security.Principal;
import java.util.Date;
import java.util.List;

public class PolicyServlet extends HttpServlet {
 
 public PolicyServlet() {
        super();
    }
 public void init(ServletConfig config)
            throws ServletException {
        super.init(config);
    }

public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        final ServletOutputStream out = response.getOutputStream();
 
        response.setContentType("text/html");
        out.println("<HTML><BODY bgcolor=\"#FFFFFF\">");
        out.println("Time stamp: " + new Date().toString());
        out.println( "<br>request.getRemoteUser = " + request.getRemoteUser() + "<br>");
        out.println("request.isUserInRole('sr_developer') = " + request.isUserInRole("sr_developer") + "<br>");
        out.println("request.getUserPrincipal = " + request.getUserPrincipal() + "<br>");

Subject s = null;
        s = Subject.getSubject(AccessController.getContext());
        out.println("Subject in servlet " + s);
        out.println("<br>");
        try {
            JpsContextFactory ctxFact = JpsContextFactory.getContextFactory();
            JpsContext ctx = ctxFact.getContext();
            final PolicyStore policyStore = ctx.getServiceInstance(PolicyStore.class);
            ApplicationPolicy policyServletPolicy
                    = policyStore.getApplicationPolicy("PolicyServlet");

 //get application role developer
            List<AppRoleEntry> developerAppRoleList = policyServletPolicy.searchAppRoles("developer");
            AppRoleEntry approleEntry = developerAppRoleList.get(0);
            Principal pr = approleEntry.getPrincipal();

//grant permissions to this role
            Principal[] principals = new Principal[]{pr};
            AuthPermission doAsPerm = new AuthPermission("authPerm");
            final Permission[] perms = new Permission[]{doAsPerm};
            out.println("<br> Attempting to grant principal " + pr + " Permissions in application Policy ");
            policyServletPolicy.grant(principals, null, perms);
            out.println("<br> Granted permissions");
            Subject subject = new Subject();
            subject.getPrincipals().add(pr);
            out.println("<br> principal has permissions ?" + policyServletPolicy.hasPermission(subject, doAsPerm));
        } catch(Exception e) {
            e.printStackTrace();
            printException("Exception in Policy Management " , e, out);
        }
 out.println("</BODY>");
        out.println("</HTML>");
    }

 void printException(String msg, Throwable e, ServletOutputStream out) {
        Throwable t;
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw, true);
            e.printStackTrace(pw);
 
            out.println("<p>" + msg + "<p>");
            out.println("<code>");
            out.println(sw.getBuffer().toString());
 
            t = e;
            /* Print the root cause */
            while ((t = t.getCause()) != null) {
                sw = new StringWriter();
                pw = new PrintWriter(sw, true);
                t.printStackTrace(pw);
 
                out.println("<hr>");
                out.println("<p>  Caused By ... </p>");
                out.println(sw.getBuffer().toString());
            }
 
            out.println("</code><p>");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}