Issue with DNS Naming and Certificates LDAP Context - java

With the last update of Java 1.8.0_181 I have an issue when I try to create a LDAPS connection to Active Directory. Up to version 1.8.0_171 using the following code I could create it without issues
Hashtable<String, Object> objEnvironment;
objEnvironment = new Hashtable<String, Object>(11);
objEnvironment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
objEnvironment.put(Context.PROVIDER_URL, "LDAPS://domain:636");
objEnvironment.put(Context.SECURITY_AUTHENTICATION, "simple");
objEnvironment.put(Context.SECURITY_PRINCIPAL, <username>);
objEnvironment.put(Context.SECURITY_CREDENTIALS, <Password>);
objEnvironment.put("java.naming.ldap.attributes.binary", <attributes>);
System.setProperty("javax.net.ssl.trustStore", "certificates".concat(File.separator).concat("cacerts"));
this.objLDAPContext = new InitialLdapContext(objEnvironment, null);
However with the last version I get the following exception java.security.cert.CertificateException: No DNS name found for xxxx.xxxx.xxx
Looking it up I found it is an issue with the FDQN name, if I do not use the same name as it is displayed on the certificate, I can not establish a connection. I would like to know if there is a way to skip this and can use the domain name as I did in the past.

The issue you are experiencing may be due to the changes introduced in Java 1.8.0_181 for improved LDAP Support. Refer the release notes here.
➜ Improve LDAP support Endpoint identification has been enabled on
LDAPS connections.
To improve the robustness of LDAPS (secure LDAP over TLS )
connections, endpoint identification algorithms have been enabled by
default.
Note that there may be situations where some applications that were
previously able to successfully connect to an LDAPS server may no
longer be able to do so. Such applications may, if they deem
appropriate, disable endpoint identification using a new system
property: com.sun.jndi.ldap.object.disableEndpointIdentification.
Define this system property (or set it to true) to disable endpoint
identification algorithms.
You may use the workaround to add -Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true while running your code.
Note that this is not a recommended approach, as your system will continue to be vulnerable using this approach.

Related

How to fix Java JMX RMI Accessible without Credentials

Any idea how to fix this security vulnerability ?
Java JMX interface is accessible via following username/password pairs: admin/password admin/admin admin/activemq monitorRole/QED controlRole/R%26D controlrole/password monitorrole/password cassandra/cassandrapassword monitorRole/tomcat controlRole/tomcat monitorRole/mrpasswd controlRole/crpasswd role1/role1passwd role2/role2passwd role3/role3passwd admin/thisIsSupposedToBeAStrongPassword! QID Detection Logic (Authenticated):
This QID tries to log into JMX RMI server using above credentials. Note:if remote JMX RMI sever accessible without authentication. all of above credentials will post.
fix for this mentions to change the common password, but not sure where exactly and if that is the right way. Any guidance is appreciated
You can use JAVA Console (jconsole.jar or jcnsole.exe) or Java Mission Control to verify whether you can connect with one of the default passwords listed by Qualys or without any credentials at all.
Here are the instructions on how to secure JMX from Oracle:
https://docs.oracle.com/javadb/10.10.1.2/adminguide/radminjmxenablepwd.html
Here's how to enable JMX with password and SSL:
https://docs.oracle.com/javadb/10.10.1.2/adminguide/radminjmxenablepwdssl.html
You may need to work with your specific vendor on how to address this for your specific configuration but here's how another particular vendor recommends addressing it:
https://support.datastax.com/hc/en-us/articles/204226179-Step-by-step-instructions-for-securing-JMX-authentication-for-nodetool-utility-OpsCenter-and-JConsole

Java seems to accept certificate with ANY CN [duplicate]

This question already has answers here:
Writing a SSL Checker using Java
(2 answers)
Closed 5 years ago.
This question is NOT a duplicate of question pointed to. There is NOWHERE in mentioned question anything about fact that TLS does not perform hostname verification by itself.
I have ActiveMQ instance and client in Java. Client uses JMSTemplate (org.springframework.jms.core.JmsTemplate) with factory org.apache.activemq.ActiveMQSslConnectionFactory. I have created self-signed certificates and with them trust store and keystore. Trust stores and keystores are read by both programs, I checked it by running both programs with
-Djavax.net.debug=all
Now my problem is that it seems that client absolutely ignores server hostname verification. Client connects to ActiveMQ using URL:
ssl://localhost:61616?jms.useCompression=true
Now, I tried to check whether everything will fail as expected if I change CN on ActiveMQ's certificate and well, it didn't went well. I changed to CN to e.g:
CN=google.com
or to:
CN=some.random.xxx333aaa.net.pp
but all these values seem to be OK with Java. Also note that there are no SANs (that is subjectAltNames). What more I tried to connect to ActiveMQ with such certificate but installed on different machine, and it seems that it all works well. Which is NOT what I want.
Also: I have finally uninstalled all Java versions and installed 1.8.0_144, using only JDK installer, installed jce_policy-8 in both places (it installs both JRE and JDK), did the same on remote machine too.
If you will examine RFC 2246 (TLS) and RFC 2818 (HTTPS) you will discover that hostname verification is part of HTTPS, not part of TLS. In TLS it is entirely up to the application to perform an authorization step.
So in fact my question is: how to force hostname verification?
See this answer.
Ok, I think I found an answer. Check this link:
https://issues.apache.org/jira/browse/AMQ-5443
and link mentioned in link above:
https://tersesystems.com/2014/03/23/fixing-hostname-verification/
It seems that TLS against what I thought DOES NOT PERFORM HOSTNAME VERIFICATION. This is absolutely stunning, but it seems that this is exactly the case. If no one will provide better answer I'll accept my own answer.
EDIT: Also see this:
https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html
and look specifically at this part:
Cipher Suite Choice and Remote Entity Verification
The SSL/TLS protocols define a specific series of steps to ensure a protected connection. However, the choice of cipher suite directly affects the type of security that the connection enjoys. For example, if an anonymous cipher suite is selected, then the application has no way to verify the remote peer's identity. If a suite with no encryption is selected, then the privacy of the data cannot be protected. Additionally, the SSL/TLS protocols do not specify that the credentials received must match those that peer might be expected to send. If the connection were somehow redirected to a rogue peer, but the rogue's credentials were acceptable based on the current trust material, then the connection would be considered valid.
When using raw SSLSocket and SSLEngine classes, you should always check the peer's credentials before sending any data. The SSLSocket and SSLEngine classes do not automatically verify that the host name in a URL matches the host name in the peer's credentials. An application could be exploited with URL spoofing if the host name is not verified.
Protocols such as HTTPS (HTTP Over TLS) do require host name verification. Applications can use HostnameVerifier to override the default HTTPS host name rules. See HttpsURLConnection for more information.

RabbitMQ authentication without password

Because I don't need to consider security issues in my application, I want to connect to RabbitMQ using the Java client without a password.
In the management UI, I set the users password to "no password". Then I tried it this way:
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("myuser");
connection = factory.newConnection();
Alternatively, I tried to assemble the URI by hand:
factory.setUri("amqp://myuser#localhost:5672");
...but in both cases the authentication fails with this exception:
Exception in thread "main" com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
at com.rabbitmq.client.impl.AMQConnection.start(AMQConnection.java:339)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:716)
at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:760)
at de.bmw.rabbitmq.workerqueue.Producer2.main(Producer2.java:51)
Is it even possible to get a connection without a password?
Passwordless authentication can be achieved by using the rabbitmq-auth-mechanism-ssl as documented here: https://github.com/rabbitmq/rabbitmq-auth-mechanism-ssl. This requires that SSL/TLS support is set up and working. If this option is chosen, a trusted root certificate is used for authentication, and any username/password is ignored altogether.
I'm currently investigating whether passwordless authentication is possible in conjunction with LDAP, but I haven't had any luck getting this to work.
Edit: In my environment, Windows services are authenticating using certificate-based auth, and the RabbitMQ cluster admins can authenticate to the management web UI using LDAP. In case you're interested in LDAP auth, here's another post about it.
Because I don't need to consider security issues in my application
I would heavily question this assumption. In fact, I would go so far as to say this is never correct.
That being said:
just use a simple password that anyone can know. It's going to be easier to do that, than to try and make RMQ work without a password.
To finalize this issue. As suggested by Derick Bailey: I helped myself by introducing (default) credentials for the different clients.

Javax.new.ssl.SSLHandShakeException Resolution

I'm receiving the ever so popular "SSLHandShakeException".
I'm running a java client using IntelliJ that is designed to handle web service requests/responses. We connect to server through a set of credentials and a url and pass in a request file.
What I've done
Verified the URL being constructed works in a browser.
Added the certificate to the trust store using these
instructions, Keytool Instructions
Verified the correct JRE is being used for the truststore.
I'm using an httpClient object. I instantiate the object as follows,
private void initConnection()
{
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(this.target.getHostName(), this.target.getPort()), new UsernamePasswordCredentials(this.userid, this.password));
this.httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
// Be able to deal with basic auth. Generate BASIC scheme object and
// add it to the local auth cache
BasicScheme basicScheme = new BasicScheme(); // we throw an error here
this.authCache.put(this.target, basicScheme);
localContext = HttpClientContext.create();
localContext.setAuthCache(this.authCache);
}
The execute for this object is as follows which is also the code throwing the error,
responseNode = this.httpClient.execute(getTarget(), httpRequest, responseHandler);
I've tried forcing the trust store in the process as follows,
System.setProperty("javax.net.ssl.trustStore", "....Common\JRE\lib\security\cacerts");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");
Works just fine against http when SSL is not involved.
Other then that I'm not an expert with SSL. I've performed quite a bit of digging and I am hoping someone out there has an idea. I'm certainly open to having not installed the cert properly (dozen times) or possibly I need to add some more code to correctly configure my objects. If there is missing information I would be happy to provide it!
Thanks well in advance.
Having had to deal with a number of SSL issues in Java clients myself I understand the frustration with the lack of useful detail in the error messages you are experiencing. Here are a few things you can try and verify.
That the server and the client can agree on the SSL version.
Like many protocols the SSL/TLS protocol has several versions out there. TLS implementations are practically always backwards compatible, but since the earlier versions of the protocol are considered insecure many servers and clients will not accept earlier version.
Hostname mismatch.
The TLS protocol specifies that even though a server's certificate might be trusted the certificate itself the common name of the certificate must match the hostname of the server. For example if a server at www.microsoft.com provided a www.google.com certificate the client would not accept the connection. This issue tends to be a big problem when people are connecting to internal servers, but not so much a problem when connecting to public servers. There is a pretty simple way to disable hostname verification with a custom SSL factory.
By using the custom HttpClient it is not looking at the system trust store by default from HttpClientBuilder docs:
When a particular component is not explicitly set this class will use its default implementation. System properties will be taken into account when configuring the default implementations when useSystemProperties() method is called prior to calling build().
Try using
HttpClients.custom().setDefaultCredentialsProvider(credsProvider).useSystemProperties().build();

How to use the Windows Keystore (MCS) with JDBC?

I am trying to create a java application that uses PKI for authentication. I need to be able to retrieve a certificate from the Microsoft Certificate Store (MCS) and pass it along to an Oracle database (11.2).
I am connecting using the jdbc:oracle:thin driver. After spending quite some time on google I have come up empty.
I've found different properties to change (depending on the article):
set the property javax.net.ssl.keyStoreType = "Windows-MY"
set the javax.net.ssl.keyStore = "Windows-MY"
javax.net.ssl.keyStore should be set to "None" (if using a custom KeyManager which I do not believe will work since by the time it gets into my custom KeyManager I will already be given the certs from a keystore specified in the connection properties).
Of course all of these people are claiming success, but nothing has worked for me. I have tried every example I have been able to find all with no luck. I was able to successfully authenticate when I was using Oracle wallets so I know my certificates are fine. If anyone has done this before and is willing to post some code that would be great.
I know most people are using the Windows keystore with a website and therefore are creating their own SSLContext, but I cannot imagine I am the only one who has wanted to do this using JDBC (which as far as I know does not allow me to provide it an SSLContext).
This is the code that I believe should work, but does not.
DriverManager.registerDriver)new OracleDriver());
String url = "jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=host)(PORT=2484))(CONNECT_DATA=(SERVICE_NAME=someName))(SECURITY= (SSL_SERVER_CERT_DN=\"CN=TESTSERVER\")))";
java.util.Properties props = new java.util.Properties();
props.setProperty("javax.net.ssl.keyStoreType", "Windows-MY");
props.setProperty("javax.net.ssl.keyStore", "NONE");
props.setProperty("javax.net.ssl.trustStoreType", "Windows-ROOT");
props.setProperty("javax.net.ssl.trustStore", "NONE");
props.setProperty("oracle.net.ssl_server_dn_match", "true");
props.setProperty("oracle.net.authentication_services", "(TCPS)");
Connection conn = DriverManager.getConnection(url, props);
This code fails with the exception:
java.sql.SQLRecoverableException: IOException: The Network Adapter could not establish the connection
This article should give your more details. Although it doesn't use the system properties, Windows-MY is clearly a store type and it's not file based. Therefore, javax.net.ssl.keyStoreType should be Windows-MY and javax.net.ssl.keyStore should be set to NONE (upper case may matter), see the JSSE Ref Guide (Customization):
javax.net.ssl.keyStore system property
Note that the value NONE may be specified. This setting is appropriate if the keystore is not
file-based (for example, it resides in a hardware token).
You may also need to configure your trust store in a similar way if your server certificate isn't trusted by your default Java trust store.

Categories