JBoss 7 and Ejb remote call with security

    This article describes my tests with ejb and JBoss7.

     

    For my test a have ear (TestEar) with one ejb module (TestEjb) and one bean (TestBean).

     

    TestEar.ear
       +---TestEjb.ejb
           +--mates.test.TestBean.class
              mates.test.TestBeanRemote.class
    

     

    As security I use RealmUsersRoles with

    x-users.properties

    testX=test1234
    

    x-roles.properties

    testX=bean
    

     

    And now standalone.xml

    and I changed ApplicationRealm

    <security-realm name="ApplicationRealm">
         <authentication>
              <jaas name="bean-sec-domain"/>
         </authentication>
    </security-realm>
    

    and security domain

     

    <security-domain name="bean-sec-domain" cache-type="default">     
         <authentication>
              <login-module code="Remoting" flag="optional">
                   <module-option name="password-stacking" value="useFirstPass"/>
              </login-module>
              <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
                   <module-option name="defaultUsersProperties" value="file:/${jboss.server.config.dir}/x-users.properties"/>
                   <module-option name="defaultRolesProperties" value="file:/${jboss.server.config.dir}/x-roles.properties"/>
                   <module-option name="usersProperties" value="file:/${jboss.server.config.dir}/x-users.properties"/>
                   <module-option name="rolesProperties" value="file:/${jboss.server.config.dir}/x-roles.properties"/>
                   <module-option name="password-stacking" value="useFirstPass"/>
              </login-module>
         </authentication>
    </security-domain>
    

     

    And now lets look at bean.

     

    @Stateless
    @DeclareRoles("bean")
    public class TestBean implements TestBeanRemote {
    
            @Resource
            private EJBContext context;
    
            @Override
            @RolesAllowed("bean")
            public String getName ()
            {
                    return getNameFree();
            }
    
            @Override
            public String getNameFree ()
            {
                    String aName = "";
                    if (context.getCallerPrincipal() != null) {
                            aName = context.getCallerPrincipal().getName();
                    }
                    return "name " + aName + " " + context.isCallerInRole("bean");
            }
    }
    

     

    Let's secure EJB

    add jboss-app.xml to TestEar.ear\META-INF. I use security domain other to ensure that i secure all beans.

     

    <?xml version="1.0" encoding="UTF-8"?>
    <p:jboss-app xmlns:p="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 ../../xsd/jboss-app_7_0.xsd ">
        <security-domain>other</security-domain>
    </p:jboss-app>
    

     

    And I want to secure TestBean. I have to add jboss-ejb3.xml to TestEjb.jar\META-INF\. TestBean is secured by bean-sec-domain.

     

    <?xml version="1.0" encoding="UTF-8"?>
    <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
        xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:security="urn:security" version="3.1" impl-version="2.0">
        <assembly-descriptor xmlns="http://java.sun.com/xml/ns/javaee">
            <security:security xmlns:security="urn:security">
                <security:security-domain>bean-sec-domain</security:security-domain>
                <ejb-name>TestBean</ejb-name>
            </security:security>
        </assembly-descriptor>
    </jboss:ejb-jar>
    

     

     

    Remote interface is real simple with 2 methods.

     

    Client:

     

    Hashtable<String, Object> p = new Hashtable<String, Object>();
    p.put(Context.INITIAL_CONTEXT_FACTORY, InitialContextFactory.class.getName());
    p.put(Context.PROVIDER_URL, "remote://127.0.0.1:4447/");
    p.put(InitialContext.SECURITY_PRINCIPAL, "testX");
    p.put(InitialContext.SECURITY_CREDENTIALS, "test1234");
    p.put("jboss.naming.client.ejb.context", true);
    p.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false");
    
    InitialContext c = new InitialContext(p);
    TestBeanRemote vLookup = (TestBeanRemote) c.lookup("java:/TestEar/TestEjb/TestBean!"+ TestBeanRemote.class.getName());
    
    System.out.println("x" + vLookup.getNameFree());
    System.out.println("x" + vLookup.getName());
    

     

    After this you can see

     

    xname testX true
    xsecured name testX true
    

     

    That's all.

     

    And now some other tests:

    Most important mart is

    p.put("jboss.naming.client.ejb.context", true);

    without this property you will see "No EJB receiver available for handling [appName:TestEar,modulename:TestEjb,distinctname:] combination"

     

    when you put in class path file jboss-ejb-client.properties with standard

     

    remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
    
    remote.connections=x1
    
    remote.connection.x1.host=127.0.0.1
    remote.connection.x1.port = 4447
    remote.connection.x1.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
    remote.connection.x1.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false  
    


    and comment p.put("jboss.naming.client.ejb.context", true);

    and in console is now

     

    xname $local false
    Exception in thread "main" javax.ejb.EJBAccessException: JBAS014502: Invocation on method: public abstract java.lang.String mates.test.TestBeanRemote.getName() of bean: TestBean is not allowed
    

     

    jboss.naming.client.ejb.context setup EJBContext on client side. See org.jboss.naming.remote.client.InitialContextFactory