How to bind an external JNDI / LDAP context into JNDI in EAP6 ?
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 6.0
Issue
ExternalContextMBeancan be utilized to bind an external LDAP directory to JBoss inEAP 5.- What is the equivalent in EAP 6?
- Register LDAP as a JNDI resource ? I want to use LDAP as JNDI resource.
Resolution
ExternalContextMBean MBean has been removed in EAP6. Therefore, it can no longer be used to bind external contexts into the local JNDI name space. There is a feature request that was implemented in JBoss EAP 6.2.0 as shown below. For JBoss EAP 6.1.x and 6.0.x, a functionality similar to External Context could be achieved but required some intermediate code.
JBoss EAP 6.2.x and above
JBoss EAP 6.1.x
JBoss EAP 6.0.x
JBoss EAP 6.2.0 and beyond using external-context in the naming subsystem
Note: In release EAP 6.2 there is a bug [1] which prevents resources defined in an external context to be injected in to code using annotations.
Also external context resources cannot be enlisted in XA transactions.
LDAP Example
Adding via the CLI
/subsystem=naming/binding=java\:global\/myExtContext:add(binding-type=external-context, module=org.jboss.as.naming, class=javax.naming.directory.InitialDirContext, cache=true, environment={"java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory", "java.naming.provider.url"=>"ldap://ldap.customer.com:389"})
Produces this xml in the JBoss profile configuration:
<subsystem xmlns="urn:jboss:domain:naming:1.4">
...
<bindings>
...
<external-context name="java:global/my-ldap" module="org.jboss.as.naming" class="javax.naming.directory.InitialDirContext" cache="true">
<environment>
<property name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
<property name="java.naming.provider.url" value="ldap://ldap.customer.com:389"/>
</environment>
</external-context>
...
</bindings>
...
</subsystem>
Remote Naming Example
This example below binds a remote servers JNDI / Remote Naming into java:global/external:
<subsystem xmlns="urn:jboss:domain:naming:1.4">
<bindings>
<external-context name="java:global/external" module="org.jboss.remote-naming" class="javax.naming.InitialContext" cache="false">
<environment>
<property name="java.naming.factory.initial" value="org.jboss.naming.remote.client.InitialContextFactory"/>
<property name="java.naming.provider.url" value="remote://192.168.1.102:4447"/>
<property name="java.naming.factory.pkgs" value="org.jboss.ejb.client.naming"/>
<property name="java.naming.security.principal" value="testuser"/>
<property name="java.naming.security.credentials" value="secret"/>
</environment>
</external-context>
</bindings>
...
</subsystem>
RefFSContextFactory Example
Note: The fscontext.jar needs to be on the boot classpath of the JDK
Create a module external.context.fscontext in $JBOSS_HOME/modules/external/context/fscontext/main/module.xml containing:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="external.context.fscontext">
<dependencies>
<system export="true">
<paths>
<path name="com/sun/jndi"/>
<path name="com/sun/jndi/fscontext"/>
</paths>
</system>
<module name="org.jboss.as.naming" export="true"/>
</dependencies>
</module>
Adding via the CLI
/subsystem=naming/binding=java\:global\/MQContext:add(binding-type=external-context, module=external.context.fscontext, class=javax.naming.InitialContext, cache=true, environment={"java.naming.factory.initial"=>"com.sun.jndi.fscontext.RefFSContextFactory", "java.naming.provider.url"=>"file:${jboss.server.data.dir}/examples", "java.naming.security.authentication"=>"none"})
Produces this xml in the JBoss profile configuration:
<subsystem xmlns="urn:jboss:domain:naming:1.4">
...
<bindings>
...
<external-context name="java:global/MQContext" module="org.jboss.as.naming" class="javax.naming.InitialContext" cache="true">
<environment>
<property name="java.naming.factory.initial" value="com.sun.jndi.fscontext.RefFSContextFactory"/>
<property name="java.naming.provider.url" value="file:${jboss.server.data.dir}/examples"/>
<property name="java.naming.security.authentication" value="none"/>
</environment>
</external-context>
</bindings>
<remote-naming/>
</subsystem>
JBoss EAP 6.1.x using an object-factory configuration in the naming subsystem
JBoss EAP 6.1 allows you to specify environment properties that will be passed to your ObjectFactory implementation, thus you do not have to hard code them as in EAP 6.0.x
LDAP Example
<subsystem xmlns="urn:jboss:domain:naming:1.3">
<bindings>
<object-factory name="java:global/myExtContext" module="my.module" class="com.jboss.exmaples.objectfactory.ExternalContextObjectFactory">
<environment>
<property name="java.naming.provider.url" value="ldap://ldap.customer.com:389"/>
<property name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
<property name="InitialContext" value="javax.naming.directory.InitialDirContext"/>
</environment>
</object-factory>
</bindings>
<remote-naming/>
</subsystem>
com.jboss.exmaples.objectfactory.ExternalContextObjectFactory
// Example factory for LDAP
public class ExternalContextObjectFactory implements ObjectFactory {
@Override
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?, ?> environment) throws Exception {
String initialContextClassName = (String) environment.get("InitialContext");
if(initialContextClassName == null)
{
return new InitialContext((Hashtable) environment);
}
else
{
Class initialContextClass = Class.forName(initialContextClassName);
InitialContext initialContext = (InitialContext) initialContextClass.newInstance();
initialContext.init((Hashtable) environment);
return initialContext;
}
}
}
RefFSContextFactory Example
// example factory for RefFSContextFactory
<subsystem xmlns="urn:jboss:domain:naming:1.3">
<bindings>
<object-factory name="java:global/myExtContext" module="my.module" class="com.jboss.exmaples.objectfactory.ExternalContextObjectFactory">
<environment>
<property name="java.naming.provider.url" value="file:/home/jboss/examples/"/>
<property name="java.naming.factory.initial" value="com.sun.jndi.fscontext.RefFSContextFactory"/>
</environment>
</object-factory>
</bindings>
<remote-naming/>
</subsystem>
public class ExternalContextObjectFactory implements ObjectFactory {
@Override
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?, ?> environment) throws Exception {
String initialContextClassName = (String) environment.get("InitialContext");
if(initialContextClassName == null)
{
return new InitialContext((Hashtable) environment);
}
else
{
Class initialContextClass = Class.forName(initialContextClassName);
InitialContext initialContext = (InitialContext) initialContextClass.newInstance();
initialContext.init((Hashtable) environment);
return initialContext;
}
}
}
my.module
This is just the module which contains the class `com.jboss.exmaples.objectfactory.ExternalContextObjectFactory`
So you would create a module or use the module where you have your ExternalContextObjectFactory implementation packaged. For example, if I named it my.module, it would look like:
`$JBOSS_HOME/modules/my/module/main/
- external-context-factory.jar/com/jboss/exmaples/objectfactory/ExternalContextObjectFactory.class
- module.xml`
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="my.module">
<resources>
<resource-root path="external-context-factory.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>
Having your application such as a Singleton bind the context into JNDI
This solution would be to use the InitialContext to point to a different naming store, possibly with registering a specific prefix. The Content from docs.oracle.com is not included.JNDI API can be used to do lookups in LDAP by constructing the InitialContext to match the connection information.
An example provided below on how to look up external LDAP entries:
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL, ldapURL);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
DirContext ctx = new InitialDirContext(env);
From that point on ctx object can be used to lookup LDAP entries.
JBoss EAP 6.0.x using an object-factory configuration in the naming subsystem
For EAP 6.0.x, you can write your own ObjectFactory implementation class and have it return the context you need. You will have to hard code the environment properties or write the class to read them from somewhere. Also note, you may want to cache, the example below is creating a new context each time.
LDAP Example
<subsystem xmlns="urn:jboss:domain:naming:1.2">
<bindings>
<object-factory name="java:global/myExtContext" module="sun.jdk" class="com.jboss.exmaples.objectfactory.ExternalContextObjectFactory"/>
</bindings>
<remote-naming/>
</subsystem>
com.jboss.exmaples.objectfactory.ExternalContextObjectFactory
// Example factory for LDAP
public class ExternalContextObjectFactory implements ObjectFactory {
@Override
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?, ?> environment) throws Exception {
Hashtable env = new Hashtable();
if(environment != null)
env.putAll(environment);
env.set("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
env.set(java.naming.provider.url","ldap://ldap.customer.com:389");
return new InitialDirContext(environment);
}
}
RefFSContextFactory Example
// example factory for RefFSContextFactory
public class ExternalContextObjectFactory implements ObjectFactory {
@Override
public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?, ?> environment) throws Exception {
Hashtable env = new Hashtable();
if(environment != null)
env.putAll(environment);
env.set("java.naming.factory.initial", "com.sun.jndi.fscontext.RefFSContextFactory");
env.set(java.naming.provider.url","file:/home/jboss/examples/");
return new InitialContext(environment);
}
}
[1] Content from issues.jboss.org is not included.Content from issues.jboss.org is not included.https://issues.jboss.org/browse/WFLY-1727
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.