9 Role Mapping Providers

This chapter describes role mapping provider concepts and functionality, and provides step-by-step instructions for developing a custom role mapping provider.

Role mapping is the process whereby principals (users or groups) are dynamically mapped to security roles at runtime. In WebLogic Server, a role mapping provider determines what security roles apply to the principals stored a subject when the subject is attempting to perform an operation on a WebLogic resource. Because this operation usually involves gaining access to the WebLogic resource, role mapping providers are typically used with authorization providers.

This chapter includes the following sections:

Role Mapping Concepts

Before you develop a role mapping provider, you need to understand the following concepts:

Security Roles

A security role is a named collection of users or groups that have similar permissions to access WebLogic resources. Like groups, security roles allow you to control access to WebLogic resources for several users at once. However, security roles are scoped to specific resources in a WebLogic Server domain (unlike groups, which are scoped to an entire WebLogic Server domain), and can be defined dynamically (as described in Dynamic Security Role Computation).

Note:

See Users, Groups, and Security Roles in Securing Resources Using Roles and Policies for Oracle WebLogic Server, Security Providers and WebLogic Resources, and Resource Types You Can Secure with Policies in Securing Resources Using Roles and Policies for Oracle WebLogic Server.

The SecurityRole interface in the weblogic.security.service package is used to represent the abstract notion of a security role. (See Java API Reference for Oracle WebLogic Server for the SecurityRole interface.)

Mapping a principal to a security role grants the defined access permissions to that principal, as long as the principal is in the security role. For example, an application may define a security role called AppAdmin, which provides write access to a small subset of that application's resources. Any principal in the AppAdmin security role would then have write access to those resources. See Dynamic Security Role Computation and Users, Groups, and Security Roles in Securing Resources Using Roles and Policies for Oracle WebLogic Server.

Many principals can be mapped to a single security role. See Users and Groups, Principals and Subjects.

Security roles are specified in Java EE deployment descriptor files and/or in the WebLogic Server Administration Console. See Managing Role Mapping Providers and Deployment Descriptors.

Dynamic Security Role Computation

Security roles can be declarative (that is, Java Platform, Enterprise Edition (Java EE) roles) or dynamically computed based on the context of the request.

Dynamic security role computation is the term for this late binding of principals (that is, users or groups) to security roles at runtime. The late binding occurs just prior to an authorization decision for a protected WebLogic resource, regardless of whether the principal-to-security role association is statically defined or dynamically computed. Because of its placement in the invocation sequence, the result of any principal-to-security role computations can be taken as an authentication identity, as part of the authorization decision made for the request.

This dynamic computation of security roles provides a very important benefit: users or groups can be granted a security role based on business rules. For example, a user may be allowed to be in a Manager security role only while the actual manager is away on an extended business trip. Dynamically computing this security role means that you do not need to change or redeploy your application to allow for such a temporarily arrangement. Further, you would not need to remember to revoke the special privileges when the actual manager returns, as you would if you temporarily added the user to a Managers group.

Note:

You typically grant users or groups security roles using the role conditions available in the WebLogic Server Administration Console. (In this release of WebLogic Server, you cannot write custom role conditions.) See Users, Groups, and Security Roles in Securing Resources Using Roles and Policies for Oracle WebLogic Server.

The computed security role is able to access a number of pieces of information that make up the context of the request, including the identity of the target (if available) and the parameter values of the request. The context information is typically used as values of parameters in an expression that is evaluated by the WebLogic Security Framework. This functionality is also responsible for computing security roles that were statically defined through a deployment descriptor or through the WebLogic Server Administration Console.

Note:

The computation of security roles for an authenticated user enhances the Role-Based Access Control (RBAC) security defined by the Java EE specification.

You create dynamic security role computations by defining role statements in the WebLogic Server Administration Console. See Users, Groups, and Security Roles in Securing Resources Using Roles and Policies for Oracle WebLogic Server.

The Role Mapping Process

The WebLogic Security Framework calls each role mapping provider that is configured for a security realm as part of an authorization decision. For related information, see The Authorization Process.

The result of the dynamic security role computation (performed by the role mapping providers) is a set of security roles that apply to the principals stored in a subject at a given moment. These security roles can then be used to make authorization decisions for protected WebLogic resources, as well as for resource container and application code. For example, an Enterprise JavaBean (EJB) could use the Java EE isCallerInRole method to retrieve fields from a record in a database, without having knowledge of the business policies that determine whether access is allowed.

Figure 9-1 shows how the role mapping providers interact with the WebLogic Security Framework to create dynamic security role computations, and an explanation follows.

Figure 9-1 Role Mapping Providers and the Role Mapping Process

Description of Figure 9-1 follows
Description of "Figure 9-1 Role Mapping Providers and the Role Mapping Process"

Generally, role mapping is performed in the following manner:

  1. A user or system process requests a WebLogic resource on which it will attempt to perform a given operation.

  2. The resource container that handles the type of WebLogic resource being requested receives the request (for example, the EJB container receives the request for an EJB resource).

    Note:

    The resource container could be the container that handles any one of the WebLogic Resources described in Security Providers and WebLogic Resources.

  3. The resource container constructs a ContextHandler object that may be used by role mapping providers to obtain information associated with the context of the request.

    The resource container calls the WebLogic Security Framework, passing in the subject (which already contains user and group principals), an identifier for the WebLogic resource, and optionally, the ContextHandler object (to provide additional input).

  4. The WebLogic Security Framework calls each configured role mapping provider to obtain a list of the security roles that apply. This works as follows:

    1. The role mapping providers use the ContextHandler to request various pieces of information about the request. They construct a set of Callback objects that represent the type of information being requested. This set of Callback objects is then passed as an array to the ContextHandler using the handle method.

      The role mapping providers may call the ContextHandler more than once in order to obtain the necessary context information. (The number of times a role mapping provider calls the ContextHandler is dependent upon its implementation.)

    2. Using the context information and their associated security provider databases containing security policies, the subject, and the WebLogic resource, the role mapping providers determine whether the requestor (represented by the user and group principals in the subject) is entitled to a certain security role.

      The security policies are represented as a set of expressions or rules that are evaluated to determine if a given security role is to be granted. These rules may require the role mapping provider to substitute the value of context information obtained as parameters into the expression. In addition, the rules may also require the identity of a user or group principal as the value of an expression parameter.

      Note:

      The rules for security policies are set up in the WebLogic Server Administration Console and in Java EE deployment descriptors. See Security Policies in Securing Resources Using Roles and Policies for Oracle WebLogic Server.

    3. If a security policy specifies that the requestor is entitled to a particular security role, the security role is added to the list of security roles that are applicable to the subject.

    4. This process continues until all security policies that apply to the WebLogic resource or the resource container have been evaluated.

  5. The list of security roles is returned to the WebLogic Security Framework, where it can be used as part of other operations, such as access decisions.

Is Your Custom Role Mapping Provider Thread Safe?

For the best performance, and by default, Weblogic Server supports parallel modification to security policy and roles during application and module deployment. For this reason, deployable authorization and role mapping providers configured in the security realm should support parallel calls. The WebLogic deployable XACML Authorization and Role Mapping providers meet this requirement.

However, custom deployable authorization and role mapping providers may or may not support parallel calls. If your custom deployable authorization or role mapping providers do not support parallel calls, you need to disable the parallel security policy and role modification and instead enforce a synchronization mechanism that results in each application and module being placed in a queue and deployed sequentially.

Note:

Enabling the synchronization mechanism affects every deployable provider configured in the realm, including the predefined WebLogic Server providers. Enabling the synchronization mechanism may negatively impact the performance of these providers.

See Administering Security for Oracle WebLogic Server for information on how to turn on this synchronization enforcement mechanism.

Do You Need to Develop a Custom Role Mapping Provider?

The default (that is, active) security realm for WebLogic Server includes the WebLogic Role Mapping provider and the XACML Role Mapping provider.

Note:

The WebLogic Role Mapping provider, also referred to as the DefaultRoleMapper, is deprecated in WebLogic Server 14.1.1.0.0 and will be removed in a future release. Instead, the XACML Role Mapping provider is the default role mapping provider.

The XACML Role Mapping provider computes dynamic security roles for a specific user (subject) with respect to a specific protected WebLogic resource for each of the default users and WebLogic resources. The XACML Role Mapping provider supports the deployment and undeployment of security roles within the system. It implements XACML 2.0, the standard access control policy markup language. If you want to use a role mapping mechanism that already exists within your organization, you could create a custom role mapping provider to tie into that system.

Does Your Custom Role Mapping Provider Need to Support Application Versioning?

All authorization, role mapping, and credential mapping providers for the security realm must support application versioning in order for an application to be deployed using versions. If you develop a custom security provider for authorization, role mapping, or credential mapping and need to support versioned applications, you must implement the Versionable Application SSPI, as described in Versionable Application Providers.

How to Develop a Custom Role Mapping Provider

If the XACML Role Mapping provider does not meet your needs, you can develop a custom role mapping provider by following these steps:

  1. Create Runtime Classes Using the Appropriate SSPIs, or, optionally, implement the Bulk Role Mapping Providers

  2. Optionally, implement the Role Consumer SSPI

  3. Generate an MBean type for your custom role mapping provider by completing the steps described in Generate an MBean Type Using the WebLogic MBeanMaker.

  4. Configure the Custom Role Mapping Provider Using the Administration Console

  5. Provide a Mechanism for Security Role Management

Create Runtime Classes Using the Appropriate SSPIs

Before you start creating runtime classes, you should first:

When you understand this information and have made your design decisions, create the runtime classes for your custom role mapping provider by following these steps:

For an example of how to create a runtime class for a custom role mapping provider, see Example: Creating the Runtime Class for the Sample Role Mapping Provider.

Implement the RoleProvider SSPI

To implement the RoleProvider SSPI, provide implementations for the methods described in Understand the Purpose of the Provider SSPIs and the following method:

  • getRoleMapper

    public RoleMapper getRoleMapper()
    

    The getRoleMapper method obtains the implementation of the RoleMapper SSPI. For a single runtime class called MyRoleProviderImpl.java, the implementation of the getRoleMapper method would be:

    return this;
    

    If there are two runtime classes, then the implementation of the getRoleMapper method could be:

    return new MyRoleMapperImpl;
    

    This is because the runtime class that implements the RoleProvider SSPI is used as a factory to obtain classes that implement the RoleMapper SSPI.

See Java API Reference for Oracle WebLogic Server for the RoleProvider SSPI.

Implement the DeployableRoleProviderV2 SSPI

Note:

The DeployableRoleProvider SSPI is deprecated in this release of WebLogic Server. Use the DeployableRoleProviderV2 SSPI instead.

To implement the DeployableRoleProviderV2 SSPI, provide implementations for the methods described in Understand the Purpose of the Provider SSPIs, Implement the RoleProvider SSPI, and the following methods:

  • deleteApplicationRoles

    void deleteApplicationRoles(ApplicationInfo application)
    

    Deletes all roles for an application and is called only on the Administration Server within a WebLogic Server domain at the time an application is deleted.

  • deployRole

    void deployRole(DeployRoleHandle handle, Resource resource, String roleName,
    String[] userAndGroupNames)
    

    Creates a role on behalf of a deployed Web application or EJB. If the role already exists, it is removed and replaced by this role.

  • endDeployRoles

    void endDeployRoles(DeployRoleHandle handle)
    

    Marks the end of an application role deployment.

  • startDeployRoles

    DeployRoleHandle startDeployRoles(ApplicationInfo application)
    

    Marks the beginning of an application role deployment and is called on all servers within a WebLogic Server domain where an application is targeted.

  • undeployAllRoles

    void undeployAllRoles(DeployRoleHandle handle)
    

    Deletes a set of roles on behalf of an undeployed Web application or EJB.

See Java API Reference for Oracle WebLogic Server for the DeployableRoleProviderV2 SSPI.

The ApplicationInfo Interface

The ApplicationInfo interface passes data about an application deployment to a security provider. You can use this data to uniquely identity the application.

The Security Framework implements the ApplicationInfo interface for your convenience. You do not need to implement any methods for this interface.

The DeployableAuthorizationProviderV2 and DeployableRoleProviderV2 interfaces use ApplicationInfo. For example, consider an implementation of the DeployableRoleProviderV2 methods. The Security Framework calls the DeployableRoleProviderV2 startDeployRoles method and passes in the ApplicationInfo interface for this application. The ApplicationInfo data is determined based on the information supplied in the WebLogic Server Administration Console when an application is deployed.

The startDeployRoles method returns DeployRoleHandle, which you can then use in the other DeployableRoleProviderV2 methods.

You use the ApplicationInfo interface to get the application identifier, the component name, and the component type for this application. Component type can be APPLICATION, CONTROL_RESOURCE, EJB, or WEBAPP, as defined in the ApplicationInfo.ComponentType class.

The following example shows one way to accomplish this task:

public DeployRoleHandle startDeployRoles(ApplicationInfo appInfo)
    throws DeployHandleCreationException
     :
// Obtain the application information...
    String appId = appInfo.getApplicationIdentifier();
    ComponentType compType = appInfo.getComponentType();
    String compName = appInfo.getComponentName();

The Security Framework calls the DeployableRoleProviderV2 deleteApplicationRoles method and passes in the ApplicationInfo interface for this application. The deleteApplicationRoles method deletes all roles for an application and is called (only on the Administration Server within a WebLogic Server domain) at the time an application is deleted.

Implement the RoleMapper SSPI

To implement the RoleMapper SSPI, provide implementations for the following methods:

  • getRoles

    public Map getRoles(Subject subject, Resource  resource, ContextHandler handler)
    

    The getRoles method returns the security roles associated with a given subject for a specified WebLogic resource, possibly using the optional information specified in the ContextHandler. For more information about ContextHandlers, see ContextHandlers and WebLogic Resources.

See Java API Reference for Oracle WebLogic Server for the RoleMapper SSPI and the getRoles methods.

Implement the SecurityRole Interface

The methods on the SecurityRole interface allow you to obtain basic information about a security role, or to compare it to another security role. These methods are designed for the convenience of security providers.

Note:

SecurityRole implementations are returned as a Map by the getRoles() method (see Implement the RoleProvider SSPI).

To implement the SecurityRole interface, provide implementations for the following methods:

  • equals

    public boolean equals(Object another)
    

    The equals method returns TRUE if the security role passed in matches the security role represented by the implementation of this interface, and FALSE otherwise.

  • toString

    public String toString()
    

    The toString method returns this security role, represented as a String.

  • hashCode

    public int hashCode()
    

    The hashCode method returns a hashcode for this security role, represented as an integer.

  • getName

    public String getName()
    

    The getName method returns the name of this security role, represented as a String.

  • getDescription

    public String getDescription()
    

    The getDescription method returns a description of this security role, represented as a String. The description should describe the purpose of this security role.

Example: Creating the Runtime Class for the Sample Role Mapping Provider

Example 9-1 shows the SimpleSampleRoleMapperProviderImpl.java class, which is the runtime class for the sample role mapping provider. This runtime class includes implementations for:

Example 9-1 SimpleSampleRoleMapperProviderImpl.java

package examples.security.providers.roles.simple;

import java.security.Principal;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.security.auth.Subject;
import weblogic.management.security.ProviderMBean;
import weblogic.security.SubjectUtils;
import weblogic.security.WLSPrincipals;
import weblogic.security.service.ContextHandler;
import weblogic.security.spi.ApplicationInfo;
import weblogic.security.spi.ApplicationInfo.ComponentType;
import weblogic.security.spi.DeployableRoleProviderV2;
import weblogic.security.spi.DeployRoleHandle;
import weblogic.security.spi.Resource;
import weblogic.security.spi.RoleMapper;
import weblogic.security.spi.SecurityServices;
import weblogic.security.spi.VersionableApplicationProvider;

public final class SimpleSampleRoleMapperProviderImpl
implements DeployableRoleProviderV2, RoleMapper, VersionableApplicationProvider
{
   private String              description; 
// a description of this provider
   private SimpleSampleRoleMapperDatabase database;     
// manages the role definitions for this provider
   private static final Map NO_ROLES = Collections.unmodifiableMap(new HashMap(1)); 
// used when no roles are found

  public void initialize(ProviderMBean mbean, SecurityServices services)
  {
     System.out.println("SimpleSampleRoleMapperProviderImpl.initialize");

// Cast the mbean from a generic ProviderMBean to a SimpleSampleRoleMapperMBean.
     SimpleSampleRoleMapperMBean myMBean = (SimpleSampleRoleMapperMBean)mbean;

     // Set the description to the simple sample role mapper's mbean's description and version 
     description = myMBean.getDescription() + "\n" + myMBean.getVersion();

     // Instantiate the helper that manages this provider's role definitions
     database = new SimpleSampleRoleMapperDatabase(myMBean);
  }
  public String getDescription()
{
     return description;
}

  public void shutdown()
{
     System.out.println("SimpleSampleRoleMapperProviderImpl.shutdown");
}

  public RoleMapper getRoleMapper()
  {
     // Since this class implements both the DeployableRoleProvider
     // and RoleMapper interfaces, this object is the
     // role mapper object so just return "this".
     return this;
  }

public Map getRoles(Subject subject, Resource resource, ContextHandler handler)
{
   System.out.println("SimpleSampleRoleMapperProviderImpl.getRoles");
   System.out.println("\tsubject\t= " + subject);
   System.out.println("\tresource\t= " + resource);

   // Make a list for the roles
   Map roles = new HashMap();


   // Make a list for the roles that have already been found and evaluated
   Set rolesEvaluated = new HashSet();

   // since resources scope roles, and resources are hierarchical,
   // loop over the resource and all its parents, adding in any roles
   // that match the current subject.
     for (Resource res = resource; res != null; res = res.getParentResource()) {
       getRoles(res, subject, roles, rolesEvaluated);
     }

   // try global resources too
   getRoles(null, subject, roles, rolesEvaluated);

   // special handling for no matching roles
   if (roles.isEmpty()) {
     return NO_ROLES;
   }

   // return the roles we found.
   System.out.println("\troles\t= " + roles);
   return roles;
   }

public DeployRoleHandle startDeployRoles(ApplicationInfo application)
{
   String appId = application.getApplicationIdentifier();
   String compName = application.getComponentName();
   ComponentType compType = application.getComponentType();
   DeployRoleHandle handle = new SampleDeployRoleHandle(appId,compName,compType);

   // ensure that previous roles have been removed so that
   // the most up to date deployment roles are in effect
   database.removeRolesForComponent(appId, compName, compType);

   // A null handle may be returned if needed
   return handle;

   }

public void deployRole(DeployRoleHandle handle, Resource resource,
String roleName, String[] principalNames)
{
   System.out.println("SimpleSampleRoleMapperProviderImpl.deployRole");
   System.out.println("\thandle\t\t= " + ((SampleDeployRoleHandle)handle).toString());
   System.out.println("\tresource\t\t= " + resource);
   System.out.println("\troleName\t\t= " + roleName);

   for (int i = 0; principalNames != null && i < principalNames.length; i++) {
      System.out.println("\tprincipalNames[" + i + "]\t= " + principalNames[i]);
   }
   database.setRole(resource, roleName, principalNames);
}
public void endDeployRoles(DeployRoleHandle handle)
{
database.saveRoles();
}

public void undeployAllRoles(DeployRoleHandle handle)
{
   System.out.println("SimpleSampleRoleMapperProviderImpl.undeployAllRoles");
   SampleDeployRoleHandle myHandle = (SampleDeployRoleHandle)handle;
   System.out.println("\thandle\t= " + myHandle.toString());

  // remove roles
   database.removeRolesForComponent(myHandle.getApplication(),
                                    myHandle.getComponent(),
                                    myHandle.getComponentType());
}

public void deleteApplicationRoles(ApplicationInfo application)
{
   System.out.println("SimpleSampleRoleMapperProviderImpl.deleteApplicationRoles");
   String appId = application.getApplicationIdentifier();
   System.out.println("\tapplication identifier\t= " + appId);

   // clear out roles for the application
   database.removeRolesForApplication(appId);
}


private void getRoles(Resource resource, Subject subject,
              Map roles, Set rolesEvaluated)
  {
   // loop over all the roles in our "database" for this resource
   for (Enumeration e = database.getRoles(resource); e.hasMoreElements();) {
     String role = (String)e.nextElement();

     // Only check for roles not already evaluated
     if (rolesEvaluated.contains(role)) {
       continue;
     }
     // Add the role to the evaluated list
     rolesEvaluated.add(role);

     // If any of the principals is on that role, add the role to the list.
     if (roleMatches(resource, role, subject)) {

       // Add a simple sample role mapper role instance to the list of roles.
       roles.put(role, new SimpleSampleSecurityRoleImpl(role));
     }
   }
}

private boolean roleMatches(Resource resource, String role, Subject subject)
{
   // loop over the the principals that are in this role.
   for (Enumeration e = database.getPrincipalsForRole(resource, role); e.hasMoreElements();) {

     // get the next principal in this role
     String principalWant = (String)e.nextElement();

     // see if any of the current principals match this principal
     if (subjectMatches(principalWant, subject)) {
       return true;
     }
   }
return false;
}

private boolean subjectMatches(String principalWant, Subject subject)
{
   // first, see if it's a group name match
   if (SubjectUtils.isUserInGroup(subject, principalWant)) {
     return true;
   }
   // second, see if it's a user name match
   if (principalWant.equals(SubjectUtils.getUsername(subject))) {
     return true;
   }
   // didn't match
   return false;
}

public void createApplicationVersion(String appId, String sourceAppId)
{
   System.out.println("SimpleSampleRoleMapperProviderImpl.createApplicationVersion");
   System.out.println("\tapplication identifier\t= " + appId);
   System.out.println("\tsource app identifier\t= " + ((sourceAppId != null) ? sourceAppId : "None"));

   // create new roles when existing application is specified
   if (sourceAppId != null) {
     database.cloneRolesForApplication(sourceAppId,appId);
   }
}


public void deleteApplicationVersion(String appId)
{
   System.out.println("SimpleSampleRoleMapperProviderImpl.deleteApplicationVersion");
   System.out.println("\tapplication identifier\t= " + appId);

   // clear out roles for the application
   database.removeRolesForApplication(appId);
}

public void deleteApplication(String appName)
{
   System.out.println("SimpleSampleRoleMapperProviderImpl.deleteApplication");
   System.out.println("\tapplication name\t= " + appName);

   // clear out roles for the application
   database.removeRolesForApplication(appName);
}

class SampleDeployRoleHandle implements DeployRoleHandle
{
   Date date;
   String application;
   String component;
   ComponentType componentType;

   SampleDeployRoleHandle(String app, String comp, ComponentType type)
   {
     this.application = app;
     this.component = comp;
     this.componentType = type;
     this.date = new Date();
   }

   public String getApplication() { return application; }
   public String getComponent() { return component; }
   public ComponentType getComponentType() { return componentType; }

   public String toString()
{
     String name = component;
     if (componentType == ComponentType.APPLICATION)
       name = application;
     return componentType +" "+ name +" ["+ date.toString() +"]";
   }
  }
}

Example 9-2 shows the sample SecurityRole implementation that is used along with the SimpleSampleRoleMapperProviderImpl.java runtime class.

Example 9-2 SimpleSampleSecurityRoleImpl.java

package examples.security.providers.roles.simple;
import weblogic.security.service.SecurityRole;
/*package*/ class SimpleSampleSecurityRoleImpl implements SecurityRole
{
   private String roleName; // the role's name
   private int    hashCode; // the role's hash code
/*package*/ SimpleSampleSecurityRoleImpl(String roleName)
{
   this.roleName = roleName;
   this.hashCode = roleName.hashCode() + 17;
}
public boolean equals(Object genericRole)
{
   // if the other role is null, we're not the same
   if (genericRole == null) {
   return false;
   }
// if we're the same java object, we're the same
if (this == genericRole) {
   return true;
}

// if the other role is not a simple sample role mapper role,
// we're not the same
if (!(genericRole instanceof SimpleSampleSecurityRoleImpl)) {
return false;
}

// Cast the other role to a simple sample role mapper role.
SimpleSampleSecurityRoleImpl sampleRole =
(SimpleSampleSecurityRoleImpl)genericRole;
// if our names don't match, we're not the same
if (!roleName.equals(sampleRole.getName())) {
   return false;
}
// we're the same
   return true;
}
public String toString()
{
return roleName;
}

public int hashCode()
{
return hashCode;
}

public String getName()
{
   return roleName;
}
public String getDescription()
{
   return "";
}
}

Role Consumer SSPI

WebLogic Server implements a role consumer for Web service annotations. This release of WebLogic Server includes an SSPI that role mapping providers can use to obtain the role collections.

The RoleConsumer SSPI is optional; only those role mapping providers that implement the SSPI are called to consume a role collection.

The SSPI supports both the delivery of initial role collections and the delivery of updated role collections.

All role mapping providers that support the RoleConsumer SSPI are called to consume a role collection. Each role mapping provider can choose to skip or obtain the role collection for a given role set. In the case where a provider persists roles, the provider need only collect the role once. However, providers keeping roles in memory can obtain the role collection again.

The out-of-the-box WebLogic Server Role Mapping providers persist the role into LDAP.

Required SSPI Interfaces

If you want your custom role mapping provider to support the delivery of role collections, you must implement three interfaces:

  • weblogic.security.spi.RoleConsumerFactory

  • weblogic.security.spi.RoleConsumer

  • weblogic.security.spi.RoleCollectionHandler

These interfaces are described in the sections that follow.

Implement the RoleConsumerFactory SSPI Interface

A role mapping provider implements the RoleConsumerFactory interface so that an instance of a RoleConsumer is available to the WebLogic Security Framework. The WebLogic Security Framework calls your RoleConsumerFactory implementation to obtain the provider's implementation of the role consumer.

The RoleConsumerFactory SSPI has one method, which returns your implementation of the RoleConsumer SSPI interface.

public interface RoleConsumerFactory
{
  /**
   * Obtain the implementation of the RoleConsumer
   * security service provider interface (SSPI).<P>
   *
   * @return a RoleConsumer SSPI implementation.<P>
   */
  public RoleConsumer getRoleConsumer();
}
Implement the RoleConsumer SSPI Interface

The RoleConsumer SSPI returns a role collection handler for consumption of a role collection. It has one method, getRoleCollectionHandler(), which takes a RoleCollectionInfo implementation as an argument and returns your implementation of the RoleCollectionHandler interface.

public interface RoleConsumer
{
  /**
   * Obtain a role handler for consumption of a role collection.
   *
   * @param info the RoleCollectionInfo for the role collection.
   *
   * @return a RoleCollectionHandler or NULL which indicates
   *         that the role collection is not needed.
   *
   * @exception ConsumptionException if an error occurs
   *            obtaining the handler and the role collection cannot be consumed.
   */
  public RoleCollectionHandler getRoleCollectionHandler(
                                        RoleCollectionInfo info)
    throws ConsumptionException;
}

The WebLogic Security Framework calls the getRoleCollectionHandler() method and passes data about a role collection to a security provider as an implementation of the RoleCollectionInfo interface. (This interface implementation is provided for you, you do not have to implement it.)

You use the RoleCollectionInfo getName(), getVersion(), getTimestamp(), and getResourceTypes() methods to discover information about this role collection. You then return a RoleCollectionHandler, or NULL to indicate that the role collection is not needed.

public interface RoleCollectionInfo
{
  /**
   * Get the name of the collection.
   */
  public String getName();

  /**
   * Get the runtime version of the role.
   */
  public String getVersion();

  /**
   * Get the timestamp of the role.
   */
  public String getTimestamp();

  /**
   * Get the resource types used in the role collection.
   */
  public Resource[] getResouceTypes();
}
Implement the RoleCollectionHandler SSPI Interface

The RoleConsumer.getRoleCollectionHandler() method returns your implementation of the RoleCollectionHandler interface. RoleCollectionHandler has two methods: setRole() and done(). The setRole() method takes a resource, a role name, and an array of user and group names that defines what user names and group names are to be assigned to that role for the given resource.

The done() method signals the completion of the role collection.

public interface RoleCollectionHandler
{
  /**
   * Set a role for the specified resource.
   */
  public void setRole(Resource resource, String roleName, String[] userAndGroupNames)
     throws ConsumptionException;

  
  /**
   * Signals the completion of the role collection.
   */
  public void done()
     throws ConsumptionException;

}
Supporting an Updated Role Collection

To support the delivery of an updated role collection, all role mapping providers that support the RoleConsumer SSPI need to examine the contents of the RoleCollectionInfo passed in the RoleConsumer.getRoleCollectionHandler() method to determine if a role collection has changed. Each provider must decide (possibly by configuration) how to perform conflict resolution with the initial role collection and any customized role received outside of the SSPI.

For the WebLogic Server supplied role mapping providers, customized roles will not be replaced by the updated role collection: all roles from the initial role collection will be removed and only the customized roles, plus the updated role collection, will be in effect. If the role collection info has a different timestamp or version, it's treated as an updated role collection. The collection name is used as a persistence key.

The RoleConsumerMBean

Role mapping providers that implement the Role Consumer SSPI must also implement the weblogic.management.security.authorization.RoleConsumerMBean to indicate that the provider supports policy consumption.

PolicyStoreMBean

This release of WebLogic Server includes support for a new MBean (weblogic.management.security.authorization.PolicyStoreMBean) that allows for standard management (add, delete, get, list, modify, read) of administrator-generated XACML policies and policy sets. An authorization or role mapping provider MBean can optionally implement this MBean interface.

The PolicyStoreMBean methods allow security administrators to manage policy in the server as XACML documents. This includes creating and managing a domain that uses the default XACML provider, as well as managing XACML documents that the administrator has created. The administrator can then use WLST to manage these XACML policies in WebLogic Server.

WebLogic Server includes an implementation of this MBean for use with the out-of-the-box XACML providers, and you can write your own implementation of this MBean for use with your own custom authorization or role mapping providers. The WebLogic Server out-of-the-box XACML providers support the mandatory features of XACML, as described in the XACML 2.0 Core Specification (http://docs.oasis-open.org/xacml/2.0/access_control-xacml-2.0-core-spec-os.pdf), with the Oracle-specific usage described in Securing Resources Using Roles and Policies for Oracle WebLogic Server.

Policies are expressed as XACML 2.0 Policy or PolicySet documents. Custom authorization providers should expect standard Policy or PolicySet documents as described in the XACML 2.0 Core Specification. Custom role mapping providers should expect Policy or PolicySet documents consistent with role assignment policies described by the Core and hierarchical role based access control (RBAC) profile of XACML v2.0 (http://docs.oasis-open.org/xacml/2.0/access_control-xacml-2.0-rbac-profile1-spec-os.pdf).

Specifically, the Target must contain:

  • An ActionAttributeDesignator with the id, urn:oasis:names:tc:xacml:1.0:action:action-id, and the value, urn:oasis:names:tc:xacml:2.0:actions:enableRole, according to anyURI-equal. For example:

<Action>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:anyURI-equal">

<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#anyURI">urn:oasis:names:tc:xacml:2.0:actions:enableRole
</AttributeValue>

<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#anyURI" MustBePresent="true"/>

</ActionMatch>
</Action>
  • A ResourceAttributeDesignator with the id, urn:oasis:names:tc:xacml:2.0:subject:role, and a value naming the role being assigned, according to string-equal. For example:

<ResourceAttributeDesignator AttributeId="urn:oasis:names:tc:xacml:2.0:resource:resource-ancestor-or-self"
DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"/>
Examining the Format of a XACML Policy File

The XACML 2.0 Core Specification (http://docs.oasis-open.org/xacml/2.0/access_control-xacml-2.0-core-spec-os.pdf) and the Oracle extensions described in Securing Resources Using Roles and Policies for Oracle WebLogic Server are the definitive sources of information for the XACML policy files used by the supplied XACML Authorization and Role Mapping Providers.

However, if as part of your development process you want to take a look at the format of a supported XACML file, perhaps the most convenient way is to use the WebLogic Server Administration Console to export the data from the XACML Authorization or Role Mapping provider's database as a XACML file. Copy this exported XACML file to a file with some other name and use the tool of your choice to review the copy.

Note:

Treat the exported file as read-only. If you do make changes, do not import the file back into WebLogic Server. Editing exported files might result in an unusable WebLogic Server configuration and is not supported.

Using WLST to Add a Policy to the PolicyStoreMBean

Example 9-3 shows an example of using WLST to add a single policy to an instance of the PolicyStoreMBean from a XACML file.

The example assumes that you have defined the properties used in this script elsewhere, in a manner similar to the following lines from an ant script:

<property name="xacml-docs-dir" value="${xacmldir}/xacml-docs"/>
<sysproperty key="file" value="${xacml-docs-dir}/policy-getSubject.xacml"/>

You should avoid entering clear-text passwords in WLST commands in general, and you should especially avoid saving on disk WLST scripts that include clear-text passwords. In these instances you should use a mechanism for passing encrypted passwords instead. See Security for WLST in Understanding the WebLogic Scripting Tool.

Example 9-3 Using WLST to Add a Policy to the PolicyStoreMBean

:
try:
      protocol = System.getProperty("protocol")
      host = System.getProperty("host")
      user = System.getProperty("authuser")
      passwd = System.getProperty("authpwd")
      port = System.getProperty("port")
      dom = System.getProperty("domain")
      rlm = System.getProperty("realm")
      fil = System.getProperty("file")
      prov = System.getProperty("provider")
      stat = System.getProperty("status")

def configure():
try:
      url = protocol + "://" + host + ":" + port
      connect(user,passwd, url)
      path = "/SecurityConfiguration/" + dom + "/Realms/" + rlm + "/" + prov
      print("cd'ing to " + path)
      cd(path)
      print("calling open()")
      xacmlFile = open(fil,"r")
      print("calling read()")
      xacmlDoc = xacmlFile.read()
      print("calling cmo.addPolicy")
      if stat == "none":
          cmo.addPolicy(xacmlDoc)
      else:
          cmo.addPolicy(xacmlDoc, stat)
      print("Add error handling")
:
:

As described in the Navigating and Interrogating MBeans section of Understanding the WebLogic Scripting Tool, when WLST first connects to an instance of WebLogic Server, the variable, cmo (Current Management Object), is initialized to the root of all configuration management objects, DomainMBean. When you navigate to an MBean type, in this case SecurityConfigurationMBean, the value of cmo reflects SecurityConfigurationMBean. When you navigate to an MBean instance, in this case to an Authorizer MBean that implements the PolicyStoreMBean, identified in the example by the variable prov, WLST changes the value of cmo to be the current MBean instance.

The example uses the addPolicy() method of the PolicyStoreMBean to add a policy read from a XACML file to the policy store. Two variants of the addPolicy() method (without and with status) are shown.

If you use an addPolicy() method that does not specify status, it defaults to ACTIVE, which indicates that the policy is evaluated for any decision to which its target applies. You can explicitly set status to be ACTIVE, INACTIVE, or BYREFERENCE. The INACTIVE status indicates that the policy will never be evaluated and is only being stored. The BYREFERENCE status indicates that the policy will only be evaluated when referenced by a policy set that is being evaluated.

You can invoke this type of WLST script from the command line, in a manner similar to the following:

java -Dhost="localhost " -Dprotocol="t3" -Dauthuser="weblogic"
-Dauthpwd="weblogic" -Dport="7001" -Ddomain="mydomain" -Drealm="myrealm"
-Dprovider="Authorizers/XACMLAuthorizer"
-Dfile="C:/XACML/xacml-docs/policy12.xml" -Dstatus="none" weblogic.WLST
XACML/scripts/XACMLaddPolicy.py
Using WLST to Read a PolicySet as a String

Example 9-4 shows an example of using WLST to read a PolicySet as a string.

The example assumes that you have defined the properties used in this script elsewhere, in a manner similar to the following lines from an ant script:

<sysproperty key="identifier"
value="urn:sample:xacml:2.0:wlssecqa:resource:type@E@Fejb@G@M@Oapplication@ENoD
DRolesOrPoliciesEar@M@Omodule@Eejb11inEarMiniAppBean.jar@M@Oejb@EMiniAppBean@
M@Omethod@EgetSubject@M@OmethodInterface@ERemote"/>
<sysproperty key="version" value="1.0"/>

You should avoid entering clear-text passwords in WLST commands in general, and you should especially avoid saving on disk WLST scripts that include clear-text passwords. In these instances you should use a mechanism for passing encrypted passwords instead. See Security for WLST in Understanding the WebLogic Scripting Tool.

Example 9-4 Using WLST to Read a PolicySet as a String

:
:
try:
      print("start XACMLreadPolicySet.py")
      protocol = System.getProperty("protocol")
      host = System.getProperty("host")
      user = System.getProperty("authuser")
      passwd = System.getProperty("authpwd")
      port = System.getProperty("port")
      dom = System.getProperty("domain")
      rlm = System.getProperty("realm")
      prov = System.getProperty("provider")
      id = System.getProperty("identifier")
      vers = System.getProperty("version")
:
:
def configure():
try:
      url = protocol + "://" + host + ":" + port
      connect(user,passwd, url)
      path = "/SecurityConfiguration/" + dom + "/Realms/" + rlm + "/" + prov
      print("cd'ing to " + path)
      cd(path)
      polset = cmo.readPolicySetAsString(id, vers)
      print("readPolicySetAsString() returned the following policy set: " + polset)
      print"Add error handling."
:
:

As described in the XACML 2.0 Core Specification (http://docs.oasis-open.org/xacml/2.0/access_control-xacml-2.0-core-spec-os.pdf), the <PolicySet> element contains a set of <Policy> or other <PolicySet> elements and a specified procedure for combining the results of their evaluation. See the XACML 2.0 Core Specification for complete information.

Bulk Role Mapping Providers

This release of WebLogic Server includes bulk access versions of the following role mapping provider SSPI interfaces:

  • BulkRoleProvider

  • BulkRoleMapper

The bulk access SSPI interfaces allow role mapping providers to receive multiple decision requests in one call rather than through multiple calls, typically in a 'for' loop. The intent of the bulk SSPI variants is to allow provider implementations to take advantage of internal performance optimizations, such as detecting that many of the passed-in Resource objects are protected by the same policy and will generate the same decision result.

There are subtle differences in how the non-bulk and bulk versions of the SSPI interfaces are used. For example, the BulkRoleMapper.getRoles() method returns a Map of roles indexed first by resource and then by their names (Map<Resource, Map<String, SecurityRole>>), representing the security roles associated with the specified resources that have been granted to the subject.

Configure the Custom Role Mapping Provider Using the Administration Console

Configuring a custom role mapping provider means that you are adding the custom role mapping provider to your security realm, where it can be accessed by applications requiring role mapping services.

Configuring custom security providers is an administrative task, but it is a task that may also be performed by developers of custom security providers. This section contains information that is important for the person configuring your custom role mapping providers:

Managing Role Mapping Providers and Deployment Descriptors

Some application components, such as Enterprise JavaBeans (EJBs) and Web applications, store relevant deployment information in Java EE and WebLogic Server deployment descriptors. For Web applications, the deployment descriptor files (called web.xml and weblogic.xml) contain information for implementing the Java EE security model, including security roles. Typically, you will want to include this information when first configuring your role mapping providers in the WebLogic Server Administration Console.

Because the Java EE platform standardizes Web application and EJB security in deployment descriptors, WebLogic Server integrates this standard mechanism with its Security Service to give you a choice of techniques for securing Web application and EJB resources. You can use deployment descriptors exclusively, the WebLogic Server Administration Console exclusively, or you can combine the techniques for certain situations.

Depending on the technique you choose, you also need to apply a Security Model. WebLogic supports different security models for individual deployments, and a security model for realm-wide configurations that incorporate the technique you want to use.

See Options for Securing EJB and Web Application Resources in Securing Resources Using Roles and Policies for Oracle WebLogic Server.

When configured to use deployment descriptors, WebLogic Server reads security role information from the web.xml and weblogic.xml deployment descriptor files (examples of web.xml and weblogic.xml files are shown in Example 9-5 and Example 9-6. This information is then copied into the security provider database for the role mapping provider.

Example 9-5 Sample web.xml File

<web-app> 
   <welcome-file-list> 
      <welcome-file>welcome.jsp</welcome-file> 
   </welcome-file-list> 
   <security-constraint> 
      <web-resource-collection>
         <web-resource-name>Success</web-resource-name>
         <url-pattern>/welcome.jsp</url-pattern>
         <http-method>GET</http-method> 
         <http-method>POST</http-method> 
      </web-resource-collection> 
      <auth-constraint> 
         <role-name>developers</role-name> 
      </auth-constraint> 
   </security-constraint> 
   <login-config> 
       <auth-method>BASIC</auth-method> 
       <realm-name>default</realm-name> 
   </login-config> 
   <security-role> 
      <role-name>developers</role-name> 
   </security-role> 
</web-app>

Example 9-6 Sample weblogic.xml File

<weblogic-web-app> 
   <security-role-assignment> 
      <role-name>developers</role-name>
      <principal-name>myGroup</principal-name> 
   </security-role-assignment> 
</weblogic-web-app>
Enabling Security Role Deployment

If you implemented the DeployableRoleProviderV2 SSPI as part of developing your custom role mapping provider and want to support deployable security roles, the person configuring the custom role mapping provider (that is, you or an administrator) must be sure that the Role Deployment Enabled box in the WebLogic Server Administration Console is checked. Otherwise, deployment for the role mapping provider is considered turned off. Therefore, if multiple role mapping providers are configured, the Role Deployment Enabled box can be used to control which role mapping provider is used for security role deployment.

Provide a Mechanism for Security Role Management

While configuring a custom role mapping provider via the WebLogic Server Administration Console makes it accessible by applications requiring role mapping services, you also need to supply administrators with a way to manage this security provider's associated security roles. The WebLogic Role Mapping provider, for example, supplies administrators with a Role Editor page that allows them to add, modify, or remove security roles for various WebLogic resources.

Neither the Role Editor page nor access to it is available to administrators when you develop a custom role mapping provider. Therefore, you must provide your own mechanism for security role management. This mechanism must read and write security role data (that is, expressions) to and from the custom role mapping provider's database.

You can accomplish this task in one of two ways:

Option 1: Develop a Stand-Alone Tool for Security Role Management

You would typically select this option if you want to develop a tool that is entirely separate from the WebLogic Server Administration Console.

For this option, you do not need to write any console extensions for your custom role mapping provider, nor do you need to develop any management MBeans. However, your tool needs to:

  1. Determine the WebLogic resource's ID, since it is not automatically provided to you by the console extension. For more information, see WebLogic Resource Identifiers.

  2. Determine how to represent the expressions that make up a security role. (This representation is entirely up to you and need not be a string.)

  3. Read and write the expressions from and to the custom role mapping provider's database.

Option 2: Integrate an Existing Security Role Management Tool into the Administration Console

You would typically select this option if you have a tool that is separate from the WebLogic Server Administration Console, but you want to launch that tool from the WebLogic Server Administration Console.

For this option, your tool needs to:

  1. Determine the WebLogic resource's ID, since it is not automatically provided to you by the console extension. See WebLogic Resource Identifiers.

  2. Determine how to represent the expressions that make up a security role. (This representation is entirely up to you and need not be a string.)

  3. Read and write the expressions from and to the custom role mapping provider's database.

  4. Link into the WebLogic Server Administration Console using basic console extension techniques.