|
EJBs can be secured similarly to Web resources. Once again the spec encourages you to use declarative security defined in the deployment descriptor for the EJB jar. Every EJB that you want to secure has to be locked down individually. There's no group function like there is for HTTP resources. Every method of the EJB, and therefore all the methods of the remote and home interface, can be secured for one or more roles. Each used role has to be defined as a security role in the EJB jars descriptor. At deployment time, each role must be mapped to a physical user or group in your server, just like it is done for WARs. In our example, if you want to allow ROLE1 to access the "callMe method of SBEjb1", you have to add the role to the EJB jars descriptor, and then add a method permission for the SBEjb1.callMe method.
- Open the EJB jars deployment descriptor
right click on EJB1.jar in the navigation tree and choose "Open Deployment Descriptor"
- Open the application assembly node, and add a role
right click on "Roles" and choose "Add"
right click on "UntitledRole" and choose "Properties"
name the role "ROLE2"
- Add the method permission for the SBEjb1's callMe method
right click on "Method Permission" and choose "Add"
right click on "UntitledPermission" and choose "Properties"
name it SBEjb1_callMe, add the "ROLE2" to roles, and "SBEJB1:callMe" to methods
The resulting ejb-jar.xml would look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>SBEjb1</ejb-name>
<home>ejb1.SBEjb1Home</home>
<remote>ejb1.SBEjb1</remote>
<ejb-class>ejb1.SBEjb1Bean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name>ROLE2</role-name>
</security-role>
<method-permission>
<description>SBEjb1_callMe</description>
<role-name>ROLE2</role-name>
<method>
<ejb-name>SBEjb1</ejb-name>
<method-name>callMe</method-name>
</method>
</method-permission>
</assembly-descriptor>
<ejb-client-jar>EJB1-client.jar</ejb-client-jar>
</ejb-jar>
To allow another role to access the callMe method, all you need to do is to add the role as a security role, and then add that role as a role name to the method permission.
....
....
<assembly-descriptor>
<security-role>
<role-name>ADMINS</role-name>
</security-role>
<security-role>
<role-name>ROLE2</role-name>
</security-role>
<method-permission>
<description>SBEjb1_callMe</description>
<role-name>ADMINS</role-name>
<role-name>ROLE2</role-name>
<method>
<ejb-name>SBEjb1</ejb-name>
<method-name>callMe</method-name>
</method>
</method-permission>
</assembly-descriptor>
....
....
Programmatic Security
In the event that you need programmatic security, the "javax.ejb.EJBContext" exposes two methods for this. Actually, this spec names two more methods, but they are deprecated. The two that aren't deprecated are as follows:
- getCallerPrincipal
- isCallerInRole
Yes, they're exactly the same as for the HttpServletRequest. But there's one significant difference. Here, you can link the coded role name to a descriptor role name in the deployment descriptor. This way, you can assemble several beans that use different role names in their code to one logical role. That role can later, at deployment time, be mapped to a user or group. This is particularly helpful when you assemble beans from different providers, and every provider uses a different role name in their code. However, in case you decide to use the same role name that is used in the bean's code, you will still need to enter the role name and role link.
Here's an sample code descriptor that uses "ROLE2ref", which is linked to ROLE2:
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>SBEjb1</ejb-name>
<home>ejb1.SBEjb1Home</home>
<remote>ejb1.SBEjb1</remote>
<ejb-class>ejb1.SBEjb1Bean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>
<security-role-ref>
<role-name>ROLE2ref</role-name>
<role-link>ROLE2</role-link>
</security-role-ref>
</session>
</enterprise-beans>
<assembly-descriptor>
<security-role>
<role-name>ADMINS</role-name>
</security-role>
<security-role>
<role-name>ROLE2</role-name>
</security-role>
<method-permission>
<description>allSBEjb1</description>
<role-name>ADMINS</role-name>
<method>
<ejb-name>SBEjb1</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
</assembly-descriptor>
<ejb-client-jar>EJB1-client.jar</ejb-client-jar>
</ejb-jar>
To achieve this, follow these steps:
- Open the deployment descriptor and a role reference to SBEjb1
right click on "Environment" under the "SBEjb1" node and choose "Add Role Reference"
right click on "UntitledRoleReference" and choose "Properties"
name the reference "ROLE2ref" and link it to "ROLE2"
(Since we already added the ROLE2 role, we're done.)
To see how the role reference works, add this sample code to the SBEjb1.callMe method:
public String callMe( String msg )
{
System.out.println("is user in role ? " + m_sessionContext.isCallerInRole("ROLE2ref"));
return "<B>" + msg + "</B>";
}
Now all we have to do is deploy the EAR.
Experiment with these new security settings yourself. Create some users and groups (or use existing ones) and change the mapping in your deployment plan.
|