Oracle® Containers for J2EE Security Guide 10g (10.1.3.5.0) Part Number E13977-01 |
|
|
View PDF |
This chapter discusses security issues affecting EJBs, covering the following topics:
Note that beginning with OC4J 10.1.3.x implementations, the EJB container supports the OracleAS JAAS Provider.
See Also:
Oracle Containers for J2EE Enterprise JavaBeans Developer's Guide for general information about EJBs and 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
"JAAS Authorization and OracleAS JAAS Provider JAAS Mode" and "Configuring and Using JAAS Mode" for information about JAAS mode, which can be used with EJB applications
Chapter 19, "Common Secure Interoperability Protocol" for information about CSIv2, used in conjunction with EJBs
The following Web site for OC4J "how-to" examples:
http://www.oracle.com/technology/tech/java/oc4j/1013/how_to/index.html
You can define security constraints and J2EE roles in the standard EJB deployment descriptor to protect your EJB methods. These J2EE roles can be linked to roles you define in your application, and then mapped to deployment roles in the security provider, as appropriate. (In the case of EJBs, a deployment role may correspond to a role in the backend database that the EJB will access, for example.) The mapping to deployment roles can be accomplished through Application Server Control during deployment, as described in "Specifying Security Role Mapping through Application Server Control", and results in appropriate configuration in the OC4J-specific deployment descriptors.
For authentication and authorization, this section focuses on XML configuration within the EJB deployment descriptors. EJB authorization is managed as follows:
The standard EJB deployment descriptor describes access rules using J2EE logical roles.
The OC4J-specific deployment descriptor maps the J2EE roles to deployment users and roles (configured in system-jazn-data.xml
, jazn-data.xml
, or Oracle Internet Directory, for example).
Note:
RMI lookup authentication is integrated with JAAS custom login modules. Refer to Chapter 9, "Login Modules" for information about login modules.Figure 18-1 provides an overview of EJB role definitions and role mapping (in this case for the file-based provider).
Figure 18-1 End-to-End Security Role Configuration
The steps for EJB authorization are described in the following sections:
For an application to access EJBs using RMI, you must grant RMI permission "login" to the appropriate user or role. Refer to "Permitting EJB RMI Client Access".
If an application contains an EJB, remote clients must be granted access for read (lookup) and write (bind) operations on the server-side JNDI context of the application, as required. Refer to "Configuring Namespace Access".
As shown in Figure 18-2 below, you can specify the name of a role (such as POMgr
) that is defined within your bean implementation, and link this name to the appropriate J2EE user or role (such as myMgr
) that is defined in the standard EJB deployment descriptor. (The next step, mapping to a deployment role, is reflected in the OC4J-specific deployment descriptor, as discussed in "Mapping J2EE Roles to Deployment Users and Roles".)
The following steps describe this in more detail:
Declare the application logical role, such as POMgr
above, with a <role-name>
subelement of <security-role-ref>
in the <enterprise-beans>
section in the standard EJB deployment descriptor. (For this example, assume this role has purchase order authority. A caller would have to be mapped into this role, as confirmed by an isCallerInRole()
call, to work with a purchase order.)
Use a <role-link>
subelement of <security-role-ref>
to link the application role to a desired J2EE logical role (which you will define in the next step, also in the standard EJB deployment descriptor). This functionality allows you to use your application in various J2EE environments without changing the bean code. The application role POMgr
is linked to the J2EE role myMgr
:
<enterprise-beans> ... <security-role-ref> <role-name>POMgr</role-name> <role-link>myMgr</role-link> </security-role-ref> ... </enterprise-beans>
(The J2EE role in the <role-link>
setting can be the same as a deployment role, or it can be mapped to a deployment role in a later step.)
Note:
The<security-role-ref>
element is required only when you use security context methods within your bean.Define the J2EE role and the EJB methods for which it has permissions in the standard EJB deployment descriptor. In this purchase order example, assume any method executed within a bean PurchaseOrder
must have authorized itself as myMgr
, a J2EE role that is declared through a <role-name>
subelement of <security-role>
. This is the J2EE role that was linked to the application role POMgr
in the previous step. Note that PurchaseOrder
is the name declared in the <ejb-name>
element, a subelement of the <session>
or <entity>
element.
The following example defines the role myMgr
and gives it permission to access all methods (as indicated by the "*
" symbol) of the EJB PurchaseOrder
bean:
<assembly-descriptor> ... <security-role> <description>Role for 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 OC4J maps POMgr
to myMgr
.
Note:
If you specify 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.Looking more closely at the <method-permission>
element: the <method>
subelement 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 take one of the following forms:
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>
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.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>java.lang.String</method-param> <method-param>java.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.
If you want certain methods to not be checked for security roles, use the standard EJB deployment descriptor to 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 empty <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.
You can specify in the standard EJB deployment descriptor 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 in the <enterprise-beans>
section. The following example indicates 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 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>
As noted earlier, you can define J2EE roles and related security constraints in the standard EJB deployment descriptor to protect your EJB methods. These J2EE roles can then be mapped to deployment users and roles that are defined in the security 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 discussion that follows.
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
While we recommend that you use Application Server Control for role mapping, the following discussion provides reference information for the resulting configuration in orion-ejb-jar.xml
when you map the J2EE role myMgr
to the deployment role managers
. Any user that can log in as part of the managers
role is considered to have permissions of the myMgr
role (which had previously been linked to the POMgr
application logical role), and can execute the methods of the PurchaseOrder
bean.
In the standard EJB deployment descriptor:
<assembly-descriptor> ... <security-role> <role-name>myMgr</role-name> </security-role> <method-permission> <role-name>myMgr</role-name> <method>...</method> </method-permission> ... </assembly-descriptor
In the OC4J-specific deployment descriptor:
<assembly-descriptor> ... <security-role-mapping name="myMgr"> <group name="managers" /> </security-role-mapping> ... </assembly-descriptor>
Alternatively, for mapping to a specific user:
<security-role-mapping name="myMgr"> <user name="guest" /> </security-role-mapping>
For mapping to a specific user within a specific role:
<security-role-mapping name="myMgr"> <group name="managers" /> <user name="guest" /> </security-role-mapping>
If an application contains an EJB, remote clients must be given namespace access to read (look up) and write (bind) objects as required on the server-side JNDI context of the application. "Read" and "write" correspond to the lookup()
and bind()
methods of a javax.naming.Context
object, respectively.
The remote client's user credentials (the JNDI properties passed to the remote client context) should map to one of the roles that are granted access to the JNDI context of the application.
The following example, which would appear in orion-application.xml
, shows how the namespace access is granted for read operations to roles named managers
and developers
.
<orion-application ... > ... <namespace-access> <read-access> <namespace-resource root=""> <security-role-mapping name="sr_developer"> <group name="developers"/> </security-role-mapping> <security-role-mapping name="myMgr"> <group name="managers"/> </security-role-mapping> </namespace-resource> </read-access> </namespace-access> ... </orion-application>
This assumes the indicated role mappings had already been set up elsewhere in orion-application.xml
.
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:
<assembly-descriptor> ... <default-method-access> <security-role-mapping name="<default-ejb-caller-role>" impliesAll="true" /> </default-method-access> ... </assembly-descriptor>
The default role is <default-ejb-caller-role>
, specified 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. A "true
" setting indicates that no security role checking occurs. A "false
" setting indicates that the container will check for this default role on these methods.
In the orion-ejb-jar.xml
file, the impliesAll
attribute has defaults as follows:
If <security-role-mapping>
is specified in orion-ejb-jar.xml
but impliesAll
is not set, then this attribute defaults to "false
" and the container checks for this default role on these methods.
If <security-role-mapping>
is not specified in orion-ejb-jar.xml
, the OC4J EJB layer defaults to a "true
" setting for impliesAll
and no security role checking occurs for 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>
or <group>
subelement. 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>
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 in client.jar
(standard J2EE client module).
Servlets or JavaBeans running within the container pass their credentials within the InitialContext
, which is created to look up the remote EJBs.
Note:
RMI lookup authentication is integrated with JAAS custom login modules. Refer to Chapter 9, "Login Modules" for information about login modules.When you access EJBs in a remote container, you must pass valid credentials to the container. Standalone clients define their credentials in the jndi.properties
file deployed with the client's code, using the following properties:
java.naming.security.principal=username java.naming.security.credentials=password
For example, if you want to access remote EJBs as POMGR/welcome
, set the properties as follows. 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");
Important:
Thejndi.properties
file must be accessible from the classpath.JavaBeans running within the container pass their credentials within the javax.naming.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
.For an application to access EJBs using RMI, you must grant RMI permission "login" to the appropriate user or role. You can accomplish this through the OracleAS JAAS Provider Admintool.
The following example sets this permission for a role (users
):
% java -jar jazn.jar -grantperm myrealm -role users \ com.evermind.server.rmi.RMIPermission login
And this example sets the permission for a user (JDOE_ENDUSER
):
% java -jar jazn.jar -grantperm myrealm -user JDOE_ENDUSER \ com.evermind.server.rmi.RMIPermission login
For the file-based provider, you can also grant this permission to a role 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".)
Restart OC4J for changes to take effect.
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";
Anonymous EJB lookup is a mode you may consider, presumably only during 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 generally discourages this practice, as it leaves EJBs completely unsecured.You can enable this mode as follows:
Confirm that the anonymous
user is configured in system-jazn-data.xml
, and that this user is activated, as described in "Predefined Accounts".
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 "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>
Give the role (users
in this example) appropriate namespace access so that it can execute read (lookup) and write (bind) operations on the server-side JNDI context of the application. 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="jndi-user-role"> <group name="administrators" /> <group name="users" /> </security-role-mapping> </namespace-resource> </read-access> <write-access> <namespace-resource root=""> <security-role-mapping name="jndi-user-role"> <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.
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:
Important:
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").
Subject propagation is supported only between OC4J 10.1.3.x instances.
OC4J supports subject propagation, as summarized in Figure 18-3. 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 subject (javax.security.auth.Subject
instance). Similarly, a remote EJB fat client can use this feature in calling to the EJB container.
After the client's current subject is obtained, through a Subject.getSubject()
call, subject propagation works as follows:
The subject is serialized over to the RMI server.
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 following steps are required in order to use subject propagation:
In OC4J, you can use subject propagation with ORMI if you specifically enable it on the client and server. (It is always enabled for IIOP, in accordance with the CSIv2 specification.) You can accomplish this with the following system property setting on the client and on the server:
-Dsubject.propagation=true
In the current release, this setting controls subject propagation at a global OC4J level.
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 <jazn>
element of the orion-application.xml
file, as discussed in "Introduction to JAAS Mode".
A propagated subject is accepted by the server only if the RMIPermission
subject.propagation
is granted to the EJB caller. The following example uses the OracleAS JAAS Provider Admintool to grant this permission to the user oc4jadmin
, so that this user will have its subject propagated to the server:
% java -jar jazn.jar -grantperm myrealm -user oc4jadmin \ com.evermind.server.rmi.RMIPermission subject.propagation
You can also grant subject.propagation
permission to a role. With the following example, any user in the users
role would have its subject propagated to the server:
% java -jar jazn.jar -grantperm myrealm -role users \ com.evermind.server.rmi.RMIPermission subject.propagation
You can restrict subject propagation by specifying the principal names that the server will accept in the subject. The following example again grants subject.propagation
permission to any user in the users
role, but the server will filter out all but the developer
and manager
principals from propagated subjects. (Note that the filtering is according to principal names, not principal types.)
% java -jar jazn.jar -grantperm myrealm -role users \ com.evermind.server.rmi.RMIPermission subject.propagation developer,manager
By default, there is no restriction—all principals in the subject are accepted. But you can also explicitly specify this with the subject.propagation
parameter "*"
(including the quotes):
% java -jar jazn.jar -grantperm myrealm -user oc4jadmin \ com.evermind.server.rmi.RMIPermission subject.propagation "*"
This is equivalent to the first example above.
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, as documented in "Tasks to Share a Library".
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 <host-access>
or <ip-access>
subelements (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 <host-access>
or <ip-access>
subelements (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"/>