bea.com | products | dev2dev | support | askBEA |
|
e-docs > WebLogic Server > Developing Security Providers for WebLogic Server > Role Mapping Providers |
Developing Security Providers for WebLogic Server |
Role mapping is the process whereby principals are dynamically mapped to roles at runtime. In WebLogic Server, a Role Mapping provider determines what 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.
The following sections describe Role Mapping provider concepts and functionality, and provide step-by-step instructions for developing a custom Role Mapping provider:
Before you develop a Role Mapping provider, you need to understand the following concepts:
A role is a named collection of users or groups that have similar permissions to access WebLogic resources. Like groups, roles allow you to control access to WebLogic resources for several users at once. However, roles are scoped to specific resources within a single application in a WebLogic Server security domain (unlike groups, which are scoped to an entire WebLogic Server security domain), and can be defined dynamically (as described in Dynamic Role Association).
Notes: For more information about roles, see "Understanding Roles" in Managing WebLogic Security. For more information about WebLogic resources, see WebLogic Resources.
The SecurityRole interface in the weblogic.security.service package is used to represent the abstract notion of a role. (For more information, see the WebLogic Server 7.0 API Reference Javadoc for the SecurityRole interface.)
Mapping a principal (that is, a user or a group) to a security role confers the defined access permissions to that principal, as long as the principal is "in" the role. For example, an application may define a role called "AppAdmin," which provides write access to a small subset of that application's resources. Any principal in the AppAdmin role would then have write access to those resources. Many principals can be mapped to a single role. For more information about principals, see Users and Groups, Principals and Subjects.
Roles are specified in Java 2 Enterprise Edition (J2EE) deployment descriptor files and/or in the WebLogic Server Administration Console. For more information, see Managing Role Mapping Providers and Deployment Descriptors.
Once you create a role, you define an association between that role and a WebLogic resource. This association (called a security policy) specifies who has what access to the WebLogic resource. Security policies (as well as roles) are instantiated for each level of the WebLogic resource hierarchy.
Notes: For more information about WebLogic resources, see WebLogic Resources and "Understanding WebLogic Security Policies" in Managing WebLogic Security.
Roles can be declarative (that is, Java 2 Enterprise Edition roles) or dynamically computed based on the context of the request. This dynamic computation of roles provides a very important benefit: users can be associated with a role based on business rules. For example, a user may be allowed to be in a manager role only while the actual manager is away on an extended business trip. Dynamically associating this 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 management group.
Note: You create dynamic role associations by defining role statements in the WebLogic Server Administration Console. For more information, see the sections under "Understanding Roles" in Managing WebLogic Security.
Dynamic role association is the term for this late binding of principals (that is, users or groups) to roles at runtime. The late binding occurs just prior to an authorization decision for a protected WebLogic resource, regardless of whether the principal-to-role association is statically defined or dynamically computed. Because of its placement in the invocation sequence, the result of any principal-to-role associations can be taken as an authentication identity, as part of the authorization decision made for the request.
Note: The association of roles for an authenticated user enhances the Role-Based Access Control (RBAC) security defined by the Java 2 Enterprise Edition (J2EE) specification.
The computed 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 associating roles that were statically defined through a deployment descriptor or through the WebLogic Server Administration Console.
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 role association (performed by the Role Mapping providers) is a set of roles that apply to the principals stored in a subject at a given moment. These 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 2 Enterprise Edition (J2EE) 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 8-1 shows how the Role Mapping providers interact with the WebLogic Security Framework to create dynamic role associations, and an explanation follows.
Figure 8-1 Role Mapping Providers and the Role Mapping Process
Generally, role mapping is performed in the following manner:
Note: A ContextHandler is a high-performing WebLogic class that allows a variable number of arguments to be passed as strings to a method. For more information about ContextHandlers, see the WebLogic Server 7.0 API Reference Javadoc for the ContextHandler interface.
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).
Note: For more information about subjects, see Users and Groups, Principals and Subjects. For more information about resource identifiers, see WebLogic Resource Identifiers.
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.)
The security policies are represented as a set of expressions or rules that are evaluated to determine if a given 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 2 Enterprise Edition (J2EE) deployment descriptors. For more information, see "Understanding WebLogic Security Policies" in Managing WebLogic Security.
Do You Need to Develop a Custom Role Mapping Provider?
The default (that is, active) security realm for WebLogic Server includes a WebLogic Role Mapping provider. The WebLogic Role Mapping provider determines dynamic roles for a specific user (subject) with respect to a specific protected WebLogic resource for each of the default users and WebLogic resources. The WebLogic Role Mapping provider supports the deployment and undeployment of roles within the system. The WebLogic Role Mapping provider uses the same security policy engine as the WebLogic Authorization provider. 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.
How to Develop a Custom Role Mapping Provider
If the WebLogic Role Mapping provider does not meet your needs, you can develop a custom Role Mapping provider by following these steps:
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:
Note: At least one Role Mapping provider in a security realm must implement the DeployableRoleProvider SSPI, or else it will be impossible to deploy Web applications and EJBs.
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:
For more information about the RoleProvider SSPI and the getRoleMapper method, see the WebLogic Server 7.0 API Reference Javadoc.
Implement the DeployableRoleProvider SSPI
To implement the DeployableRoleProvider SSPI, provide implementations for the methods described in Understand the Purpose of the "Provider" SSPIs, Implement the RoleProvider SSPI, and the following methods:
For more information about the DeployableRoleProvider SSPI and the deployRole and undeployRole methods, see the WebLogic Server 7.0 API Reference Javadoc.
To implement the RoleMapper SSPI, provide implementations for the following methods:
For more information about the RoleMapper SSPI and the getRoles methods, see the WebLogic Server 7.0 API Reference Javadoc.
Example: Creating the Runtime Class for the Sample Role Mapping Provider
Listing 8-1 shows the SampleRoleMapperProviderImpl.java class, which is the runtime class for the sample Role Mapping provider. This runtime class includes implementations for:
Note: The bold face code in Listing 8-1 highlights the class declaration and the method signatures.
Listing 8-1 SampleRoleMapperProviderImpl.java
package examples.security.providers.roles;
import java.security.Principal;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
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.WLSPrincipals;
import weblogic.security.service.ContextHandler;
import weblogic.security.spi.DeployableRoleProvider;
import weblogic.security.spi.Resource;
import weblogic.security.spi.RoleCreationException;
import weblogic.security.spi.RoleMapper;
import weblogic.security.spi.RoleRemovalException;
import weblogic.security.spi.SecurityServices;
public final class SampleRoleMapperProviderImpl implements DeployableRoleProvider, RoleMapper
{
private String description;
private SampleRoleMapperDatabase database;
private static final Map NO_ROLES = Collections.unmodifiableMap(new
HashMap(1));
public void initialize(ProviderMBean mbean, SecurityServices services)
{
System.out.println("SampleRoleMapperProviderImpl.initialize");
SampleRoleMapperMBean myMBean = (SampleRoleMapperMBean)mbean;
description = myMBean.getDescription() + "\n" + myMBean.getVersion();
database = new SampleRoleMapperDatabase(myMBean);
}
public String getDescription()
{
return description;
}
public void shutdown()
{
System.out.println("SampleRoleMapperProviderImpl.shutdown");
}
public RoleMapper getRoleMapper()
{
return this;
}
public Map getRoles(Subject subject, Resource resource, ContextHandler
handler)
{
System.out.println("SampleRoleMapperProviderImpl.getRoles");
System.out.println("\tsubject\t= " + subject);
System.out.println("\tresource\t= " + resource);
Map roles = new HashMap();
Set principals = subject.getPrincipals();
for (Resource res = resource; res != null; res = res.getParentResource())
{
getRoles(res, principals, roles);
}
getRoles(null, principals, roles);
if (roles.isEmpty()) {
return NO_ROLES;
}
return roles;
}
public void deployRole(Resource resource, String roleName, String[]
principalNames) throws RoleCreationException
{
System.out.println("SampleRoleMapperProviderImpl.deployRole");
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 undeployRole(Resource resource, String roleName) throws
RoleRemovalException
{
System.out.println("SampleRoleMapperProviderImpl.undeployRole");
System.out.println("\tresource\t= " + resource);
System.out.println("\troleName\t= " + roleName);
database.removeRole(resource, roleName);
}
private void getRoles(Resource resource, Set principals, Map roles)
{
for (Enumeration e = database.getRoles(resource); e.hasMoreElements();)
{
String role = (String)e.nextElement();
if (roleMatches(resource, role, principals))
{
roles.put(role, new SampleSecurityRoleImpl(role, "no description"));
}
}
}
private boolean roleMatches(Resource resource, String role, Set
principalsHave)
{
for (Enumeration e = database.getPrincipalsForRole(resource, role);
e.hasMoreElements();)
{
String principalWant = (String)e.nextElement();
if (principalMatches(principalWant, principalsHave))
{
return true;
}
}
return false;
}
private boolean principalMatches(String principalWant, Set principalsHave)
{
if (WLSPrincipals.getEveryoneGroupname().equals(principalWant) ||
(WLSPrincipals.getUsersGroupname().equals(principalWant) &&
!principalsHave.isEmpty()) || (WLSPrincipals.getAnonymousUsername().
equals(principalWant) && principalsHave.isEmpty()) ||
principalsContain(principalsHave, principalWant))
{
return true;
}
return false;
}
private boolean principalsContain(Set principalsHave, String
principalNameWant)
{
for (Iterator i = principalsHave.iterator(); i.hasNext();)
{
Principal principal = (Principal)i.next();
String principalNameHave = principal.getName();
if (principalNameWant.equals(principalNameHave))
{
return true;
}
}
return false;
}
}
Listing 8-2 shows the sample SecurityRole implementation that is used along with the SampleRoleMapperProviderImpl.java runtime class.
Listing 8-2 SampleSecurityRoleImpl.java
package examples.security.providers.roles;
import weblogic.security.service.SecurityRole;
public class SampleSecurityRoleImpl implements SecurityRole
{
private String _roleName;
private String _description;
private int _hashCode;
public SampleSecurityRoleImpl(String roleName, String description)
{
_roleName = roleName;
_description = description;
_hashCode = roleName.hashCode() + 17;
}
public boolean equals(Object secRole)
{
if (secRole == null)
{
return false;
}
if (this == secRole)
{
return true;
}
if (!(secRole instanceof SampleSecurityRoleImpl))
{
return false;
}
SampleSecurityRoleImpl anotherSecRole = (SampleSecurityRoleImpl)secRole;
if (!_roleName.equals(anotherSecRole.getName()))
{
return false;
}
return true;
}
public String toString () { return _roleName; }
public int hashCode () { return _hashCode; }
public String getName () { return _roleName; }
public String getDescription () { return _description; }
}
Generate an MBean Type Using the WebLogic MBeanMaker
Before you start generating an MBean type for your custom security provider, you should first:
When you understand this information and have made your design decisions, create the MBean type for your custom Role Mapping provider by following these steps:
Notes: Several sample security providers (available under "Code Direct" on the dev2dev Web site) illustrate how to perform these steps.
All instructions provided in this section assume that you are working in a Windows environment.
Create an MBean Definition File (MDF)
To create an MBean Definition File (MDF), follow these steps:
Note: A complete reference of MDF element syntax is available in MBean Definition File (MDF) Element Syntax.
Use the WebLogic MBeanMaker to Generate the MBean Type
Once you create your MDF, you are ready to run it through the WebLogic MBeanMaker. The WebLogic MBeanMaker is currently a command-line utility that takes as its input an MDF, and outputs some intermediate Java files, including an MBean interface, an MBean implementation, and an associated MBean information file. Together, these intermediate files form the MBean type for your custom security provider.
The instructions for generating an MBean type differ based on the design of your custom Role Mapping provider. Follow the instructions that are appropriate to your situation:
If the MDF for your custom Role Mapping provider does not include any custom operations, follow these steps:
java -DMDF=xmlfile -DFiles=filesdir -DcreateStubs=true weblogic.management.commo.WebLogicMBeanMaker
where xmlFile is the MDF (the XML MBean Description File) and filesdir is the location where the WebLogic MBeanMaker will place the intermediate files for the MBean type.
Whenever xmlfile is provided, a new set of output files is generated. If files already exist in the location specified by filesdir, you are informed that the existing files will be overwritten and are asked to confirm.
Each time you use the -DcreateStubs=true flag, it overwrites any existing MBean implementation file.
If the MDF for your custom Role Mapping provider does include custom operations, consider the following:
java -DMDF=xmlfile -DFiles=filesdir -DcreateStubs=true weblogic.management.commo.WebLogicMBeanMaker
where xmlFile is the MDF (the XML MBean Description File) and filesdir is the location where the WebLogic MBeanMaker will place the intermediate files for the MBean type.
Whenever xmlfile is provided, a new set of output files is generated. If files already exist in the location specified by filesdir, you are informed that the existing files will be overwritten and are asked to confirm.
Each time you use the -DcreateStubs=true flag, it overwrites any existing MBean implementation file.
java -DMDF=xmlfile -DFiles=filesdir -DcreateStubs=true weblogic.management.commo.WebLogicMBeanMaker
where xmlFile is the MDF (the XML MBean Description File) and filesdir is the location where the WebLogic MBeanMaker will place the intermediate files for the MBean type.
Whenever xmlfile is provided, a new set of output files is generated. If files already exist in the location specified by filesdir, you are informed that the existing files will be overwritten and are asked to confirm.
Each time you use the -DcreateStubs=true flag, it overwrites any existing MBean implementation file.
About the Generated MBean Interface File
The MBean interface file is the client-side API to the MBean that your runtime class or your MBean implementation will use to obtain configuration data. It is typically used in the initialize method as described in Understand the Purpose of the "Provider" SSPIs.
Because the WebLogic MBeanMaker generates MBean types from the MDF you created, the generated MBean interface file will have the name of the MDF, plus the text "MBean" appended to it. For example, the result of running the SampleRoleMapper MDF through the WebLogic MBeanMaker will yield an MBean interface file called SampleRoleMapperMBean.java.
Use the WebLogic MBeanMaker to Create the MBean JAR File (MJF)
Once your have run your MDF through the WebLogic MBeanMaker to generate your intermediate files, and you have edited the MBean implementation file to supply implementations for the appropriate methods within it, you need to package the MBean files and the runtime classes for the custom Role Mapping provider into an MBean JAR File (MJF). The WebLogic MBeanMaker also automates this process.
To create an MJF for your custom Role Mapping provider, follow these steps:
java -DMJF=jarfile -DFiles=filesdir weblogic.management.commo.WebLogicMBeanMaker
where jarfile is the name for the MJF and filesdir is the location where the WebLogic MBeanMaker looks for the files to JAR into the MJF.
Compilation occurs at this point, so errors are possible. If jarfile is provided, and no errors occur, an MJF is created with the specified name.
Notes: If you want to update an existing MJF, simply delete the MJF and regenerate it. The WebLogic MBeanMaker also has a -DIncludeSource option, which controls whether source files are included into the resulting MJF. Source files include both the generated source and the MDF itself. The default is false. This option is ignored when -DMJF is not used.
The resulting MJF can be installed into your WebLogic Server environment, or distributed to your customers for installation into their WebLogic Server environments.
Install the MBean Type Into the WebLogic Server Environment
To install an MBean type into the WebLogic Server environment, copy the MJF into the WL_HOME\server\lib\mbeantypes directory, where WL_HOME is the top-level installation directory for WebLogic Server. This "deploys" your custom Role Mapping provider—that is, it makes the custom Role Mapping provider manageable from the WebLogic Server Administration Console.
You can create instances of the MBean type by configuring your custom Role Mapping provider (see Configure the Custom Role Mapping Provider Using the Administration Console), and then use those MBean instances from a GUI, from other Java code, or from APIs. For example, you can use the WebLogic Server Administration Console to get and set attributes and invoke operations, or you can develop other Java objects that instantiate MBeans and automatically respond to information that the MBeans supply. We recommend that you back up these MBean instances. For more information, see "Backing Up Security Configuration Data" under "Recovering Failed Servers" in Creating and Configuring WebLogic Server Domains.
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:
Note: The steps for configuring a custom Role Mapping provider using the WebLogic Server Administration Console are described under "Configuring a Custom Security Provider" in Managing WebLogic Security.
Managing Role Mapping Providers and Deployment Descriptors
Some application components, such as Enterprise JavaBeans (EJBs) and Web applications, store relevant deployment information in Java 2 Enterprise Edition (J2EE) and WebLogic Server deployment descriptors. For Web applications, the deployment descriptor files (called web.xml and weblogic.xml) contain information for implementing the J2EE security model, including security role mappings. Typically, you will want to include this information when first configuring your Role Mapping providers in the WebLogic Server Administration Console.
The Administration Console provides an Ignore Security Data in Deployment Descriptors flag for this purpose, which you or an administrator should deselect the first time a custom Role Mapping provider is configured. (To locate this flag, click Security
Listing 8-3 Sample web.xml File
<?xml version="1.0" ?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
...
<context-param>
<param-name>HTTPS_PORT</param-name>
<param-value>7502</param-value>
</context-param>
...
<servlet>
<servlet-name>Security</servlet-name>
<servlet-class>com.beasys.commerce.ebusiness.security.
EncryptionServlet</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>Security</servlet-name>
<url-pattern>/security</url-pattern>
</servlet-mapping>
...
<session-config>
<session-timeout>15</session-timeout>
</session-config>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>Administration Tool Pages</web-resource-name>
<description>The Administration Tool Pages</description>
<url-pattern>/tools/catalog/*</url-pattern>
<url-pattern>/tools/content/*</url-pattern>
<url-pattern>/tools/order/*</url-pattern>
<url-pattern>/tools/property/*</url-pattern>
<url-pattern>/tools/usermgmt/*</url-pattern>
<url-pattern>/tools/util/*</url-pattern>
<url-pattern>/tools/webflow/*</url-pattern>
<url-pattern>/tools/*info.jsp</url-pattern>
<url-pattern>/repository/*</url-pattern>
<url-pattern>/security/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>Administrators</description>
<role-name>SystemAdminRole</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Portal Administration Tool Pages
</web-resource-name>
<description>The Portal Administration Tool Pages</description>
<url-pattern>/tools/portal/*</url-pattern>
<url-pattern>/tools/wlps_home.jsp</url-pattern>
<url-pattern>/repository/*</url-pattern>
<url-pattern>/security/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>Administrators</description>
<role-name>DelegatedAdminRole</role-name>
<role-name>SystemAdminRole</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
...
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<security-role>
<description>System Administrators</description>
<role-name>SystemAdminRole</role-name>
</security-role>
...
</web-app>
While you can set additional security role mappings in the web.xml/weblogic.xml deployment descriptors and in the Administration Console, BEA recommends that you copy the security role mappings defined in the Web application or EJB deployment descriptors once, then use the Administration Console to define subsequent security role mappings. This is because any changes made to the roles through the Administration Console during configuration of a Role Mapping provider will not be persisted to the web.xml and weblogic.xml files. Before you deploy the application again (which will happen if you redeploy it through the Administration Console, modify it on disk, or restart WebLogic Server), you should select the Ignore Security Data in Deployment Descriptors flag. If you do not, the security role mappings defined using the Administration Console will be overwritten by those defined in the deployment descriptors.
Note: The Ignore Security Data in Deployment Descriptors flag also affects Authorization providers and Credential Mapping providers. For more information, see Managing Authorization Providers and Deployment Descriptors and Managing Credential Mapping Providers, Resource Adapters, and Deployment Descriptors, respectively.
Enabling Security Role Deployment
If you implemented the DeployableRoleProvider SSPI and want to support deployable security roles with your custom Role Mapping provider, the person configuring the custom Role Mapping provider (that is, you or an administrator) must be sure that the Role Deployment Enabled flag 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 flag can be used to control which Role Mapping provider is used for security role deployment.
The Role Deployment Enabled flag performs the same function as the Ignore Security Data in Deployment Descriptors flag (described in Managing Role Mapping Providers and Deployment Descriptors), but is specific to Role Mapping providers.
Note: If both the Role Deployment Enabled flag and the Ignore Security Data in Deployment Descriptors flag are checked, the Ignore Security Data in Deployment Descriptors flag takes precedence. In other words, if the Ignore Security Data in Deployment Descriptors flag is checked, the Role Mapping provider will not do deployment even if its Role Deployment Enabled flag is checked.
Caution: Deploying a role for a WebLogic resource and role name that already exists will result in the role being overwritten.