I have some code like this for connecting to HornetQ.
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
properties.put(Context.PROVIDER_URL, "remote://127.0.0.1:4447");
properties.put(Context.SECURITY_PRINCIPAL, "user");
properties.put(Context.SECURITY_CREDENTIALS, "pwd");
ConnectionFactory connectionFactory = null;
Destination destination = null;
try {
Context context = new InitialContext(properties);
I inherited this, and am trying to get a better understanding of it. I haven't found documentation for the valid values where I have "remote://". I'm not sure if it's accurate to call that a protocol or not, but that's what it looks like. I've seen "jnp://" in other samples.
Is there an official list of valid values, and what they mean?
You may want to refer to specific JNDI Reference for specific versions. JBOSS AS 7.2 is covered here: https://docs.jboss.org/author/display/AS72/JNDI+Reference (note that in JBOSS AS 7.x, jnp is no longer supported, older JBOSS versions do support the jnp:// and access via the standard naming services).
Another link: https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/Naming_on_JBoss-The_Naming_InitialContext_Factories.html.
Related
I'm using Redisson with below configuration to connect to Sentinel servers:
Config config = new Config();
config.useSentinelServers().setMasterName("local")
.addSentinelAddress("redis://localhost:26379", "redis://localhost:26380", "redis://localhost:26381");
RedissonClient client = Redisson.create(config);
How ever when I run this code I get the below error creating the client:
Caused by: java.lang.IllegalArgumentException: port out of range:-1
at java.net.InetSocketAddress.checkPort(InetSocketAddress.java:143)
at java.net.InetSocketAddress.<init>(InetSocketAddress.java:224)
at org.redisson.client.RedisClient.<init>(RedisClient.java:105)
at org.redisson.connection.MasterSlaveConnectionManager.createClient(MasterSlaveConnectionManager.java:354)
at org.redisson.connection.SentinelConnectionManager.<init>(SentinelConnectionManager.java:74)
at org.redisson.config.ConfigSupport.createConnectionManager(ConfigSupport.java:258)
at org.redisson.Redisson.<init>(Redisson.java:115)
at org.redisson.Redisson.create(Redisson.java:154)
I wanted to know if I'm missing any thing in the redisson config or my sentinel servers are not configured well.
Apologies for the confusion I have caused in editing the wiki. I should have stated that was in reflection to the latest version.
From 2.9.3 and 3.4.3 above, we have introduced the support for SSL, it is then required to specify the URI scheme to inform the type of connection that is requires.
It is working now if I change the original configuration as below:
Config config = new Config();
config.useSentinelServers().setMasterName("local")
.addSentinelAddress("localhost:26379", "localhost:26380", "localhost:26381");
RedissonClient client = Redisson.create(config);
It is misleading in the documentation as it does suggests otherwise.
https://github.com/redisson/redisson/wiki/2.-Configuration#271-sentinel-settings
Trying to migrate an application from WebLogic 12.2.1 to Tomcat 8.5.4, what under Weblogic was an entry as Foreign JNDI Providers for an LDAP connection has been migrated to a new Resource under Tomcat.
Following this advice on Stack Overflow, a custom LdapContextFactory has been packaged as a new jar file under Tomcat lib folder.
In the Tomcat server.xml file the following GlobalNamingResources/Resource has been configured:
<Resource name="ldapConnection"
auth="Container"
type="javax.naming.ldap.LdapContext"
factory="com.sample.custom.LdapContextFactory"
singleton="false"
java.naming.referral="follow"
java.naming.factory.initial="com.sun.jndi.ldap.LdapCtxFactory"
java.naming.provider.url="ldap://some.host:389"
java.naming.security.authentication="simple"
java.naming.security.principal="CN=some,OU=some,OU=some,DC=some,DC=a,DC=b"
java.naming.security.credentials="password"
com.sun.jndi.ldap.connect.pool="true"
com.sun.jndi.ldap.connect.pool.maxsize="10"
com.sun.jndi.ldap.connect.pool.prefsize="4"
com.sun.jndi.ldap.connect.pool.timeout="30000" />
The connection above works fine when browsing the LDAP directory via an LDAP browser like Apache Directory Studio / LDAP Browser embedded in Eclipse.
The custom com.sample.custom.LdapContextFactory is quite simple:
public class LdapContextFactory implements ObjectFactory {
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
Hashtable<Object, Object> env = new Hashtable<>();
Reference reference = (Reference) obj;
Enumeration<RefAddr> references = reference.getAll();
while (references.hasMoreElements()) {
RefAddr address = references.nextElement();
String type = address.getType();
String content = (String) address.getContent();
env.put(type, content);
}
return new InitialLdapContext(env, null);
}
}
However, at start-up Tomcat is throwing the following exception:
07-Sep-2016 15:04:01.064 SEVERE [main] org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans Exception processing Global JNDI Resources
javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001E5, problem 2001 (NO_OBJECT), data 0, best match of:
''
]; remaining name ''
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3160)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3081)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2888)
at com.sun.jndi.ldap.LdapCtx.c_listBindings(LdapCtx.java:1189)
at com.sun.jndi.toolkit.ctx.ComponentContext.p_listBindings(ComponentContext.java:592)
at com.sun.jndi.toolkit.ctx.PartialCompositeContext.listBindings(PartialCompositeContext.java:330)
at com.sun.jndi.toolkit.ctx.PartialCompositeContext.listBindings(PartialCompositeContext.java:317)
at javax.naming.InitialContext.listBindings(InitialContext.java:472)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:136)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:145)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:110)
at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.lifecycleEvent(GlobalResourcesLifecycleListener.java:82)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:94)
at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:401)
at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:345)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:784)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:152)
at org.apache.catalina.startup.Catalina.start(Catalina.java:655)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:355)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:495)
Similar questions and investigations suggest an invalid LDAP DN, but:
The same LDAP configuration works fine via an LDAP Client
No search is actually performed, at start-up time Tomcat throws this exception without any query
The error suggests an empty string '' as remaining name, hence not really something not found, apparently
Question(s): Is this the correct way to migrate an Foreign JNDI Providers entry from WebLogic to Tomcat? How to fix an invalid LDAP DN entry with an empty remaining name? Could it be a missing baseDN to configure somewhere?
Update
The same exact error happens when changing the LdapContextFactory to the following, as suggested via comments:
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
Hashtable<Object, Object> env = new Hashtable<>();
Reference reference = (Reference) obj;
Enumeration<RefAddr> references = reference.getAll();
String providerUrl = "no valid URL";
while (references.hasMoreElements()) {
RefAddr address = references.nextElement();
String type = address.getType();
String content = (String) address.getContent();
switch (type) {
case Context.PROVIDER_URL:
env.put(Context.PROVIDER_URL, content);
providerUrl = content;
break;
default:
env.put(type, content);
break;
}
}
InitialLdapContext context = null;
Object result = null;
try {
context = new InitialLdapContext(env, null);
LOGGER.info("looking up for " + providerUrl);
result = context.lookup(providerUrl);
} finally {
if (context != null) {
context.close();
}
}
LOGGER.info("Created new LDAP Context");
return result;
}
Change is confirmed via logging, to make sure it was deployed properly.
The involved listener is defined by default at the top of the server.xml file as
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
And cannot be disabled as per official documentation:
The Global Resources Lifecycle Listener initializes the Global JNDI resources defined in server.xml as part of the Global Resources element. Without this listener, none of the Global Resources will be available.
The same also happens on Tomcat version 8.5.5 and 7.0.69: simply adding the new global resource as above and the additional jar providing the factory above, the exception pointing at an empty remaining name will be thrown.
The stacktrace went away by appending to the java.naming.provider.url property the LDAP schema DN, using the first factory implementation provided in the question.
Below a screenshot of the LDAP client used in this context, the Apache Directory Studio / LDAP Browser embedded in Eclipse, from which it was possible to browse the concerned LDAP simply using the initial values of the question.
By appending the schema DN of the Root element to the connection URL, the exception went away and the LDAP resource is now shared via JNDI in Tomcat 8.
Further details as outcome of the troubleshooting:
In Tomcat 8 global resources are handled via a global resource listener, the GlobalResourcesLifecycleListener, defined by default in the server.xml file. Such a listener invokes a context.listBindings("") on bean creation, hence effectively browsing the LDAP directory.
This initial browsing may most probably be the difference between Tomcat and WebLogic, where LDAP is looked up via JNDI only when required, hence via direct query, rather than at start-up with a generic query. As such, in Tomcat the LDAP url would need further details, that is, a slightly different configuration as part of its url to directly point to a valid base DN.
From official WebLogic documentation:
On start up, WebLogic Server attempts to connect to the JNDI source. If the connection is successful, WebLogic Server sets up the requested objects and links in the local JNDI tree, making them available to WebLogic Server clients.
Hence, a connection is rather simpler than a listBindings:
Enumerates the names bound in the named context, along with the objects bound to them. The contents of any subcontexts are not included.
I'm trying to access a Message Queue configured in GlassFish but have been facing a lot of problems. The first one is regarding the Trust Store password on the client side. I can only make it work if I use the default password (changeit), I'm always getting
Keystore was tampered with, or password was incorrect
if I try to use a different password. And yes, I'm pretty sure I'm using the correct password.
In fact, if I set the Trust Store with the default password and use the following property with a wrong value, it still works:
-Djavax.net.ssl.trustStorePassword=<wrong value>
Which leads me to conclude that it completely ignores this setting.
This is what I've so far:
System.setProperty("com.sun.CSIV2.ssl.standalone.client.required", "true");
System.setProperty("javax.net.ssl.trustStore", "<my path>/truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "<my password>");
Properties properties = new Properties();
System.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
System.setProperty("org.omg.CORBA.ORBInitialPort", "3820");
InitialContext ctx = new InitialContext(properties);
com.sun.messaging.ConnectionFactory connectionFactory = new com.sun.messaging.ConnectionFactory();
connectionFactory.setProperty(ConnectionConfiguration.imqAddressList, "127.0.0.1:7676");
connectionFactory.setProperty(ConnectionConfiguration.imqDefaultUsername, "<app user>");
connectionFactory.setProperty(ConnectionConfiguration.imqDefaultPassword, "<app user password>");
QueueConnection queueConnection = connectionFactory.createQueueConnection();
queueConnection.start();
So, my first question is: How can I use the non-default password on my Trust Store? Do I have to use some kind of encoding/hashing on the value?
My second question is regarding authentication. The standard way of getting the Connection Factory (via JNDI) and authenticate (via createQueueConnection(user, pass)) does not seem to be working, it always tries to use the guest account. Is there a way to use the standard approach on GlassFish or am I limited to use proprietary code?
EDIT #1
After digging a little deeper, I've detected a behavior that seems a bug.
Looking at the stacktrace, one of the first methods being invoked is initJKS() from com.sun.enterprise.security.ssl.impl.SecuritySupportImpl. With the help of javassist, I realized that the following section is being invoked:
if (masterPasswordHelper == null && Globals.getDefaultHabitat() != null) {
masterPasswordHelper = Globals.getDefaultHabitat().getByType(MasterPasswordImpl.class);
}
if (masterPasswordHelper instanceof MasterPasswordImpl) {
keyStorePass = masterPasswordHelper.getMasterPassword();
trustStorePass = keyStorePass;
}
Causing the bypass of the next set of instructions:
if (keyStorePass == null) {
keyStorePass = System.getProperty(KEYSTORE_PASS_PROP, DEFAULT_KEYSTORE_PASS).toCharArray();
trustStorePass = System.getProperty(TRUSTSTORE_PASS_PROP, DEFAULT_TRUSTSTORE_PASS).toCharArray();}
And, as a consequence, to ignore the property javax.net.ssl.trustStorePassword. Why is Globals.getDefaultHabitat() returning a non null value?
When I run jconsole it shows me a list of Java processes:
I could then connect to one of these and see its MBeans. How does it discover the JMX processes? How can I do this in a program?
This article shows how to do it using Attach API from JDK tools.jar
Replying since I had this question too and got an answer.
There is a JPS program in JDK which shows java processes.
I am not 100% sure (don't want to dive deep into jconsole code) but 99% sure jconsole uses the same mechanism as jps:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/tools/jps/Jps.java?av=f
HostIdentifier hostId = arguments.hostId();
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(hostId);
// get the set active JVMs on the specified host.
Set<Integer> jvms = monitoredHost.activeVms();
These class are part of tools.jar, you need to include it in the project's classpath.
If we go deeper (I do not expose all the intermediate steps) - finally we'll know that active VMs list is populated from hsperfdata files in temporary directories:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java
Here is a link to know more:
java hsperfdata directory
At last, here is a code snippet allowing you to get the java processes ids:
sun.jvmstat.monitor.MonitoredHost host = sun.jvmstat.monitor.MonitoredHost.getMonitoredHost(new sun.jvmstat.monitor.HostIdentifier((String) null));
System.out.println(host.activeVms());
P.S.
Then you can use Attach API (as kostya mentioned) to discover the rest of needed things.
After you register the MBean in your application, like this:
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//register the MBean
ObjectMbean mBean = new ObjectMbean();
ObjectName name = new ObjectName("com.gd.eventfiltering.jmx:type=SystemConfig");
mbs.registerMBean(mBean, name);
Then you can call your MBean like this:
JMXServiceURL url = new JMXServiceURL(JMX_PATH);
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName(JMX_OBJECT);
IObjectMbean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName,IObjectMbean.class, false);
//call the method
List<EventType> filters = mbeanProxy.methodFromYourMBean();
jmxc.close();
I have a server with two NICs and I need to specify which NIC must be used to to connect to a backend LDAP.
I know that in Java the NICs can be specified when a socket is created (http://docs.oracle.com/javase/tutorial/networking/nifs/definition.html), but how can I do that using the
JNDI/LDAP framework?
Thanks
What you need to do is to obtain control over JNDI's process of creating a socket. For that, you need to tell JNDI which SocketFactory to use.
When constructing the InitialLdapContext, you can provide a Hashtable.
Hashtable props = new Hashtable();
props.put("java.naming.ldap.factory.socket", "com.whatever.MySocketFactory");
InitialLdapContext ic = new InitialLdapContext(props, null);
When com.whatever.MySocketFactory is your own class, extending javax.net.SocketFactory.
I think there's a constant somewhere in the JDK for java.naming.ldap.factory.socket, but I can't find it...
Or you could use:
env.put(Context.PROVIDER_URL, "ldap://<specific IP Address>:636/o=JNDITutorial");
-jim