Skip Headers

Oracle® Containers for J2EE Security Guide 10g Release 3 (10.1.3) B14429-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# 14 EJB Security Configuration

This chapter discusses security issues affecting EJBs, covering the following topics:

- EJB JNDI Security Properties

- Configuring EJB Security

- Permitting EJB RMI Client Access

- Enabling and Configuring Subject Propagation for ORMI

Note that beginning with the OC4J 10.1.3 implementation, the EJB container supports the OracleAS JAAS Provider.

- See Also: Oracle Containers for J2EE Enterprise JavaBeans Developer's Guide for general information about EJBs Oracle Containers for J2EE Enterprise JavaBeans Developer's Guide also for information about EJB 3.0 security annotations Oracle Containers for J2EE Services Guide for information about ORMI "Enabling ORMIS for OC4J" (in this document) for information about ORMIS "Introduction to JAAS Mode" and "Use OracleAS JAAS Provider JAAS Mode" for information about JAAS mode, which can be used with EJB applications The following Web site for OC4J "how-to" examples:
      http://www.oracle.com/technology/tech/java/oc4j/1013/how_to/index.html

## EJB JNDI Security Properties

There are two JNDI properties that are specific to security. You can either set these within the `jndi.properties` file or within your client implementation.

### JNDI Properties in jndi.properties

If setting the JNDI properties within the `jndi.properties` file, set the properties as follows. Make sure that this `jndi.properties` file is accessible from the classpath.

When you access EJBs in a remote container, you must pass valid credentials to this container. standalone clients define their credentials in the `jndi.properties` file deployed with the client's code.

    java.naming.security.principal=username
    java.naming.security.credentials=password

### JNDI Properties within Implementation

JavaBeans running within the container pass their credentials within the `InitialContext` instance, which is created to look up the remote EJBs.

For example, to pass JNDI security properties within the `Hashtable` environment:

    Hashtable env = new Hashtable();
    env.put("java.naming.provider.url", "ormi://myhost/ejbsamples");
    env.put("java.naming.factory.initial",
            "oracle.j2ee.naming.ApplicationClientInitialContextFactory");
    env.put(Context.SECURITY_PRINCIPAL, "guest");
    env.put(Context.SECURITY_CREDENTIALS, "welcome");
    Context ic = new InitialContext (env);
    Object homeObject = ic.lookup("java:comp/env/employeeBean");

    // Narrow the reference to a TemplateHome.
    EmployeeHome empHome =
       (EmployeeHome) PortableRemoteObject.narrow(homeObject, EmployeeHome.class);

Note: `ApplicationClientInitialContextFactory` is in the file `oc4jclient.jar`.

## Configuring EJB Security

EJB security involves two realms: granting permissions if you download into a browser, and configuring your application for authentication and authorization. This section covers the following:

- Granting Permissions in the Browser

- Authenticating and Authorizing EJB Applications

- Specifying Credentials in EJB Clients

- Configuring Anonymous EJB Lookup

### Granting Permissions in the Browser

If you download the EJB application as a client where the security manager is active, you must grant the following permissions before you can execute:

    permission java.net.SocketPermission "*:*", "connect,resolve";
    permission java.lang.RuntimePermission "createClassLoader";
    permission java.lang.RuntimePermission "getClassLoader";
    permission java.util.PropertyPermission "*", "read";
    permission java.util.PropertyPermission "LoadBalanceOnLookup", "read,write";

### Authenticating and Authorizing EJB Applications

You can define security constraints and J2EE security roles in the EJB deployment descriptor to protect your EJB methods (or in the `orion-application.xml` descriptor for the overall J2EE application). These J2EE security roles must be mapped to deployment users and roles in the OracleAS JAAS Provider. This security role mapping can be accomplished through Application Server Control during deployment, as described in "Specifying Security Role Mapping through Application Server Control".

For authentication and authorization, this section focuses on XML configuration within the EJB deployment descriptors. EJB authorization is specified within the EJB and OC4J-specific deployment descriptors. You can manage the authorization piece of your security within the deployment descriptors, as follows:

- The EJB deployment descriptor describes access rules using logical roles.

- The OC4J-specific deployment descriptor maps the logical roles to deployment users and roles, made available to OC4J through the OracleAS JAAS Provider.

Users and roles are identities known by the container. Roles are the logical identities each application uses to indicate access rights to its different objects. The user name / password pairs can be digital certificates and, in the case of SSL, private key pairs.

Thus, the definition and mapping of roles is demonstrated in Figure 14-1.

Figure 14-1 End-to-End Security Role Configuration

Description of "Figure 14-1 End-to-End Security Role Configuration"

Defining users and roles are discussed in the following sections:

- Specifying Logical Roles in the EJB Deployment Descriptor

- Specifying Unchecked Security for EJB Methods

- Specifying the Run-As Security Identity

- Mapping Logical Roles to Users and Roles

- Specifying a Default Role Mapping for Undefined Methods

#### Specifying Logical Roles in the EJB Deployment Descriptor

As shown in Figure 14-2, you can use a logical name for a role within your bean implementation, and map this logical name to the correct security role or user. The mapping of the logical name to a database role is specified in the OC4J-specific deployment descriptor. See "Mapping Logical Roles to Users and Roles" for more information.

Figure 14-2 Security Role References

Description of "Figure 14-2 Security Role References"

If you use a logical name for a database role within your bean implementation for methods such as `isCallerInRole()`, you can map the logical name to an actual database role by doing the following:

1. Declare the logical name within the `<enterprise-beans>` section in a `<security-role-ref>` element. For example, to define a role used within the purchase order example, you may have checked within the bean implementation to see if the caller had authorization to sign a purchase order. Thus, the caller would have to be signed in under a correct role. For the bean to not require awareness of database roles, you can check `isCallerInRole()` on a logical name, such as `POMgr`, because only purchase order managers can sign off on the order. Thus, you would specify the logical security role, `POMgr`, in the `<role-name>` subelement of a `<security-role-ref>` element within the `<enterprise-beans>` section, as follows:

       <enterprise-beans>
         ...
         <security-role-ref>
          <role-name>POMgr</role-name>
          <role-link>myMgr</role-link>
         </security-role-ref>
         ...
       </enterprise-beans>

   The `<role-link>` setting within the `<security-role-ref>` element can be the actual database role, which is defined further within the `<assembly-descriptor>` section. Alternatively, it can be another logical name, which is still defined more in the `<assembly-descriptor>` section and is mapped to an actual database role within the Oracle-specific deployment descriptor.

   Note: The `<security-role-ref>` element is required only when you use security context methods within your bean.

2. Define the role and the methods that it applies to. In the purchase order example, any method executed within the `PurchaseOrder` bean must have authorized itself as `myMgr`. Note that `PurchaseOrder` is the name declared in the ```<ejb-name>` element, a subelement of the `<session>` or `<entity>` element.

   Thus, the following defines the role as `myMgr`, the EJB as `PurchaseOrder`, and all methods by denoting the "`*`" symbol.

   Note: The `myMgr` role in the `<security-role>` element is the same as the `<role-link>` setting within the `<enterprise-beans>` section. This ties the logical name of `POMgr` to the `myMgr` definition.

       <assembly-descriptor>
        <security-role>
         <description>Role needed purchase order authorization</description>
         <role-name>myMgr</role-name>
        </security-role>
        <method-permission>
         <role-name>myMgr</role-name>
         <method>
          <ejb-name>PurchaseOrder</ejb-name>
          <method-name>*</method-name>
         </method>
        </method-permission>
       ...
       </assembly-descriptor>

After performing both steps, you can refer to `POMgr` within the bean implementation, and the container translates `POMgr` to `myMgr`.

Note: If you define different roles within the `<method-permission>` element for methods in the same EJB, the resulting permission is a union of all the method permissions defined for the methods of this bean.

The `<method>` subelement of `<method-permission>` is used to specify the security role for one or more methods within an interface or implementation. According to the EJB specification, this definition can be of one of the following forms:

1. Defining all methods within a bean by specifying the bean name and using the "`*`" character to denote all methods within the bean, as follows:

       <method-permission>
         <role-name>myMgr</role-name>
         <method>
           <ejb-name>EJBNAME</ejb-name>
           <method-name>*</method-name>
         </method>
       </method-permission>

2. Defining a specific method that is uniquely identified within the bean. Use the appropriate interface name and method name, as follows:

       <method-permission>
         <role-name>myMgr</role-name>
         <method>
           <ejb-name>myBean</ejb-name>
           <method-name>myMethodInMyBean</method-name>
         </method>
       </method-permission>

   Note: If there are multiple methods with the same overloaded name, the element of this style refers to all the methods with the overloaded name.

3. Defining a method with a specific signature among many overloaded versions, as follows:

       <method-permission>
         <role-name>myMgr</role-name>
         <method>
             <ejb-name>myBean</ejb-name>
          <method-name>myMethod</method-name>
          <method-params>
             <method-param>javax.lang.String</method-param>
             <method-param>javax.lang.String</method-param>
          </method-params>
         </method>
       </method-permission>

   The parameters are the fully-qualified Java types of the input parameters of the method. If the method has no input arguments, the <`method-params`> element contains no subelements.

#### Specifying Unchecked Security for EJB Methods

If you want certain methods to not be checked for security roles, you define these methods as unchecked, as follows:

    <method-permission>
      <unchecked/>
      <method>
         <ejb-name>EJBNAME</ejb-name>
         <method-name>*</method-name>
      </method>
    </method-permission>

Instead of defining a `<role-name>` element, you define an `<unchecked/>` element. When executing any methods in the `EJBNAME` bean, the container does not check for security. Unchecked methods always override any other role definitions.

#### Specifying the Run-As Security Identity

You can specify that all methods of an EJB execute under a specific identity. That is, the container does not check different roles for permission to run specific methods; instead, the container executes all of the EJB methods under the specified security identity. You can specify a particular role or the caller identity as the security identity.

Specify the "run-as" security identity in the `<security-identity>` element, which is contained in the `<enterprise-beans>` section. The following XML demonstrates that `POMgr` is the role under which all the entity bean methods execute:

    <enterprise-beans>
     <entity>
     ...
      <security-identity>
         <run-as>
            <role-name>POMgr</role-name>
         </run-as>
      </security-identity>
    ...
     </entity>
    </enterprise-beans>

Alternatively, the following XML example demonstrates how to specify that all methods of the bean execute under the identity of the caller:

    <enterprise-beans>
     <entity>
     ...
      <security-identity>
         <use-caller-identity/>
      </security-identity>
    ...
     </entity>
    </enterprise-beans>

#### Mapping Logical Roles to Users and Roles

As noted earlier, you can define security constraints and J2EE security roles in the EJB deployment descriptor to protect your EJB methods. These J2EE security roles must be mapped to deployment users and roles in the OracleAS JAAS Provider. This security role mapping can be accomplished through Application Server Control during deployment, as described in "Specifying Security Role Mapping through Application Server Control".

Mappings are reflected in `<security-role-mapping>` settings in Oracle-specific descriptors, as shown in the examples that follow.

See Also: Oracle Containers for J2EE Developer's Guide for information about the `orion-application.xml` file Oracle Containers for J2EE Enterprise JavaBeans Developer's Guide for information about the `orion-ejb-jar.xml` file

Example 14-1 Mapping Logical Role to Actual Role

While we recommend that you use Application Server Control for role mapping, this example provides reference information for the resulting configuration in `orion-ejb-jar.xml` when you map the logical role `POMGR` to the `managers` role. Any user that can log in as part of this role is considered to have the `POMGR` role, and so can execute the methods of `PurchaseOrderBean`.

    <security-role-mapping name="POMGR">
      <group name="managers" />
    </security-role-mapping>

For mapping to a specific user:

    <security-role-mapping name="POMGR">
     <user name="guest" />
    </security-role-mapping>

For mapping to a specific user within a specific role:

    <security-role-mapping name="POMGR">
     <group name="managers" />
     <user name="guest" />
    </security-role-mapping>

As shown in Figure 14-3, the logical role name for `POMGR` defined in the EJB deployment descriptor is mapped to `managers` within the OC4J-specific deployment descriptor, in the `<security-role-mapping>` element.

Figure 14-3 Security Role Mapping

Description of "Figure 14-3 Security Role Mapping"

Notice that the `<role-name>` setting in the EJB deployment descriptor is the same as for the `name` attribute in the `<security-role-mapping>` element in the OC4J-specific deployment descriptor. This is what identifies the mapping.

#### Specifying a Default Role Mapping for Undefined Methods

If any methods have not been associated with a role mapping, they are mapped to the default security role through the `<default-method-access>` element in the `orion-ejb-jar.xml` file. The following is the automatic mapping for any unsecured methods:

    <default-method-access>
       <security-role-mapping name="&lt;default-ejb-caller-role&gt;"
                              impliesAll="true" />
    </default-method-access>

The default role is `<default-ejb-caller-role>` and is defined in the `name` attribute. You can replace this string with any name for the default role. The `impliesAll` attribute indicates whether any security role checking occurs for these methods. This attribute defaults to "`true`", which states that no security role checking occurs for these methods. If you set this attribute to "`false`", the container will check for this default role on these methods.

If the `impliesAll` attribute is "`false`", you must map the default role defined in the `name` attribute to a deployment user or role through the `<user>` and `<group>` elements. The following example shows how all methods not associated with a method permission are mapped to the "`others`" role.

    <default-method-access>
       <security-role-mapping name="default-role" impliesAll="false" />
          <group name="others" />
       </security-role-mapping>
    </default-method-access>

### Specifying Credentials in EJB Clients

When you access EJBs in a remote container, you must pass valid credentials to this container.

- Standalone clients define their credentials in the `jndi.properties` file deployed with the EAR file.

- Servlets or JavaBeans running within the container pass their credentials within the `InitialContext`, which is created to look up the remote EJBs.

#### Credentials in JNDI Properties

Indicate the user name (principal) and password (credentials) to use when looking up remote EJBs in the `jndi.properties` file.

For example, if you want to access remote EJBs as `POMGR/welcome`, define the following properties. The `java.naming.factory.initial` setting indicates that you will use the Oracle JNDI implementation:

    java.naming.security.principal=POMGR
    java.naming.security.credentials=welcome
    java.naming.factory.initial=
                        oracle.j2ee.naming.ApplicationClientInitialContextFactory
    java.naming.provider.url=ormi://myhost/ejbsamples

In your application program, authenticate and access the remote EJBs as shown in the following example:

    InitialContext ic = new InitialContext();
    CustomerHome =
       (CustomerHome)ic.lookup("java:comp/env/purchaseOrderBean");

#### Credentials in the InitialContext

To access remote EJBs from a servlet or JavaBean, pass the credentials in the `InitialContext` object as follows:

    Hashtable env = new Hashtable();
    env.put("java.naming.provider.url", "ormi://myhost/ejbsamples");
    env.put("java.naming.factory.initial",
            "oracle.j2ee.naming.ApplicationClientInitialContextFactory");
    env.put(Context.SECURITY_PRINCIPAL, "POMGR");
    env.put(Context.SECURITY_CREDENTIALS, "welcome");
    Context ic = new InitialContext (env);
    CustomerHome = (CustomerHome)ic.lookup("java:comp/env/purchaseOrderBean");

### Configuring An onymous EJB Lookup

Anonymous EJB lookup is a mode you may consider, presumably only during early development or very special circumstances. In this mode, you do not specify the principal and credential when creating the `InitialContext`, and therefore do not have to specify a principal or credential to remotely access EJBs. Your `jndi.properties` file would look like this:

    java.naming.factory.initial=
       oracle.j2ee.naming.ApplicationClientInitialContextFactory
    java.naming.provider.url=ormi://localhost:23791/ejb30slsb
    java.naming.security.principal=
    java.naming.security.credentials=

Important: Oracle strongly discourages this practice, except in special circumstances, as it leaves EJBs completely unsecured.

You can enable this mode as follows:

1. Confirm that the `anonymous` user is configured in `system-jazn-data.xml`, and that this user is activated, as described in "Predefined OC4J Accounts".

2. Also in `system-jazn-data.xml`, under the appropriate realm, assign the `anonymous` user to a role that has been granted RMI permissions, as described in the next section, "Permitting EJB RMI Client Access". For example, assuming the `users` role is granted RMI permissions:

       <jazn-data>
          ...
          <jazn-realm>
             <realm>
                <name>myrealm</name>
                ...
                <roles>

                   <role>
                      <name>users</name>
                      <members>
                         <member>
                            <type>user</type>
                            <name>anonymous</name>
                         </member>
                      </members>
                   </role>
                   ...
                </roles>
                ...
             </realm>
             ...
          </jazn-realm>
          ...
       </jazn-data>

3. Give the role (`users` in this example) appropriate namespace access so that it can execute read and write operations on the EJB. Use configuration such as the following in the `orion-application.xml` file for the application:

       <orion-application>
          ...
          <namespace-access>
             <read-access>
                <namespace-resource root="">
                   <security-role-mapping name="&lt;jndi-user-role&gt;">
                      <group name="administrators" />
                      <group name="users" />
                   </security-role-mapping>
                </namespace-resource>
             </read-access>
             <write-access>
                <namespace-resource root="">
                   <security-role-mapping name="&lt;jndi-user-role&gt;">
                      <group name="administrators" />
                      <group name="users" />
                   </security-role-mapping>
                </namespace-resource>
             </write-access>
          </namespace-access>
          ...
       </orion-application>

With this configuration, you can access remote EJBs without specifying principals or credentials.

## Permitting EJB RMI Client Access

To enable fat client access to EJBs using RMI, you must grant RMI permission "login" to the appropriate role. You can accomplish this in one of the following ways:

- For the file-based provider, through Application Server Control by selecting the role and checking the "Grant RMI Permission" checkbox. (Also refer to "Create a Role" or "Edit a Role".)

- Or through the OracleAS JAAS Provider Admintool:

      % java -jar jazn.jar -grantperm myrealm -role myrole \
             com.evermind.server.rmi.RMIPermission login

Restart OC4J for changes to take effect.

For an application to access EJBs, you must create the end user `JDOE_ENDUSER` in the `system-jazn-data.xml` file and grant it RMI permission "login".

See Also: Appendix C, "OracleAS JAAS Provider Admintool Reference"

## Enabling and Configuring Subject Propagation for ORMI

This section discusses subject propagation in OC4J, and documents how to enable it with ORMI. (It is always used with IIOP, in accordance with the CSIv2 specification.) The following topics are covered:

- Overview of Subject Propagation in OC4J

- Enabling Subject Propagation for ORMI

- Sharing Principal Classes for Subject Propagation

- Removing and Configuring Subject Propagation Restrictions

Note: Subject propagation is a powerful feature that should be used only in environments where the server is secure from untrusted client access. It is therefore advised, in order to ensure proper integrity of client requests, that appropriate safeguards be established before this feature is used in production environments. For example, consider using application or network firewalls, RMI access restrictions (through the `<access-mask>` element in `rmi.xml`, as documented in "Configuring ORMIS Access Restrictions"), or RMI subject-propagation restrictions (through the `<subject-propagation-mask>` element in `rmi.xml`, as documented in "Removing and Configuring Subject Propagation Restrictions").

### Overview of Subject Propagation in OC4J

OC4J supports subject propagation, as summarized in Figure 14-4. Through this feature, a Web client can establish its identity to a servlet, and the servlet can then use that identity to communicate with other EJBs and servlets, where the identity is the appropriate JAAS subject (`javax.security.auth.Subject` instance).

Figure 14-4 Subject Propagation

Description of "Figure 14-4 Subject Propagation"

After the client's current subject is obtained, through a `Subject.getSubject()` call, subject propagation works as follows:

1. The subject is serialized over to the RMI server.

2. The RMI server deserializes the subject and uses it to set up the server-side JAAS context.

Subjects may be propagated through a series of EJB invocations, for example. The EJB incorporates the client identity if the EJB is configured to use the client's identity. The EJB cannot be configured to use run-as mode with a specific role.

The authenticated subject (from supplied JNDI credentials) is then merged with the propagated subject to form a combined subject.

### Enabling Subject Propagation for ORMI

In OC4J, you can use subject propagation with ORMI if you specifically enable it on the client and server. You can accomplish this with the following system property setting at each end:

    -Dsubject.propagation=true

In the current release, this setting controls subject propagation at a global OC4J level.

Be aware that for subject propagation to work properly, JAAS mode must be enabled for the Web application where the subject is being propagated from, and for the EJB where the subject is being propagated to. So for each, there must be a setting of `jaas-mode="doAs"` or `jaas-mode="doAsPrivileged"` in the `orion-application.xml` file.

See Also: "Introduction to JAAS Mode"

### Sharing Principal Classes for Subject Propagation

While `java.security.Subject` is a class provided with the JDK, `java.security.Principal` is an interface that you can implement as desired. For subject propagation to work properly with ORMI, you must ensure that the remote client, application, and OC4J all have access to any `Principal` class definitions.

You can accomplish this by putting them in a library that is loaded as an OC4J shared library. There are two main steps to this (considering functionality of the Application Server Control Console in particular):

1. Load the library as an OC4J shared library. From the Application Server Control Console Administration tab for the OC4J instance, use the Shared Libraries task.

   This results in configuration such as the following in the OC4J `server.xml` file:

       <application-server ... >
          ...
          <shared-library name="mylib.jar" version="1.0" library-compatible="true">
             <code-source path="../mypath" />
          </shared-library>
          ...
       </application-server>

2. Import the library into your application. In deploying an application through Application Server Control, when you reach the Deploy: Deployment Settings page (as discussed in "Deploying an Application through Application Server Control"), you have the opportunity to import shared libraries.

   This results in configuration such as the following in your application `orion-application.xml` file:

       <orion-application ... >
          ...
          <imported-shared-libraries>
             <import-shared-library name="mylib.jar" />
             ...
          </imported-shared-libraries>
          ...
       </orion-application>

Note: This is the preferred way to use shared libraries in OC4J; however, the `<library>` element and `ORACLE_HOME``/j2ee/home/applib` directory are still supported.

See Also: Oracle Containers for J2EE Developer's Guide for more information about OC4J class loading and shared libraries

### Removing and Configuring Subject Propagation Restrictions

By default, access to subject propagation is denied to all ORMI clients. You can configure desired access through settings in the `<subject-propagation-mask>` element and its `<host-access>` and `<ip-access>` subelements in `rmi.xml`.

Subject propagation access can be either exclusive or inclusive:

- In the exclusive mode, access is denied to all IP addresses or hosts except those specifically included. Use `mode="deny"` in `<subject-propagation-mask>`, then specify which particular hosts or IP addresses to allow by using `mode="allow"` in a `<host-access>` subelement, `<ip-access>` subelement, or both.

- In the inclusive mode, access is available to all IP addresses or hosts except those specifically excluded. Use `mode="allow"` in `<subject-propagation-mask>`, then specify which particular hosts or IP addresses to deny by using `mode="deny"` in a `<host-access>` subelement, `<ip-access>` subelement, or both.

The following example configures an exclusive mode, allowing subject propagation for only `localhost` and `192.168.1.0`. (`255.255.255.0` is the applicable subnet mask.)

    <rmi-server ... >
       ...
       <subject-propagation-mask default="deny">
          <host-access domain="localhost" mode="allow"/>
          <ip-access ip="192.168.1.0" netmask="255.255.255.0" mode="allow"/>
       </subject-propagation-mask>
       ...
    </rmi-server>

The default setting is as follows:

    <subject-propagation-mask default="deny"/>