April 25, 2012

JBoss EJB 3.0 Security with Annotation and Declarative with Deployment Descriptor (ejb-jar.xml and jboss.xml)

The Security configuration and programming model has been much simplified with Java EE 5 and especially with the general introduction of Annotation. The Annotation has reduced significantly the XML cacophony. But in some cases declaring thing external from the source code is good, and an example of that is Security.

So lets start with an easy EJB and use standard Java Enterprise Bean Security Annotations [1], but we will also use JBoss specific JAAS Security Annotation. Later on we will test that we can override these values by declaring security on the EJB deployment descriptor ejb-jar.xml (Java EE) and jboss.xml (JBoss Container Specific)

@javax.ejb.Local
public interface FooLocal {

    public void method1();

    public void method2();
}
@javax.ejb.Remote
public interface FooRemote {

    public void method1();

    public void method2();
}
@javax.ejb.Stateless
@org.jboss.ejb3.annotation.SecurityDomain("mydomain")
@javax.annotation.security.DeclareRoles({ "USERGROUP", "ADMINGROUP" })
public class FooBean implements FooLocal, FooRemote {

    @javax.annotation.security.RolesAllowed({ "USERGROUP" })
    public void method1() {
        print();
    }

    @javax.annotation.security.RolesAllowed({ "ADMINGROUP" })
    public void method2() {
        print();
    }

    public void print() throws PolicyContextException {
        final String key = "javax.security.auth.Subject.container";
        Subject caller = (Subject) PolicyContext.getContext(key);
        Set<principal> principals = caller.getPrincipals();
        for (Principal principal : principals) {
            LOGGER.info("class=" + principal.getClass() + ", principal="
                    + principal + ", name='" + principal.getName() + "'");
        }
    }
}
NOTE: Do not use JNDI prefix java:/jaas in the SecurityDomain annotation.

NOTE: SecurityDomain has since JBoss 5.X changed package name, if you are using JBoss 4.X it is org.jboss.security.annotation.SecurityDomain.

In our first example the deployment descriptors can be quite empty.

META-INF/ejb-jar.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
    version="3.0">

</ejb-jar>
META-INF/jboss.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
    version="5.0">

    <security-domain>java:/jaas/mydomain</security-domain>
</jboss>
NOTE: Since JBoss 5.X the JNDI prefix java:/jaas is now optional, but left for backward compatibility.

And finally we will have to define our security domain in $JBOSS_HOME/server/$CONF/conf/login-config.xml.
<application-policy name="mydomain">
    <authentication>
        <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
            <module-option name="usersProperties">props/mydomain-users.properties</module-option>
            <module-option name="rolesProperties">props/mydomain-roles.properties</module-option>
        </login-module>
    </authentication>
</application-policy>
Now lets get started with overriding these security settings with the deployment descriptors. The two deployment descriptors are quite open and writing of them can be done in different ways. But I use these guidelines, for hopefully making things a little more simpler.

Try to use the generic ejb-jar.xml as much as possible. And only put specific container configuration in the jboss.xml.

And changing security is a Java EE feature so declaring security is done in the ejb-jar.xml file.

META-INF/ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
    version="3.0">
     
    <assembly-descriptor>
        <security-role>
            <role-name>USERGROUP</role-name>
        </security-role>
        <security-role>
            <role-name>ADMINGROUP</role-name>
        </security-role>
        <method-permission>
            <role-name>ADMINGROUP</role-name>
            <method>
                <ejb-name>FooBean</ejb-name>
                <method-name>method1</method-name>
            </method>
        </method-permission>
        <method-permission>
            <role-name>ADMINGROUP</role-name>
            <method>
                <ejb-name>FooBean</ejb-name>
                <method-name>method2</method-name>
            </method>
        </method-permission>
    </assembly-descriptor>
</ejb-jar>


Reference:
[1] Java EE 5 Tutorial: http://docs.oracle.com/javaee/5/tutorial/doc/bnbyl.html
[2] JBoss Security FAQ: https://community.jboss.org/wiki/SecurityFAQ

No comments: