Custom Login Module with remote EJB
francois.swiegers May 23, 2012 4:56 AMHi there,
I am in the process of migrating a JBoss 4 application to JBoss 7, and am having difficulty with security over remote RMI EJB's. Specifically, I'm trying to add a custom login module to Jaikiran's post on EJB remoting (https://docs.jboss.org/author/display/AS71/EJB+invocations+from+a+remote+client+using+JNDI).
After adding the custom security module (described in more detail later in this post), I get the following exception on my client:
Caused by: javax.security.sasl.SaslException: Authentication failed: all available authentication mechanisms failed
at org.jboss.remoting3.remote.ClientConnectionOpenListener$Capabilities.handleEvent(ClientConnectionOpenListener.java:365)
at org.jboss.remoting3.remote.ClientConnectionOpenListener$Capabilities.handleEvent(ClientConnectionOpenListener.java:214)
at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:72)
at org.xnio.channels.TranslatingSuspendableChannel.handleReadable(TranslatingSuspendableChannel.java:189)
Upon debugging org.jboss.remoting3.remote.ClientConnectionOpenListener, it seems that the problem is that the only mechanism passed to the connection is PLAIN, but the connection listener only has client factories for the following mechanisms registered:
DIGEST-MD5=[org.jboss.sasl.digest.DigestMD5ClientFactory@1f4bcf7, com.sun.security.sasl.digest.FactoryImpl@8997d1],
ANONYMOUS=[org.jboss.sasl.anonymous.AnonymousClientFactory@a4488],
EXTERNAL=[com.sun.security.sasl.ClientFactoryImpl@18a6e6e], CRAM-MD5=[com.sun.security.sasl.ClientFactoryImpl@18a6e6e],
GSSAPI=[com.sun.security.sasl.gsskerb.FactoryImpl@e99ce5]}
Because it can't find a factory for the PLAIN mechanism, no SASL client is loaded, and the exception is thrown.
This seems to happen entirely on the client, even before the authentication is attempted on the server. Is there a way that I can add a factory for the PLAIN mechanism in my client connection? I recall that the PLAIN mechanism is required for JBOSS to pass the authentication on to the Jaas service - or is there a better way to do remote authentication?
Many thanks in advance for any help in this regard.
(From here I am just describing the process by which I added the custom security module, in case it could be the source of the problem)
standalone.xml
First thing I did was to change the application realm to use my Jaas authenticator:
<security-realm name="ApplicationRealm">
<authentication>
<jaas name="alchemy"/>
</authentication>
</security-realm>
...
<security-domains>
<security-domain name="alchemy" cache-type="default">
<authentication>
<login-module code="org.zboss.login.module.TestLoginModule" flag="required"/>
</authentication>
</security-domain>
</security-domains>
...
<subsystem xmlns="urn:jboss:domain:remoting:1.1">
<connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/>
</subsystem>
Custom Login Module
Then I added my custom login module as a module to JBoss by putting it in
jboss\modules\org\zboss\login\module\main
-> zboss-login-module.jar
-> module.xml
<?xml version="1.0" encoding="UTF-8"?>
module.xml contains:
<module xmlns="urn:jboss:module:1.0" name="org.zboss.login.module">
<resources>
<resource-root path="zboss-login-module.jar"/>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.picketbox"/>
</dependencies>
</module>
jboss-ejb-client.properties
endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port=6447
remote.connection.default.username=swiegersf
remote.connection.default.password=abc
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS=JBOSS-LOCAL-USER
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT=false
Client code
final Hashtable<String, Object> jndiProperties = new Hashtable<String, Object>();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, InitialContextFactory.class.getName());
jndiProperties.put(Context.PROVIDER_URL, "remote://localhost:6447/");
jndiProperties.put(InitialContext.SECURITY_PRINCIPAL, "swiegersf");
jndiProperties.put(InitialContext.SECURITY_CREDENTIALS, "abc");
jndiProperties.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", false);
jndiProperties.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_POLICY_NOPLAINTEXT", false);
jndiProperties.put("jboss.naming.client.connect.options.org.xnio.Options.SASL_DISALLOWED_MECHANISMS", "JBOSS-LOCAL-USER");
Context context = new InitialContext(jndiProperties);
Calculator calculator = (Calculator) context.lookup(name);
int result = calculator.add(3, 8); // error!