Declarative Security

The JAAS security framework, in JBoss (JBossSX) or other EJB containers provides authentication and authorization for components in EJB 3.0 applications. The EJB3 cartridge supports declarative role based security for this security framework.

Currently, the EJB3 cartridge uses metadata annotations to declare security related information. It would just as easy to swap this information to the deployment descriptor to setup the security policies.

Configuration

Enabling security for the EJB3 cartridge is similar to the EJB/hibernate cartridges. All that is required is to uncomment the securityRealm property in your AndroMDA build configuration (andromda.xml). The ejb3 namespace section will look something like the following.

        <namespace name="ejb3">
            <properties>
                ...
                <!-- uncomment to enable EJB security -->
                <property name="securityRealm">${application.id}</property>
                ...
            </properties>
        </namespace>

Once you have done that, the cartridge will create the login-config.xml and and login-service.xml deployment descriptors for JBoss. Both files are generated to the ear META-INF directory. The login-config.xml will look like:

<?xml version="1.0" encoding="UTF-8"?>
<policy>
    <application-policy name="howtomodel">
        <authentication>
            <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule"
                          flag="required">
                <module-option name="debug">true</module-option>
                <module-option name="unauthenticatedIdentity">guest</module-option>
                <module-option name="dsJndiName">java:/jdbc/howtomodel</module-option>
                <module-option name="principalsQuery">
                    SELECT PASSWORD 'Password' FROM principal WHERE BINARY PRINCIPAL_ID =?
                </module-option>
                <module-option name="rolesQuery">
                    SELECT ROLE 'Roles', ROLE_GROUP 'RoleGroups' FROM role WHERE BINARY PRINCIPAL_ID =?
                </module-option>
                <!-- uncomment to enable MD5 and BASE64 hash encoding
                <module-option name="hashAlgorithm">MD5</module-option>
                <module-option name="hashEncoding">BASE64</module-option>
                -->
            </login-module>
        </authentication>
    </application-policy>
</policy>
The login-service.xml loads the login module from login-config.xml, making sure the LoginConfigService and SecurityManagerService services are running before the new login module is activated.

These 2 files are generated the first time the security realm is enabled. They will not be overridden. For example, you can modify these files to prevent the queries checking for case sensitivity by removing the BINARY in the where clauses.

JBoss will load the MBean service configured in login-service.xml by specifying this service in the jboss-app.xml deployment descriptor. The EJB3 cartridge will do this for you, so you don't have to worry about it. It will add the following:

    ...
    <module>
        <service>META-INF/howtomodel-login-service.xml</service>
    </module>
    ...

The cartridge will also create an auth.conf file in ./app/src/main/config. You will need this file if your client is outside of the server JVM to be able to authenticate your credentials. This file needs to be in your classpath when you run your external client.

howtomodel {
   // jBoss LoginModule
   org.jboss.security.ClientLoginModule  required
   ;
};
You can use something like so to locate your auth.conf file from the your standalone client.
System.setProperty("java.security.auth.login.config", "./auth.conf");
Alternatively, when running from the command line, specify the -D arg option.

Remember that you will need to create your table schema corresponding to the authentication policy defined in login-config.xml. The DDL would look something like the following if you were using MySQL:

create table principal 
(
PRINCIPAL_ID varchar(64) not null default '', 
PASSWORD varchar(64) default NULL, 
PRIMARY KEY(PRINCIPAL_ID)
);

create table role
(
PRINCIPAL_ID varchar(64) not null default '', 
ROLE varchar(64) default NULL, ROLE_GROUP varchar(64) default NULL, 
PRIMARY KEY(PRINCIPAL_ID)
);

Modeling

Now you have to define some roles for your application. This is simply done by adding actors to your model named with the role's name.

images/org/andromda/test/8/a/uml.gif

The next thing to do is to draw a dependency from a logical role actor to a <<Service>> and/or to one or more methods of the service. Making the whole service dependent on an actor grants the role access to all service operations. To grant access to single operation(s) draw the dependency from the actor to the operations(s).

Defining security roles is purely optional. If no roles have been specified, then the bean operations do not pass any security instructions.

images/org/andromda/test/8/b/uml.gif

  • Auto-generated source that does not need manual editing
  • Auto-generated source that should be edited manually
  • File that is affected by the modifications applied in this section

Take a look at the RentalServiceBean class. You will notice a RolesAllowed annotation at the top level of the class as well as on each operation of the service bean. The RolesAllowed annotation is a list of security role names mapped to security roles allowed to execute the annotated method or all methods if specified at the class level.

The EJB3 cartridge provides a couple of extra security related tagged values. The andromda_service_security_denyAll tagged value which can be assigned on a session bean operation which specifies that no roles are permitted to execute that operation. If modeled on the session bean class and set to true, then no roles are permitted to execute all of the operations in that session bean. This tag overrides any roles specified using actor dependencies.

Inversely, the andromda_service_security_permitAll tagged value, if set to true on a session bean operation, implies that all roles are permitted to execute that operation. If modeled on the session bean class and set to true, then all roles are permitted to execute all opeations in that session bean. This tag overrides any roles specified usin actor dependencies.

In any of the cases above, method permissions that have been specified on a method of a bean will override the method permission value specified on the class itself.

To specify the RunAs metadata annotation and explicitly specify the caller's security identity used for the execution of the bean method, you simply need to model the <<RunAs>> stereotype on the actor role. This will imply the identity of the actor applies a run-as identity to the bean when making calls. The actor's name or corresponding andromda_role_name tagged value contains the logical role name. The run-as identity is only applicable to actor-bean dependency. It cannot be applied to bean operations. The run-as idendity is particularly useful for message driven beans where the security identity for the execution of the onMessage callback needs to be set.

Finally, the above diagram also illustrates how dependencies can be modeled from actors to entities. This creates corresponding security infrastructure in the entity DAO components. DAO objects are generated for every entity to expose CRUD API via stateless session beans. Since your session facade business layer used the DAO components layer, you need to propogate the security constraints through the DAO layer. Have a look at CarDaoBase.java. It contains the @RolesAllowed annotation to declare that the MANAGER and ASSISTANT roles require access to all operations within the DAO.

@javax.annotation.security.RolesAllowed({"ASSISTANT", "MANAGER"})

Next

We cover entity inheritance in the following section so click here to go to that section.