17 The Security Model

This chapter describes the OPSS authorization and policy models, and compares them with the Java EE and Java Authorization and Authentication Services (JAAS) authorization models.

This chapter includes the following sections:

About the OPSS Authorization and Policy Models

For information about the OPSS authorization and policy models, see Administering Oracle Entitlements Server.

Authorization Models

A policy specifies the permissions granted to code loaded from a given location. The JAAS model extends policies by allowing an optional list of principals. These policies grant permissions to code from a specified location that is run by any of those principals.

The OPSS model is based on the JAAS model and, moreover, allows application policies and roles, and system policies. Application roles can be mapped to enterprise users and groups (such as administrative roles). A policy can grant permissions to any of these roles, groups, or principals.

A Java EE application can delegate authorization to the container where it runs, or it can implement its own authorization with calls to methods such as checkPermission, checkBulkAuthorization, or getGrantedResources.

The following sections describe the main points of the Java EE and JAAS authorization models:

The Java EE Authorization Model

The Java EE authorization model uses role membership to control access to Enterprise JavaBeans (EJB) and web resources that are referenced by URLs. Policies assign permissions to users and roles, and they are enforced by the container.

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

  • Declaratively, where 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 policies are processed 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, then the code throws an exception.

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

Table 17-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 specified at the URL level or at the EJB method level.

Programmatic

Specified in application code. Provides fine-grained authorization.

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

A container can provide authorization to applications running in it in two ways: declaratively and programmatically, as explained in the following sections:

Declarative Authorization

Declarative authorization allows you to control access to URL-based resources (such as Java servlets and pages) and EJB methods.

To configure declarative authorization:

  1. Specify (in standard deployment descriptors) the resource to protect and a role that has access to that resource. Alternatively, use code annotations.

  2. Map the role to an enterprise group (in proprietary deployment descriptors, such as the web.xml file).

Programmatic Authorization

Programmatic authorization provides a fine-grained authorization not available in declarative approach, and it requires that the application code call the isUserInRole method (for Java servlets) or the isCallerInRole method (for EJB), both available from standard Java APIs.

Although these methods still depend on role membership to determine authorization, they give finer control over authorization decisions because the controlling access is not limited to EJB or URL.

Java EE Application Example

The following example illustrates an application calling the isUserInRole method. The example assumes that the application Enterprise ARchive (EAR) file includes the web.xml and weblogic-application.xml files, and that these files include the following specifications:

<!-- security roles in web.xml -->
 <security-role>
   <role-name>sr_developer</role-name>
 </security-role>
<!-- maaping of user to role in weblogic.application.xml -->
<wls:security-role-assignment>
  <wls:role-name>sr_developer</wls:role-name>
  <wls:principal-name>weblogic</wls:principal-name>
</wls:security-role-assignment>

Code Calling 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>");
    }
}

The JAAS Authorization Model

The JAAS authorization model introduces permissions but also uses roles. In this model, a policy binds permissions with a subject (role, group, or user) and, optionally, with code. You grant permission to a role by calling the addPrincipalsToAppRole method. Permissions are evaluated by calls to the static AccessController.checkPermission method. The model allows a high control of resources.

In a policy you specify the following data:

  • Application roles and enterprise groups allowed the permission(s).

  • Permissions (in application policies) and codesources (in system policies). Application polices define what a user or the member of a group is allowed to access. System policies define what actions the code is allowed to perform.

When you program with this model, you precede sensitive parts of the your application with checks that determine whether the current user or role has the appropriate permissions to the code, and the code is run if the user has the right permissions. For an example, see Using Supported Permission Classes.

The JAAS/OPSS Authorization Model

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

The following sections explain the OPSS authorization model:

The Resource Catalog

OPSS supports the specification and runtime support of the resource catalog in security stores.

The resource catalog allows you to:

  • Describe policies and secured artifacts in human-readable terms.

  • Define and modify policies independently of the application source code.

  • Browse and search policies, roles, and the role hierarchy.

  • Group permissions in entitlements.

Managing Policies

Manage the resource catalog with the following interfaces, all sub-interfaces of oracle.security.jps.service.policystore.EntityManager:

  • GrantManager - Use this interface to query grants using search criteria, to obtain list of grants that satisfy various combinations of resource catalog artifacts, and to grant or revoke permissions to principals.

  • PermissionSetManager - Use this interface to create, modify, and query permission entitlements.

  • ResourceManager - Use this interface to create, delete, and modify resource instances.

  • ResourceTypeManager - Use this interface to create, delete, modify, and query resource types.

To create a resource type, a resource instance, actions, or a permission set, use code like the following:

import oracle.security.jps.service.policystore.entitymanager.*;
import oracle.security.jps.service.policystore.search.*;
import oracle.security.jps.service.policystore.info.resource.*;
import oracle.security.jps.service.policystore.info.*;
import oracle.security.jps.service.policystore.*;
import java.util.*;
 
public class example {
  public static void main(String[] args) throws Exception {
     ApplicationPolicy ap;

     ResourceTypeManager rtm = ap.getEntityManager(ResourceTypeManager.class);
     ResourceTypeSearchQuery query = new ResourceTypeSearchQuery();
     query.setANDMatch();
     query.addQuery(ResourceTypeSearchQuery.SEARCH_PROPERTY.NAME, false,      ComparatorType.EQUALITY, "resourceType", BaseSearchQuery.MATCHER.EXACT);
     List<ResourceTypeEntry> allResourceTypes = rtm.getResourceTypes(query);

     ResourceManager rm = ap.getEntityManager(ResourceManager.class);
     ResourceSearchQuery ResourceQuery = new ResourceSearchQuery();
     ResourceQuery.setANDMatch();
     ResourceQuery.addQuery(ResourceSearchQuery.SEARCH_PROPERTY.NAME, false,      ComparatorType.EQUALITY, "R2", BaseSearchQuery.MATCHER.EXACT);
     List<ResourceEntry> allResources = rm.getResources("RT2", ResourceQuery);

     PermissionSetManager psm = ap.getEntityManager(PermissionSetManager.class);
     PermissionSetSearchQuery pssq = new PermissionSetSearchQuery();
     pssq.setANDMatch();
     pssq.addQuery(PermissionSetSearchQuery.SEARCH_PROPERTY.NAME, false,      ComparatorType.EQUALITY, "PS1", BaseSearchQuery.MATCHER.EXACT);
     List<PermissionSetEntry> allPermSets = psm.getPermissionSets(pssq);

     RoleCategoryManager rcm = ap.getEntityManager(RoleCategoryManager.class);
     RoleCategorySearchQuery rcsq = new RoleCategorySearchQuery();
     rcsq.setANDMatch();
     rcsq.addQuery(RoleCategorySearchQuery.SEARCH_PROPERTY.NAME, false,      ComparatorType.EQUALITY, "roleCategoryCartoon",      BaseSearchQuery.MATCHER.EXACT);

     List<RoleCategoryEntry> allRoleCategories = rcm.getRoleCategories(rcsq);
  }
}

The following example illustrates a complex query involving resource catalog elements:

//ApplicationPolicy ap as in the preceeding example
ResourceTypeManager rtm = ap.getEntityManager(ResourceTypeManager.class);
ResourceTypeSearchQuery query = new ResourceTypeSearchQuery();
query.setANDMatch();
query.addQuery(ResourceTypeSearchQuery.SEARCH_PROPERTY.NAME, false, ComparatorType.EQUALITY, "resourceType", BaseSearchQuery.MATCHER.EXACT);
List<ResourceTypeEntry> enties = rtm.getResourceTypes(query);
 
ResourceManager rm = ap.getEntityManager(ResourceManager.class);
ResourceSearchQuery ResourceQuery = new ResourceSearchQuery();
ResourceQuery.setANDMatch();
ResourceQuery.addQuery(ResourceSearchQuery.SEARCH_PROPERTY.NAME, false, ComparatorType.EQUALITY, "R2", BaseSearchQuery.MATCHER.EXACT);
ArrayList<BaseSearchQuery> querries = ResourceQuery.getQueries();
List<ResourceEntry> resources = rm.getResources("RT2", ResourceQuery);
 
PermissionSetManager psm = ap.getEntityManager(PermissionSetManager.class);
PermissionSetSearchQuery pssq = new PermissionSetSearchQuery();
pssq.setANDMatch();
pssq.addQuery(PermissionSetSearchQuery.SEARCH_PROPERTY.NAME, false, ComparatorType.EQUALITY, "PS1", BaseSearchQuery.MATCHER.EXACT);
List<PermissionSetEntry> psets = psm.getPermissionSets(pssq);
 
RoleCategoryManager rcm = ap.getEntityManager(RoleCategoryManager.class);
RoleCategorySearchQuery rcsq = new RoleCategorySearchQuery();
rcsq.setANDMatch();
rcsq.addQuery(RoleCategorySearchQuery.SEARCH_PROPERTY.NAME, false, ComparatorType.EQUALITY, "roleCategoryCartoon", BaseSearchQuery.MATCHER.EXACT);
ArrayList<BaseSearchQuery> queries = rcsq.getQueries();
List<RoleCategoryEntry> rcs = rcm.getRoleCategories(rcsq);

The following example illustrates how to create a grant:

GrantManager gm = ap.getEntityManager(GrantManager.class);
Set<PrincipalEntry> pe = new HashSet<PrincipalEntry>();
List<AppRoleEntry> are = ap.searchAppRoles(appRoleName);
pe.addAll(are);
gm.grant(pe, null, permissionSetName);

Checking Policies Programmatically

When you check policies programmatically, keep in mind the following points:

  • By default, authorization failures are not visible in the console. To have authorization failures sent to the console, set the jps.auth.debug system variable: -Djps.auth.debug=true.

    In particular, to have JpsAuth.checkPermission failures sent to the console, you must set that variable.

  • The policy provider must be explicitly set in Java SE applications:

    java.security.Policy.setPolicy(new oracle.security.jps.internal.policystore.JavaPolicyProvider()) 
    

    Not setting the policy provider explicitly in a Java SE application may cause runtime methods (such as JpsAuth.checkPermission) to return incorrect values.

The following sections illustrate the use of several methods to check policies programmatically:

Using checkPermission

Oracle Fusion Middleware supports the checkPermission method in the java.security.AccessController and oracle.security.jps.util.JpsAuth classes.

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

The static AccessController.checkPermission method uses the default access control context (the context inherited when the thread was created). To check permissions on some other context, call the instance checkPermission method on a particular AccessControlContext instance.

The following table describes the behavior of checkPermission according to the value of the JAAS mode:

Table 17-2 checkPermission Behavior According to JAAS Mode

JAAS Mode checkPermission Behavior

off or undefined

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

doAs

Enforces a combination of codesource and subject-based security using the access control context created in the doAs block.

doAsPrivileged

Enforces subject-based security using a null access control context.

subjectOnly

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

Note:

If you call checkPermission inside a doAs block and the check permission call fails, then to display the failed protection domain you must set the java.security.debug=access,failure system property.

The following example illustrates an application checking a permission. It assumes that the application EAR file includes the configuration jazn-data.xml and web.xml files.

jazn-data.xml

<?xml version="1.0" ?>
<jazn-data>
  <policy-store>
    <applications>
      <application>
        <name>MyApp</name>
                
        <app-roles>
        <app-role>
          <name>AppRole</name>
          <display-name>AppRole display name</display-name>
          <description>AppRole description</description>
          <guid>F5494E409CFB11DEBFEBC11296284F58</guid>
          <class>oracle.security.jps.service.policystore.ApplicationRole</class>
        </app-role>
      </app-roles>
                
      <resource-types>
        <resource-type>
          <name>MyResourceType</name>
          <display-name>MyResourceType display name</display-name>
          <description>MyResourceType description</description>
          <provider-name>MyResourceType provider</provider-name>
          <matcher-class>oracle.security.jps.ResourcePermission</matcher-class>
          <actions-delimiter>,</actions-delimiter>
          <actions>write,read</actions>
        </resource-type>
      </resource-types>
                
      <resources>
        <resource>
          <name>MyResource</name>
          <display-name>MyResource display name</display-name>
          <description>MyResource description</description>
          <type-name-ref>MyResourceType</type-name-ref>
        </resource>
      </resources>
                
      <permission-sets>
        <permission-set>
          <name>MyEntitlement</name>
          <display-name>MyEntitlement display name</display-name>
          <description>MyEntitlement description</description>
          <member-resources>
            <member-resource>
              <type-name-ref>MyResourceType</type-name-ref>
              <resource-name>MyResource</resource-name>
              <actions>write</actions>
            </member-resource>
          </member-resources>
        </permission-set>
      </permission-sets>
                
      <jazn-policy>
        <grant>
          <grantee>
            <principals>
              <principal>
                <class>
              oracle.security.jps.service.policystore.ApplicationRole</class>
                <name>AppRole</name>
                <guid>F5494E409CFB11DEBFEBC11296284F58</guid>
              </principal>
            </principals>
          </grantee>
                        
          <!-- entitlement -->
          <permission-set-refs>
            <permission-set-ref>
              <name>MyEntitlement</name>
            </permission-set-ref>
          </permission-set-refs>
        </grant>
      </jazn-policy>
    </application>      
  </applications>
 </policy-store>
 <jazn-policy></jazn-policy>
</jazn-data>

web.xml

The following example illustrates the JpsFilter filter configuration:

<web-app>
 <display-name>PolicyTest: PolicyServlet</display-name>
 <filter>
  <filter-name>JpsFilter</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>JpsFilter</filter-name>
   <servlet-name>PolicyServlet</servlet-name>
   <dispatcher>REQUEST</dispatcher>
  </filter-mapping>...

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();
        }
    }
}

Using doAs and doAsPrivileged

Oracle Fusion Middleware supports the doAs and doAsPrivileged methods in the javax.security.auth.Subject and oracle.security.jps.util.JpsSubject classes.

Oracle recommends you use the oracle.security.jps.util.JpsSubject class because it renders better performance and provides audit.

Note:

If you call checkPermission inside a doAs block and the check permission call fails, then to display the failed protection domain you must set the java.security.debug=access,failure system property.

Using checkBulkAuthorization

The checkBulkAuthorization method determines whether a subject has access to one or more resource actions. This method returns the set of resource actions the subject is authorized on the resources. Grants using resources must include the resource type.

When you call this method, make sure that:

  1. You have set the java.security.policy system property to the location of the Oracle WebLogic Server policy file.

  2. Your application calls checkBulkAuthorization after setPolicy:

    java.security.Policy.setPolicy(new oracle.security.jps.internal.policystore.JavaPolicyProvider())
    

checkBulkAuthorization assumes that:

  • The caller can provide a subject with user and enterprise role principals, and a list of resources including the stripe each resource belongs to.

  • The application can access the application stripes configured in the domain where the application is running.

Using getGrantedResources

The getGrantedResources method provides a runtime authorization query to fetch all granted resources on a given subject by returning the resource actions that have been granted to the subject. This method returns only permissions associated with resource types and is available only when for LDAP security stores.

The Class ResourcePermission

A permission class provides the means to control the actions that a grantee is allowed on a resource. Even though a custom permission class gives you complete control over the actions, target matching, and logic, to work as expected at runtime, a custom permission class must be specified in the system classpath of the server so that it is available and can be loaded when it is required. But modifying the system class path in environments is difficult and, in some environments, such modification might not be even possible.

OPSS includes the oracle.security.jps.ResourcePermission class that you use as the permission class within any application grant to protect application or system resources. In this way, you no longer need to write custom permission classes and can readily use that class in permissions within application grants stored in any supported policy provider. Do not use this class in system policies, but use it only in application policies.

Configuring Resource Permissions

A permission that uses the ResourcePermission class is called a resource permission, and it specifies the resource type, the resource name, and an optional list of actions:

<permission>
  <class>oracle.security.jps.ResourcePermission</class>
  <name>resourceType=type,resourceName=name</name>
  <actions>character-separated-list-of-actions</actions>
</permission>

Even though the resource type information is not used at runtime, the resource type definition is required.

The following examples illustrate the specifications of resource permissions, which include the required resource types:

<permission>
  <class>oracle.security.jps.ResourcePermission</class>
  <name>resourceType=epm.calcmgr.permission,resourceName=EPM_Calc_Manager</name>
</permission>

<resource-types>
  <resource-type>
    <name>epm.calcmgr.permission</name>
    <display-name>CalcManager ResourceType</display-name>
    <description>Resourcetype for managing CalcManager grants</description>
    <provider-name></provider-name>
    <matcher-class>oracle.security.jps.ResourcePermission</matcher-class>
    <actions-delimiter>,</actions-delimiter>
    <actions></actions>
  </resource-type>
</resource-types>

<permission>
  <class>oracle.security.jps.ResourcePermission</class>
  <name>resourceType=oracle.bi.publisher.Reports,resourceName=GLReports</name>
  <actions>develop;schedule</actions>
</permission>

<resource-types>
  <resource-type>
    <name>oracle.bi.publisher.Reports</name>
    <display-name>BI Publisher Reports</display-name>
    <provider-name></provider-name>
    <matcher-class>oracle.security.jps.ResourcePermission</matcher-class>
    <actions-delimiter>;</actions-delimiter>
    <actions>view;develop;schedule</actions>
  </resource-type>
</resource-types>

A resource type associated with a resource permission can have an empty list of actions. Note the following points about resource permissions:

  • The name must conform to the following format:

    resourceType=aType,resourceName=aName
    

    You must define the resource type of a resource permission. To obtain the type of a resource, use the ResourcePermission.getType method.

  • The character-separated list of actions is optional. If specified, then it must be a subset of the actions specified in the associated resource type. The method ResourcePermission.getActions returns this list.

    The character used to separate the items of the list must equal to the character specified in the <actions-delimiter> of the associated resource type.

  • The ResourcePermission.getResourceName method returns the display name of a resource used in a permission.

  • Wildcard characters are not supported in resource permissions.

Managing and Checking Resource Permissions

The following lines illustrate how to create a resource permission and how to check it:

ResourcePermission rp =
   new ResourcePermission("oracle.bi.publisher.Reports","GLReps","develop");
JpsAuth.checkPermission(rp);
 

The permission check succeeds if the resource permission satisfies the following conditions:

  • The permission is an instance of the ResourcePermision class.

  • The resource type name matches (ignoring case) the name of a resource type.

  • The resource name matches exactly the name of a resource instance.

  • The list of actions is a comma-separated subset of the set of actions specified in the resource type.

About the Class for a Resource Type

When you create a resource type, optionally specify a class. If unspecified, then it defaults to the oracle.security.jps.ResourcePermission class.

If two or more resource types share a class, then that class must be one of the following:

  • The oracle.security.jps.ResourcePermission class.

  • A concrete class extending the oracle.security.jps.AbstractTypedPermission abstract class, as illustrated by MyAbstractTypedPermission:

    public class MyAbstractTypedPermission extends AbstractTypedPermission {
       private static final long serialVersionUID = 8665318227676708586L;
       public MyAbstractTypedPermission(String resourceType, 
                                        String resourceName,                                     String actions) {super(resourceType, resourceName, actions);
        }
    }
    
  • A class implementing the oracle.security.jps.TypePermission class and extending the java.security.Permission class.