Need some guidance.
I have java webstart app and I want it to connect to a server via SSL.just adding a property like:System.setProperty("javax.net.ssl.trustStore","my.keystore");But since a JAWS program is downloaded from server didn't work and don't have a my.keystore on local file system. So decided to distribute the certificate to all clients.I did the following and it worked.
But I am sure there must be better solutions than this.. Any ideas to make it better?
public boolean validateUserFromActiveDirectory(String userId) {
final String MEMBER_GROUP = "CN=asdadasd,OU=asdasdasd Accounts,OU=adasdas,OU=asdasdas,DC=asdasdas,DC=asdasdas,DC=adasdasd,DC=asdasdasd";
String employeeNumber = "";
final String LDAP_INIT_CTX = "com.sun.jndi.ldap.LdapCtxFactory";
final String LDAP_URL = "ldap://xx-ssssssss.eee.eee.eeeee.eeeee:636";
final String MY_ATTRS[] = { "employeeNumber" };
String adminPassword = "somepassword";
String securityProtocol = "ssl";
boolean isValidUser = false;
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_INIT_CTX);
env.put(Context.PROVIDER_URL, LDAP_URL);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.REFERRAL, "follow");
env.put(Context.SECURITY_PRINCIPAL, MEMBER_GROUP);
env.put(Context.SECURITY_CREDENTIALS, adminPassword);
env.put(Context.SECURITY_PROTOCOL, securityProtocol);
//C:\Documents and Settings\yourusername\Local Settings\Temp
File tf = File.createTempFile("someTruststore", ".jks");
tf.deleteOnExit();
byte buffer[] = new byte[0x1000];
ClassLoader cl = JNDI.class.getClassLoader();
InputStream in = cl.getResourceAsStream(
"someTruststore.jks");
FileOutputStream out = new FileOutputStream(tf);
int cnt;
while ((cnt = in.read(buffer)) != -1)
out.write(buffer, 0, cnt);
in.close();
out.close();
System.setProperty("javax.net.ssl.trustStore", tf
.getAbsolutePath());
DirContext context = new InitialLdapContext(env, null);
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration results = context.search(
"XX=ent,XX=abc,XX=aaaaa,XX=aaaa", "(sAMAccountName="
+ userId + ")", searchControls);
if (results != null && results.hasMore()) {
//some logic
}
}
} catch (Exception e) {
e.printStackTrace();
}
return isValidUser;
}
-Padur ===========================**=============
/**
* */
package util;
/**
* @author spaduri
*
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
public class CustomSSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory factory;
public CustomSSLSocketFactory() {
try {
SSLContext sslcontext = null;
// Call getKeyManagers to get suitable key managers
KeyManager[] kms=getKeyManagers();
if (sslcontext == null) {
sslcontext = SSLContext.getInstance("SSL");
sslcontext.init(kms,
new TrustManager[] { new CustomTrustManager() },
new java.security.SecureRandom());
}
factory = (SSLSocketFactory) sslcontext.getSocketFactory();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static SocketFactory getDefault() {
return new CustomSSLSocketFactory();
}
public Socket createSocket(Socket socket, String s, int i, boolean flag) throws IOException {
return factory.createSocket(socket, s, i, flag);
}
public Socket createSocket(InetAddress inaddr, int i, InetAddress inaddr1, int j) throws IOException {
return factory.createSocket(inaddr, i, inaddr1, j);
}
public Socket createSocket(InetAddress inaddr, int i) throws IOException {
return factory.createSocket(inaddr, i);
}
public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
return factory.createSocket(s, i, inaddr, j);
}
public Socket createSocket(String s, int i) throws IOException {
return factory.createSocket(s, i);
}
public String[] getDefaultCipherSuites() {
return factory.getSupportedCipherSuites();
}
public String[] getSupportedCipherSuites() {
return factory.getSupportedCipherSuites();
}
protected KeyManager[] getKeyManagers()
throws IOException, GeneralSecurityException
{
// First, get the default KeyManagerFactory.
String alg=KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmFact=KeyManagerFactory.getInstance(alg);
// Next, set up the KeyStore to use. We need to load the file into
// a KeyStore instance.
ClassLoader cl = CustomSSLSocketFactory.class.getClassLoader();
// read the file someTrustStore from the jar file from a classpath
InputStream in = cl.getResourceAsStream("ssl/someTruststore.jks");
//FileInputStream fis=new FileInputStream(adentTruststore.jks);
KeyStore ks=KeyStore.getInstance("jks");
ks.load(in, null);
in.close();
// Now we initialise the KeyManagerFactory with this KeyStore
kmFact.init(ks, null);
// And now get the KeyManagers
KeyManager[] kms=kmFact.getKeyManagers();
return kms;
}
}
package util;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class CustomTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] cert, String authType) {
return;
}
public void checkServerTrusted(X509Certificate[] cert, String authType) {
return;
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
Laz appreciate your patience, trying to learn when I get some time. I started writing my own CustomSSLSocketFactory..right now I am bypassing security...based on the example by platinum solutions.If I do that ...will the information pass as a clear text on the network?
Now I wonder what should I do with the truststore file I am having "sometruststore.jks" file. What should I do with that ..Do I have wrie my own custom trustmanager software ? Please guide me in correct direction.
-padur
You could do it without having to rely on system properties and the file system. Reading the keystore as a stream like you are doing and creating your own SSLSocketFactory would be much cleaner.
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
...
// assume keyStore is the KeyStore you read via getResourceAsStream
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(keyStore);
final SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
final URL url = new URL("https://whatever");
final HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
...
I haven't verified but I see no reason why this shouldn't work through Webstart.
Updated:
You mention that you are looking to connect to active directory so I'm guessing you are going to use LDAPS as the protocol? If so, maybe the code at this URL can serve as inspiration? You'll have to create a subclass of javax.net.ssl.SSLSocketFactory
(see BlindSSLSocketFactoryTest
at that platinumsolutions link) that wraps the logic above of creating the the SSLContext
and delegates calls to the SSLSocketFactory
that context.getSocketFactory()
creates.
public class TrustedSSLSocketFactory extends SSLSocketFactory {
private static SSLContext context;
public static void initTrustedSSLSocketFactory(final KeyStore keyStore) throws Exception {
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(keyStore);
final SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
}
public static SocketFactory getDefault() {
return context.getSocketFactory();
}
public Socket createSocket(String arg0, int arg1) throws IOException, UnknownHostException {
return trustedFactory.createSocket(arg0, arg1);
}
public Socket createSocket(InetAddress arg0, int arg1) throws IOException {
return trustedFactory.createSocket(arg0, arg1);
}
public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) throws IOException, UnknownHostException {
return trustedFactory.createSocket(arg0, arg1, arg2, arg3);
}
public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, int arg3) throws IOException {
return trustedFactory.createSocket(arg0, arg1, arg2, arg3);
}
}
Hopefully that compiles, I'm unable to test it at the moment! Also note the laziness with the throws
clause on initTrustedSSLSocketFactory
.
Then when you setup the LDAP environment, use
TrustedSSLSocketFactory.initTrustedSSLSocketFactory(keyStore);
env.put("java.naming.ldap.factory.socket", TrustedSSLSocketFactory.class.getName())
in a similar manner to the sample code at platinumsolutions. Hopefully this is more of what you're looking for?