Chapter 6. Jakarta Enterprise Beans Application Security
Chapter 6. Jakarta Enterprise Beans Application Security 6.1. Security Identity 6.1.1. About Jakarta Enterprise Beans Security Identity Jakarta Enterprise Beans can specify an identity to use when invoking methods on other components. This is the Jakarta Enterprise Beans security identity, also known as invocation identity. By default, the Jakarta Enterprise Beans uses its own caller identity. The identity can alternatively be set to a specific security role. Using specific security roles is useful when you want to construct a segmented security model, for example, restricting access to a set of components to internal Jakarta Enterprise Beans only. 6.1.2. Set the Security Identity of Jakarta Enterprise Beans The security identity of the Jakarta Enterprise Beans is specified through the <security-identity> tag in the security configuration. If no <security-identity> tag is present, the caller identity of the Jakarta Enterprise Beans is used by default. Example: Set the Security Identity of Jakarta Enterprise Beans to Be the Same as Its Caller This example sets the security identity for method invocations made by an Jakarta Enterprise Beans to be the same as the current caller's identity. This behavior is the default if you do not specify a <security-identity> element declaration. <ejb-jar> <enterprise-beans> <session> <ejb-name>ASessionBean</ejb-name> ... <security-identity> <use-caller-identity/> </security-identity> </session> ... </enterprise-beans> </ejb-jar> Example: Set the Security Identity of Jakarta Enterprise Beans to a Specific Role To set the security identity to a specific role, use the <run-as> and <role-name> tags inside the <security-identity> tag. <ejb-jar> <enterprise-beans> <session> <ejb-name>RunAsBean</ejb-name> ... <security-identity> <run-as> <description>A private internal role</description> <role-name>InternalRole</role-name> </run-as> </security-identity> </session> </enterprise-beans> ... </ejb-jar> By default, when you use <run-as> , a principal named anonymous is assigned to outgoing calls. To assign a different principal, uses the <run-as-principal> . <session> <ejb-name>RunAsBean</ejb-name> <security-identity> <run-as-principal>internal</run-as-principal> </security-identity> </session> Note You can also use the <run-as> and <run-as-principal> elements inside a servlet element. 6.2. Jakarta Enterprise Beans Method Permissions 6.2.1. About Jakarta Enterprise Beans Method Permissions Jakarta Enterprise Beans can restrict access to their methods to specific security roles. The Jakarta Enterprise Beans <method-permission> element declaration specifies the roles that can invoke the interface methods of the Jakarta Enterprise Beans. You can specify permissions for the following combinations: All home and component interface methods of the named Jakarta Enterprise Beans A specified method of the home or component interface of the named Jakarta Enterprise Beans A specified method within a set of methods with an overloaded name 6.2.2. Use Jakarta Enterprise Beans Method Permissions The <method-permission> element defines the logical roles that are allowed to access the Jakarta Enterprise Beans methods defined by <method> elements. Several examples demonstrate the syntax of the xml. Multiple method permission statements may be present, and they have a cumulative effect. The <method-permission> element is a child of the <assembly-descriptor> element of the <ejb-jar> descriptor. The XML syntax is an alternative to using annotations for Jakarta Enterprise Beans method permissions. Example: Allow Roles to Access All Methods of a Jakarta Enterprise Beans <method-permission> <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description> <role-name>employee</role-name> <role-name>temp-employee</role-name> <method> <ejb-name>EmployeeService</ejb-name> <method-name>*</method-name> </method> </method-permission> Example: Allow Roles to Access Certain Methods of a Jakarta Enterprise Beans and Limit Method Parameters <method-permission> <description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AcmePayroll bean </description> <role-name>employee</role-name> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>findByPrimaryKey</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>getEmployeeInfo</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>updateEmployeeInfo</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> </method-permission> Example: Allow Any Authenticated User to Access Methods of Jakarta Enterprise Beans Using the <unchecked/> element allows any authenticated user to use the specified methods. <method-permission> <description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description> <unchecked/> <method> <ejb-name>EmployeeServiceHelp</ejb-name> <method-name>*</method-name> </method> </method-permission> Example: Completely Exclude Specific Jakarta Enterprise Beans Methods <exclude-list> <description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description> <method> <ejb-name>EmployeeFiring</ejb-name> <method-name>fireTheCTO</method-name> </method> </exclude-list> Example: A Complete <assembly-descriptor> Containing Several <method-permission> Blocks <ejb-jar> <assembly-descriptor> <method-permission> <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description> <role-name>employee</role-name> <role-name>temp-employee</role-name> <method> <ejb-name>EmployeeService</ejb-name> <method-name>*</method-name> </method> </method-permission> <method-permission> <description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AcmePayroll bean </description> <role-name>employee</role-name> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>findByPrimaryKey</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>getEmployeeInfo</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>updateEmployeeInfo</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> </method-permission> <method-permission> <description>The admin role may access any method of the EmployeeServiceAdmin bean </description> <role-name>admin</role-name> <method> <ejb-name>EmployeeServiceAdmin</ejb-name> <method-name>*</method-name> </method> </method-permission> <method-permission> <description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description> <unchecked/> <method> <ejb-name>EmployeeServiceHelp</ejb-name> <method-name>*</method-name> </method> </method-permission> <exclude-list> <description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description> <method> <ejb-name>EmployeeFiring</ejb-name> <method-name>fireTheCTO</method-name> </method> </exclude-list> </assembly-descriptor> </ejb-jar> 6.3. Jakarta Enterprise Beans Security Annotations 6.3.1. About Jakarta Enterprise Beans Security Annotations Jakarta Enterprise Beans javax.annotation.security annotations are defined in the Jakarta Annotations 1.3 specification. Jakarta Enterprise Beans use security annotations to pass information about security to the deployer. These include: @DeclareRoles Declares which roles are available. @RunAs Configures the propagated security identity of a component. 6.3.2. Use Jakarta Enterprise Beans Security Annotations You can use either XML descriptors or annotations to control which security roles are able to call methods in your Jakarta Enterprise Beans. For information on using XML descriptors, see Use Jakarta Enterprise Beans Method Permissions . Any method values explicitly specified in the deployment descriptor override annotation values. If a method value is not specified in the deployment descriptor, those values set using annotations are used. The overriding granularity is on a per-method basis. Annotations for Controlling Security Permissions of Jakarta Enterprise Beans @DeclareRoles Use @DeclareRoles to define which security roles to check permissions against. If no @DeclareRoles is present, the list is built automatically from the @RolesAllowed annotation. @RolesAllowed, @PermitAll, @DenyAll Use @RolesAllowed to list which roles are allowed to access a method or methods. Use @PermitAll or @DenyAll to either permit or deny all roles from using a method or methods. @RunAs Use @RunAs to specify a role a method uses when making calls from the annotated method. Example: Security Annotations Example @Stateless @RolesAllowed({"admin"}) @SecurityDomain("other") public class WelcomeEJB implements Welcome { @PermitAll public String WelcomeEveryone(String msg) { return "Welcome to " + msg; } @RunAs("tempemployee") public String GoodBye(String msg) { return "Goodbye, " + msg; } public String GoodbyeAdmin(String msg) { return "See you later, " + msg; } } In this code, all roles can access method WelcomeEveryone . The GoodBye method uses the tempemployee role when making calls. Only the admin role can access method GoodbyeAdmin , and any other methods with no security annotation. 6.4. Remote Access to Jakarta Enterprise Beans 6.4.1. Use Security Realms with Remote Jakarta Enterprise Beans Clients One way to add security to clients which invoke Jakarta Enterprise Beans remotely is to use security realms. A security realm is a simple database of username/password pairs and username/role pairs. The terminology is also used in the context of web containers, with a slightly different meaning. To authenticate a specific username/password pair that exists in a security realm against Jakarta Enterprise Beans, follow these steps: Add a new security realm to the domain controller or standalone server. Configure the wildfly-config.xml file, which is located in the class path of the application, as shown in the following example: <configuration> <authentication-client xmlns="urn:elytron:client:1.2"> <authentication-rules> <rule use-configuration="default" /> </authentication-rules> <authentication-configurations> <configuration name="default"> <sasl-mechanism-selector selector="DIGEST-MD5" /> <set-user-name name="admin" /> <credentials> <clear-password password="password123!" /> </credentials> </configuration> </authentication-configurations> </authentication-client> <jboss-ejb-client xmlns="urn:jboss:wildfly-client-ejb:3.0"> <connections> <connection uri="remote+http://127.0.0.1:8080" /> </connections> </jboss-ejb-client> </configuration> Create a custom remoting connector on the domain or standalone server that uses your new security realm. Deploy your Jakarta Enterprise Beans to the server group which is configured to use the profile with the custom Remoting connector, or to your standalone server if you are not using a managed domain. 6.4.2. Add a New Security Realm Run the management CLI: Execute the jboss-cli.sh or jboss-cli.bat script and connect to the server. Create the new security realm itself: Run the following command to create a new security realm named MyDomainRealm on a domain controller or a standalone server. For a domain instance, use this command: For a standalone instance, use this command: Create a properties file named myfile.properties : For a standalone instance, create a file EAP_HOME /standalone/configuration/myfile.properties and for a domain instance, create a file EAP_HOME /domain/configuration/myfile.properties . These files need to have read and write access for the file owner. Create the references to the properties file which will store information about the new role: Run the following command to create a pointer to the myfile.properties file, which will contain the properties pertaining to the new role. Note The properties file will not be created by the included add-user.sh and add-user.bat scripts. It must be created externally. For a domain instance, use this command: For a standalone instance, use this command: Your new security realm is created. When you add users and roles to this new realm, the information will be stored in a separate file from the default security realms. You can manage this new file using your own applications or procedures. Note When using the add-user.sh script to add a user to a non-default file, other than application-users.properties , you have to pass it the argument --user-properties myfile.properties otherwise it will try to use application-users.properties . 6.4.3. Add a User to a Security Realm Run the add-user script. Open a terminal and change directories to the EAP_HOME /bin/ directory. If you are on Red Hat Enterprise Linux or any other UNIX-like operating system, run add-user.sh . If you are on Windows Server, run add-user.bat . Choose whether to add a management user or application user. For this procedure, type b to add an application user. Choose the realm the user will be added to. By default, the only available realm is ApplicationRealm . If you have added a custom realm, you may add the user to that instead. Type the username, password, and roles, when prompted. Type the desired username, password, and optional roles when prompted. Verify your choice by typing yes , or type no to cancel the changes. The changes are written to each of the properties files for the security realm. 6.4.4. Relationship Between Security Domains and Security Realms Important For Jakarta Enterprise Beans to be secured by security realms, they have to use a security domain which is configured to retrieve user credentials from the security realm. This means that the domain needs to contain the Remoting and RealmDirect login modules. Assigning a security domain is done by the @SecurityDomain annotation, which can be applied on an Jakarta Enterprise Beans. The other security domain retrieves the user and password data from the underlying security realm. This security domain is the default one if there is no @SecurityDomain annotation on the Jakarta Enterprise Beans but the Jakarta Enterprise Beans contains any of the other security-related annotations to be considered secured. The underlying http-remoting connector , which is used by the client to establish a connection, decides which security realm is used. For more information on http-remoting connector , see About the Remoting Subsystem in the JBoss EAP Configuration Guide . The security realm of the default connector can be changed this way: 6.4.5. About Remote Jakarta Enterprise Beans Access Using SSL Encryption By default, the network traffic for Remote Method Invocation (RMI) of EJB2 and Jakarta Enterprise Beans3 Beans is not encrypted. In instances where encryption is required, Secure Sockets Layer (SSL) can be utilized so that the connection between the client and server is encrypted. Using SSL also has the added benefit of allowing the network traffic to traverse some firewalls, depending on the firewall configuration. Warning Red Hat recommends that SSLv2, SSLv3, and TLSv1.0 be explicitly disabled in favor of TLSv1.1 or TLSv1.2 in all affected packages. 6.5. Elytron Integration with the ejb Subsystem Starting with JBoss EAP 7.1, it is possible to map deployments so that their security is handled by the elytron subsystem. If a deployment references a mapped security domain, its security will be handled by Elytron, otherwise its security will be handled by the legacy security subsystem. This mapping is defined in the ejb subsystem. Within the ejb subsystem, mappings are created from a security domain name, as referenced within a deployment, to a referenced Elytron security-domain. When a mapped security domain name is configured for a bean in a deployment, this indicates that security should be handled by Elytron. New Jakarta Enterprise Beans security interceptors are set up instead of the existing ones. The new Jakarta Enterprise Beans security interceptors make use of the Elytron SecurityDomain associated with the invocation to obtain the current SecurityIdentity and perform the following tasks: Establish the run-as principal. Create any extra roles for the run-as principal. Create the run-as roles. Make authorization decisions. JBoss EAP 7.1 introduced a new management resource in the ejb subsystem, application-security-domains . The application-security-domains element contains the application security domains that should be mapped to an Elytron security domain. Table 6.1. Attributes of the application-security-domain Attribute Description name This attribute refers to the name of the security domain as specified in a deployment. security-domain This attribute is a reference to the Elytron security domain that should be used. enable-jacc This attribute enables authorization using Jakarta Authorization. referencing-deployments This is a runtime attribute that lists all deployments currently referencing the ASD. legacy-compliant-principal-propagation This attribute determines the principal of the local unsecured Jakarta Enterprise Beans when the incoming run-as identity is not defined. If set to true , the principal of the local unsecured Jakarta Enterprise Beans is the current authenticated identity. If set to false , the principal of the local unsecured Jakarta Enterprise Beans is anonymous. This attribute is optional and the default value is 'true'. You can configure the application-security-domain in the ejb subsystem by using either the management console or the management CLI. For more information, see the following topics: Configure the Application Security Domain Using the Management Console Configure the Application Security Domain Using the Management CLI 6.5.1. Configure the Application Security Domain Using the Management Console Access the management console. For more information, see Management Console in the JBoss EAP Configuration Guide . Navigate to Configuration Subsystems EJB and click View . Select the Security Domain tab and configure application security domains as necessary. 6.5.2. Configure the Application Security Domain Using the Management CLI In the following example, MyAppSecurity is a security domain that is referenced in the deployment and ApplicationDomain is an Elytron security domain that has been configured in the elytron subsystem. The following XML is added to the ejb subsystem of the server configuration file as a result of this command. <application-security-domains> <application-security-domain name="MyAppSecurity" security-domain="ApplicationDomain"/> </application-security-domains> See the ejb-security quickstart that ships with JBoss EAP for a simple working example of an Jakarta Enterprise Beans that uses Elytron to handle security.
<ejb-jar> <enterprise-beans> <session> <ejb-name>ASessionBean</ejb-name> <security-identity> <use-caller-identity/> </security-identity> </session> </enterprise-beans> </ejb-jar> <ejb-jar> <enterprise-beans> <session> <ejb-name>RunAsBean</ejb-name> <security-identity> <run-as> <description>A private internal role</description> <role-name>InternalRole</role-name> </run-as> </security-identity> </session> </enterprise-beans> </ejb-jar> <session> <ejb-name>RunAsBean</ejb-name> <security-identity> <run-as-principal>internal</run-as-principal> </security-identity> </session> <method-permission> <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description> <role-name>employee</role-name> <role-name>temp-employee</role-name> <method> <ejb-name>EmployeeService</ejb-name> <method-name>*</method-name> </method> </method-permission> <method-permission> <description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AcmePayroll bean </description> <role-name>employee</role-name> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>findByPrimaryKey</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>getEmployeeInfo</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>updateEmployeeInfo</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> </method-permission> <method-permission> <description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description> <unchecked/> <method> <ejb-name>EmployeeServiceHelp</ejb-name> <method-name>*</method-name> </method> </method-permission> <exclude-list> <description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description> <method> <ejb-name>EmployeeFiring</ejb-name> <method-name>fireTheCTO</method-name> </method> </exclude-list> <ejb-jar> <assembly-descriptor> <method-permission> <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description> <role-name>employee</role-name> <role-name>temp-employee</role-name> <method> <ejb-name>EmployeeService</ejb-name> <method-name>*</method-name> </method> </method-permission> <method-permission> <description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AcmePayroll bean </description> <role-name>employee</role-name> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>findByPrimaryKey</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>getEmployeeInfo</method-name> </method> <method> <ejb-name>AcmePayroll</ejb-name> <method-name>updateEmployeeInfo</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </method> </method-permission> <method-permission> <description>The admin role may access any method of the EmployeeServiceAdmin bean </description> <role-name>admin</role-name> <method> <ejb-name>EmployeeServiceAdmin</ejb-name> <method-name>*</method-name> </method> </method-permission> <method-permission> <description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description> <unchecked/> <method> <ejb-name>EmployeeServiceHelp</ejb-name> <method-name>*</method-name> </method> </method-permission> <exclude-list> <description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description> <method> <ejb-name>EmployeeFiring</ejb-name> <method-name>fireTheCTO</method-name> </method> </exclude-list> </assembly-descriptor> </ejb-jar> @Stateless @RolesAllowed({"admin"}) @SecurityDomain("other") public class WelcomeEJB implements Welcome { @PermitAll public String WelcomeEveryone(String msg) { return "Welcome to " + msg; } @RunAs("tempemployee") public String GoodBye(String msg) { return "Goodbye, " + msg; } public String GoodbyeAdmin(String msg) { return "See you later, " + msg; } } <configuration> <authentication-client xmlns="urn:elytron:client:1.2"> <authentication-rules> <rule use-configuration="default" /> </authentication-rules> <authentication-configurations> <configuration name="default"> <sasl-mechanism-selector selector="DIGEST-MD5" /> <set-user-name name="admin" /> <credentials> <clear-password password="password123!" /> </credentials> </configuration> </authentication-configurations> </authentication-client> <jboss-ejb-client xmlns="urn:jboss:wildfly-client-ejb:3.0"> <connections> <connection uri="remote+http://127.0.0.1:8080" /> </connections> </jboss-ejb-client> </configuration> /host=master/core-service=management/security-realm=MyDomainRealm:add() /core-service=management/security-realm=MyDomainRealm:add() chmod 600 myfile.properties /host=master/core-service=management/security-realm=MyDomainRealm/authentication=properties:add(path=myfile.properties) /core-service=management/security-realm=MyDomainRealm/authentication=properties:add(path=myfile.properties) /subsystem=remoting/http-connector=http-remoting-connector:write-attribute(name=security-realm,value=MyDomainRealm) /subsystem=ejb3/application-security-domain=MyAppSecurity:add(security-domain=ApplicationDomain) <application-security-domains> <application-security-domain name="MyAppSecurity" security-domain="ApplicationDomain"/> </application-security-domains>