How can I configure JNDI and EJB communication to use SSL in JBoss EAP 6
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 6.x
Issue
- How can I configure JNDI and EJB communication to use SSL in JBoss EAP 6?
- How do I get the remoting interfaces to use SSL with remote JNDI lookups against the target server?
- My test client receives the following error trying to make JNDI calls with SSL:
14:06:25,651 ERROR [org.jboss.remoting.remote.connection] (Remoting "config-based-naming-client-endpoint" read-1) JBREM000200: Remote connection failed: java.io.IOException: Client starting STARTTLS but channel doesn't support SSL - Automatic propagation of the security context from JAAS in Tomcat to the EJB call doesn't work
Resolution
Server Configuration
There are two ways to configure security for EJBs that will be accessed by remote clients. 1) Authentication is handled directly by the security-realm that is associated with the EJB remoting connection. 2) Authentication is handled by a security-domain.
Option 1 - Using Security-Realm to handle Authentication
Authentication is handled by the security-realm. This is the default configuration. In this use case, users are added by using the $JBOSS_HOME/bin/add-user.sh script.
To enable SSL for EJB connection, configure the "ApplicationRealm" security-realm to use a keystore as the server's identity:
CLI Command below adds the ssl to the server-identities as shown below:
/core-service=management/security-realm=ApplicationRealm/server-identity=ssl:add(keystore-path=server.keystore, keystore-relative-to=jboss.server.config.dir, keystore-password=123456)
<security-realm name="ApplicationRealm">
<server-identities>
<ssl>
<keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="123456"/>
</ssl>
</server-identities>
<authentication>
<properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
</authentication>
<authorization>
<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
</authorization>
</security-realm>
</security-realms>
Configure an application level security-domain to use the "Remoting" and "RealmDirect" login modules. The EJB will need to be configured to use the security-domain by using the @SecurityDomain annotation or a
The CLI command below adds the ApplicationSecurityDomain as shown below:
/subsystem=security/security-domain=ApplicationSecurityDomain:add(cache-type=default)
/subsystem=security/security-domain=ApplicationSecurityDomain/authentication=classic:add(login-modules=[ {"code"=>"Remoting", "flag"=>"optional", "module-options"=>[password-stacking=>"useFirstPass"], {"code"=>"RealmDirect", "flag"=>"required", "module-options"=>[password-stacking=>"useFirstPass"]}}])
<!-- FIXME: application level security domain -- configured in @SecurityDomain or <security-domain> tag in jboss-ejb3.xml -->
<security-domain name="ApplicationSecurityDomain" cache-type="default">
<authentication>
<login-module code="Remoting" flag="optional">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
<login-module code="RealmDirect" flag="required">
<module-option name="password-stacking" value="useFirstPass"/>
</login-module>
</authentication>
</security-domain>
Option 2 - Using Security Domain to handle Authentication
Authentication is handled by the security-domain. In this use case, the username/password is not verified by the security-realm that is tied directly to the EJB remoting connection. The security-realm will defer to the security-domain for credential verification:
To enable SSL for EJB connection, configure the "ApplicationRealm" security-realm to use a keystore as the server's identity:
<security-realm name="ApplicationRealm">
<server-identities>
<ssl>
<keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="123456"/>
</ssl>
</server-identities>
<authentication>
<!-- FIXME: defer to the ApplicationSecurityDomain security-domain
<jaas name="ApplicationSecurityDomain"/>
</authentication>
</security-realm>
In this use case, the application level security-domain can be configured to use any login module that expects a username/password. The EJB will need to be configured to use the security-domain by using the @SecurityDomain annotation or a
<!-- FIXME: application level security domain -- configured in @SecurityDomain or <security-domain> tag in jboss-ejb3.xml -->
<security-domain name="ApplicationSecurityDomain" cache-type="default">
<authentication>
<login-module code="UsersRoles" flag="required">
<module-option name="usersProperties" value="file:///${jboss.server.config.dir}/users.properties"/>
<module-option name="rolesProperties" value="file:///${jboss.server.config.dir}/roles.properties"/>
</login-module>
</authentication>
</security-domain>
Client Configuration
The client code can use either the 1) EJB client API or the 2) Remote Naming API.
-
Client code that uses the EJB client API approach should look like the following and should have a jboss-ejb-client.properties file (notice the SSL related entries):
private static void testEJBClient() throws Exception { System.out.println("*** EJB Client API ***"); Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); InitialContext ctx = new InitialContext(env); Object obj = ctx.lookup("ejb:SimpleEAR_EJB3/SimpleEAR_EJB3//Hello!jboss.example.ejb.Hello"); Hello ejbObject = (Hello) obj; System.out.println(ejbObject.sayHello()); System.out.println("*** EJB Client API ***"); }Add the following parameters to the jboss-ejb-client.properties file:
remote.connections=default endpoint.name=client-endpoint remote.connection.default.port=4447 remote.connection.default.host=localhost # FIXME: SSL related settings remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=true remote.connection.default.connect.options.org.xnio.Options.SSL_STARTTLS=true remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false # The following setting is required when deferring to JAAS remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false remote.connection.default.username=admin remote.connection.default.password=testingPlease see the Content from docs.jboss.org is not included.JBoss AS 7 Developer Guide for more information on this approach.
-
Client code that uses the Remote Naming API approach should look like the following (notice the SSL related entries):
private static void testRemoteNaming() throws Exception { System.out.println("*** Remote Naming API ***"); Hashtable<String, String> env = new Hashtable<String, String>(); env.put("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory"); env.put("java.naming.provider.url", "remote://127.0.0.1:4447"); env.put("jboss.naming.client.ejb.context", "true"); env.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", "false"); // FIXME: SSL related config parameters env.put("jboss.naming.client.remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "true"); env.put("jboss.naming.client.connect.options.org.xnio.Options.SSL_STARTTLS", "true"); env.put(Context.SECURITY_PRINCIPAL, "admin"); env.put(Context.SECURITY_CREDENTIALS, "testing"); InitialContext ctx = new InitialContext(env); NamingEnumeration<Binding> binding_list = ctx.listBindings("SimpleEAR_EJB3"); while (binding_list.hasMore()) { Binding binding = (Binding) binding_list.next(); Object obj1 = binding.getObject(); System.out.println("read obj1 = " + obj1); } System.out.println("binding_list:"+binding_list); Object obj = ctx.lookup("SimpleEAR_EJB3/SimpleEAR_EJB3//Hello!jboss.example.ejb.Hello"); Hello ejbObject = (Hello) obj; System.out.println(ejbObject.sayHello()); System.out.println("*** Remote Naming API ***"); }
Diagnostic Steps
Enable trace level logging on the following logging categories:
<logger category="org.jboss.as.domain.management.security">
<level name="TRACE"/>
</logger>
<logger category="org.jboss.sasl">
<level name="TRACE"/>
</logger>
<logger category="org.jboss.security">
<level name="TRACE"/>
</logger>
<logger category="org.jboss.as.ejb3">
<level name="TRACE"/>
</logger>
<logger category="org.jboss.as.remoting">
<level name="TRACE"/>
</logger>
<logger category="org.jboss.remoting3">
<level name="TRACE"/>
</logger>
<logger category="org.jboss.remoting">
<level name="TRACE"/>
</logger>
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.