PDA

View Full Version : TLS and setupAuthenticatedEnvironment



willett
Sep 1st, 2006, 12:17 AM
I am trying to connect to Active Directory over TLS. I have two questions:

Is there a way to start (and stop) TLS through LdapTemplate?

Under the AbstractContextSource class, can someone elaborate on the setupAuthenticatedEnvironment method and how it is used with Active Directory?

rasky
Sep 1st, 2006, 03:26 AM
I'm afraid there is currently no way out of the box to handle TLS connections. I guess it would be possible to initiate TLS by subclassing ContextSource; the problem is the originial Context instance which will be lost when returning the new one to LdapTemplate.

I guess you could do it using a custom ContextExecutor or SearchExecutor, but that way you'll need to do most of the work yourself so not very much will be gained.

It's quite possible that support for TLS will be included in a future release. We have been discussing it, so it all basically depends on the demand.

mlarchet
Sep 4th, 2006, 03:43 AM
What do you want to do with TLS ?
I'm using LdapTemplate to connect to Active Directory successfully using global SSL connections, all you have to do is to specify 'ldaps' in your URL.

Everything works good if your server certificate is approved by the JVM.

RBS
Oct 18th, 2006, 07:34 AM
Hi, to add TLS I just created a subclass of LdapContextSource as follows. Maybe this could be integerated into Spring?

Regards
Ben Surgison

Code below:

package uk.co.ezsight.ldapdao;

import java.io.IOException;
import java.security.KeyStore;
import java.util.Hashtable;

import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.StartTlsRequest;
import javax.naming.ldap.StartTlsResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.support.LdapContextSource ;

/**
* ContextSource implementation which overrides setupAuthenticatedEnvironment to
* allow keystore authentication.
*
* @author Ben Surgison
*
*/
public class MyLdapContextSource extends LdapContextSource {

private static final Log log = LogFactory.getLog(MyLdapContextSource.class);

private static final String KEYSTORE = "javax.net.ssl.keyStore";
private static final String KEYSTORETYPE = "javax.net.ssl.keyStoreType";
private static final String KEYSTOREPASSWORD = "javax.net.ssl.keyStorePassword";
private static final String TRUSTSTORE = "javax.net.ssl.trustStore";
private static final String TRUSTSTORETYPE = "javax.net.ssl.trustStoreType";
private static final String TRUSTSTOREPASSWORD = "javax.net.ssl.trustStorePassword";

private String keyStore;
private String keyStoreType;
private String keyStorePassword;
private String trustStore;
private String trustStoreType;
private String trustStorePassword;

/**
* Overridden implementation to allow TLS to be started
*/
public DirContext getReadOnlyContext() {
LdapContext ctx = (LdapContext) super.getReadOnlyContext();

// only start tls if keyStore has been set.
if(this.keyStore==null&&this.keyStore.length()>0){
// Start TLS
StartTlsResponse tls;
try {
tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
tls.negotiate();
} catch (NamingException ne) {
log.error(ne.getLocalizedMessage(),ne);
} catch (IOException ioe) {
log.error(ioe.getLocalizedMessage(),ioe);
}
}
return ctx;
}

/**
* Overridden implementation of setting the environment up to be authenticated.
* This allows a keyStore certificate to be used for SASL security.
*
* @param env
* the environment to modify.
*/
@SuppressWarnings("unchecked")
protected void setupAuthenticatedEnvironment(Hashtable env) {

// revert to original if keyStore hasn't been set.
if(this.keyStore==null&&this.keyStore.length()>0){
super.setupAuthenticatedEnvironment(env);
return;
}

// Setup keyStore system properties.
System.setProperty(KEYSTORE, getMyQualifiedName(this.keyStore));
System.setProperty(KEYSTOREPASSWORD, this.keyStorePassword);
System.setProperty(KEYSTORETYPE, getMyKeyStoreType(this.keyStoreType));

// Setup trustStore system properties.
System.setProperty(TRUSTSTORE, getMyQualifiedName(this.trustStore));
System.setProperty(TRUSTSTOREPASSWORD, this.trustStorePassword);
System.setProperty(TRUSTSTORETYPE, getMyKeyStoreType(this.trustStoreType));
}

private String getMyKeyStoreType(String keyStoreType) {
if(keyStoreType!=null&&keyStoreType.length()>0){
return keyStoreType;
}
return KeyStore.getDefaultType();
}

private String getMyQualifiedName(String filename) {
String qualifiedName = null;
if(filename.indexOf("/")>-1||filename.indexOf("\\")>-1){
qualifiedName = filename; // use full name as entered
}
else{
try{
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
qualifiedName = classLoader.getResource(filename).toExternalForm() ; // get full name from classpath
qualifiedName = qualifiedName.substring(6);
}
catch(Exception e){
log.error("Missing file: " + filename,e);
}
}
return qualifiedName;
}

/**
* @param keyStore the keyStore to set
*/
public void setKeyStore(String keyStore) {
this.keyStore = keyStore;
}

/**
* @param keyStorePassword the keyStorePassword to set
*/
public void setKeyStorePassword(String passPhrase) {
this.keyStorePassword = passPhrase;
}

/**
* @param keyStoreType the keyStoreType to set
*/
public void setKeyStoreType(String keyStoreType) {
this.keyStoreType = keyStoreType;
}

/**
* @param trustStore the trustStore to set
*/
public void setTrustStore(String trustStore) {
this.trustStore = trustStore;
}

/**
* @param trustStorePassword the trustStorePassword to set
*/
public void setTrustStorePassword(String trustStorePassword) {
this.trustStorePassword = trustStorePassword;
}

/**
* @param trustStoreType the trustStoreType to set
*/
public void setTrustStoreType(String trustStoreType) {
this.trustStoreType = trustStoreType;
}

}

rasky
Oct 19th, 2006, 08:31 AM
Ben,
Good to see some code. There's a Jira issue on adding support for TLS connections to Spring LDAP (http://opensource.atlassian.com/projects/spring/browse/LDAP-8). If you would attach your code there, preferrably with corresponding junit test code, we'll take it into account when starting to work on this issue.
Cheers!

RBS
Oct 23rd, 2006, 07:37 AM
Rasky,

Please let me know how to apply for a log on so that I can attach my source code.

Regards
Ben Surgison
BenSurgison@Hotmail.com

rasky
Oct 23rd, 2006, 07:51 AM
You can sign up for an account directly on the site. Just click 'Log in' and then 'Signup' and you should be on your way.

bjwarner
Nov 9th, 2008, 10:41 PM
Thanks very much Ben. This code got things working for me.

Just wanted to point out that I think there might have been a couple of small errors in your code, around the...


if(this.keyStore == null && this.keyStore.length() > 0)

...statements. Have put fixed version below.



package uk.co.ezsight.ldapdao;

import java.io.IOException;
import java.security.KeyStore;
import java.util.Hashtable;

import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.StartTlsRequest;
import javax.naming.ldap.StartTlsResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.support.LdapContextSource ;

/**
* ContextSource implementation which overrides setupAuthenticatedEnvironment to
* allow keystore authentication.
*
* @author Ben Surgison
*
*/
public class MyLdapContextSource extends LdapContextSource {
private static final Log log = LogFactory.getLog(SSLLdapContextSource.class);

private static final String KEYSTORE = "javax.net.ssl.keyStore";
private static final String KEYSTORETYPE = "javax.net.ssl.keyStoreType";
private static final String KEYSTOREPASSWORD = "javax.net.ssl.keyStorePassword";
private static final String TRUSTSTORE = "javax.net.ssl.trustStore";
private static final String TRUSTSTORETYPE = "javax.net.ssl.trustStoreType";
private static final String TRUSTSTOREPASSWORD = "javax.net.ssl.trustStorePassword";

private String keyStore;
private String keyStoreType;
private String keyStorePassword;
private String trustStore;
private String trustStoreType;
private String trustStorePassword;

/**
* Overridden implementation to allow TLS to be started
*/
public DirContext getReadOnlyContext() {
LdapContext ctx = (LdapContext) super.getReadOnlyContext();

// only start tls if keyStore has been set.
if (this.keyStore != null && this.keyStore.length() > 0) {
// Start TLS
StartTlsResponse tls;
try {
tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest());
tls.negotiate();
} catch (NamingException ne) {
log.error(ne.getLocalizedMessage(), ne);
} catch (IOException ioe) {
log.error(ioe.getLocalizedMessage(), ioe);
}
}
return ctx;
}

/**
* Overridden implementation of setting the environment up to be authenticated. This allows a keyStore certificate
* to be used for SASL security.
*
* @param env
* the environment to modify.
*/
@SuppressWarnings("unchecked")
protected void setupAuthenticatedEnvironment(Hashtable env) {
super.setupAuthenticatedEnvironment(env);

// revert to original if keyStore hasn't been set.
if (this.keyStore == null || this.keyStore.length() == 0) {
return;
}

// Setup keyStore system properties.
System.setProperty(KEYSTORE, getMyQualifiedName(this.keyStore));
System.setProperty(KEYSTOREPASSWORD, this.keyStorePassword);
System.setProperty(KEYSTORETYPE, getMyKeyStoreType(this.keyStoreType));

// Setup trustStore system properties.
System.setProperty(TRUSTSTORE, getMyQualifiedName(this.trustStore));
System.setProperty(TRUSTSTOREPASSWORD, this.trustStorePassword);
System.setProperty(TRUSTSTORETYPE, getMyKeyStoreType(this.trustStoreType));
}

private String getMyKeyStoreType(String keyStoreType) {
if (keyStoreType != null && keyStoreType.length() > 0) {
return keyStoreType;
}
return KeyStore.getDefaultType();
}

private String getMyQualifiedName(String filename) {
String qualifiedName = null;
if (filename.indexOf("/") > -1 || filename.indexOf("\\") > -1) {
qualifiedName = filename; // use full name as entered
} else {
try {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
qualifiedName = classLoader.getResource(filename).toExternalForm() ; // get full name from classpath
qualifiedName = qualifiedName.substring(6);
} catch (Exception e) {
log.error("Missing file: " + filename, e);
}
}
return qualifiedName;
}

/**
* @param keyStore
* the keyStore to set
*/
public void setKeyStore(String keyStore) {
this.keyStore = keyStore;
}

/**
* @param keyStorePassword
* the keyStorePassword to set
*/
public void setKeyStorePassword(String passPhrase) {
this.keyStorePassword = passPhrase;
}

/**
* @param keyStoreType
* the keyStoreType to set
*/
public void setKeyStoreType(String keyStoreType) {
this.keyStoreType = keyStoreType;
}

/**
* @param trustStore
* the trustStore to set
*/
public void setTrustStore(String trustStore) {
this.trustStore = trustStore;
}

/**
* @param trustStorePassword
* the trustStorePassword to set
*/
public void setTrustStorePassword(String trustStorePassword) {
this.trustStorePassword = trustStorePassword;
}

/**
* @param trustStoreType the trustStoreType to set
*/
public void setTrustStoreType(String trustStoreType) {
this.trustStoreType = trustStoreType;
}
}

rasky
Nov 10th, 2008, 12:39 AM
Please note that as of Spring LDAP 1.3.0 (Spring LDAP 1.3.0.RC1 is out now) extensions to the context authentication mechanism should be done using a DirContextAuthenticationStrategy (http://static.springframework.org/spring-ldap/docs/1.3.x/apidocs/org/springframework/ldap/core/support/DirContextAuthenticationStrategy.html) rather than from subclassing LdapContextSource. More specifically there are two different implementations for working with TLS connections: DefaultTlsDirContextAuthenticationStrategy (http://static.springframework.org/spring-ldap/docs/1.3.x/apidocs/org/springframework/ldap/core/support/DefaultTlsDirContextAuthenticationStrategy.html) and ExternalTlsDirContextAuthenticationStrategy (http://static.springframework.org/spring-ldap/docs/1.3.x/apidocs/org/springframework/ldap/core/support/ExternalTlsDirContextAuthenticationStrategy.html) included with the distribution.

Veena
Dec 17th, 2009, 07:47 AM
Hi Rasky,

Recently i switched to 3.0 and thanks for all your efforts, the code looks much better.
Before switching i had customized the contextSource as exemplified in this thread for change password functionality and could set the trust store related information by overriding the setupEnivorment method. It was working fine.
How is it possible to achieve the same with DefaultTlsDirContextAuthenticationStrategy as setupEnvironment() is final and the applyAuthentication method is not getting invoked. Result of which i get sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderE xception: unable to find valid certification path to requested target

Please let me know how to pass trustore information using DefaultTlsDirContextAuthenticationStrategy?

thanks and regards,
Veena

mmshanka
Nov 5th, 2010, 05:03 PM
I have been using 1.2 version and we finally decided to support TLS since 1.3 now provides a way to do this. We have been using ldaptemplate for all the queries. Here is what I have:

final LdapContextSource context = configureContextSource();
final SpringSecurityLdapTemplate template =
new SpringSecurityLdapTemplate( context );

// Active Directory doesn’t transparently handle referrals. This fixes that.
template.setIgnorePartialResultException(true);

// Searching for classSchema since we expect this to be present as a part of all the LDAP Schemas.
// This should help us confirm that the LDAP connection related params are all fine.
template.searchForSingleAttributeValues(…..);

——————————-
private LdapContextSource configureContextSource() throws DirectoryServiceConfigurationException {

MyTlsDirContextAuthenticationStrategy authenticationStrategy =
new MyTlsDirContextAuthenticationStrategy();

final String url = buildLdapURL();
LdapContextSource ctxSrc = new LdapContextSource();
ctxSrc.setUrl(url);
ctxSrc.setCacheEnvironmentProperties(false);

if(!ldapConfig.get(LDAP_USE_ANONYMOUS_BIND).getPre ferenceValueBoolean()) {
ctxSrc.setUserDn(ldapConfig.get(LDAP_BIND_DN).getP referenceValue());
ctxSrc.setPassword(ldapConfig.get(LDAP_BIND_PASSWO RD).getPreferenceValue());
}

ctxSrc.setAuthenticationStrategy(authenticationStr ategy);

try {
ctxSrc.afterPropertiesSet();
} catch (final Exception ex) {
log.error(ErrorCode.LDAP_INIT_SECURITYCONTEXT_FAIL ED.getCodeString() +
ErrorCode.LDAP_INIT_SECURITYCONTEXT_FAILED.getDesc ription(), ex);
throw new DirectoryServiceConfigurationException(ErrorCode.L DAP_INIT_SECURITYCONTEXT_FAILED.getDescription(),
ErrorCode.LDAP_INIT_SECURITYCONTEXT_FAILED.getCode ());
}

return ctxSrc;
}

——————-

MyTlsDirContextAuthenticationStrategy is extended from DefaultTlsDirContextAuthenticationStrategy only to set the system properties for keystore and other related properties.

I have a open Ldap server setup to support TLS. Code looks much more clean to me. However, when the template.searchForSingleAttributeValues(…..); is invoked, it complains of TLS already started.

I drilled down more and found that,

LdapTemplate.search(……) –> AbstractContextSource.getReadOnlyContext() –> AbstractContextSource.getContext(String principal, String credentials) –> authenticationStrategy.processContextAfterCreation (…)

will now try to Start TLS again and fails since it is already started and the exception is thrown which results in search failure.

I am not seeing a way I can bypass this issue since every operation on the LdapTemplate will try to obtain a ReadOnlyContext and will fail at the same place since TLS is already started. I don’t think this will go away since LdapTemplate is very specific to Spring-ldap.

However, please suggest a workaround if possible or other ideas/suggestions.

--------------------------------------

On a different note, extending the LdapContextSource in 1.2 to support TLS worked fine in the first instance of starting TLS. However, subsequent changes to the properties or removing the keystore has no effect on the context that was established in the first attempt.

Seems to me like something is being cached. I tried removing pooling and not caching environment properties, but the issue doesn’t seem to go away. On restarting my server, the issue gets resolved and the new context I obtain behaves as expected.

Can’t seem to understand what may be going wrong. Suggestions are welcome.

Veena
Nov 10th, 2010, 03:36 AM
Hi Shanka,

We shouldn't be sub classing the DefaultTlsDirContextAuthenticationStrategy but add it as attribute to the MyLdapContextSource in config file.

<bean id="securedContextSource" class ="MyLdapContextSource "
<property name="url" value="<your ldap server>" />
<property name="base" value="<OU base>" />
<property name="userDn" value="<userDn>" />
<property name="password" value="<password>" />
<property name="pooled" value="false" />
<property name="authenticationStrategy">
<bean class="org.springframework.ldap.core.support.DefaultTlsDi rContextAuthenticationStrategy">
<property name="shutdownTlsGracefully" value="true"></property> </bean>


let me know if this helps you.
best regards,
Veena

mmshanka
Nov 10th, 2010, 12:35 PM
Hi Veena,

Thank you for the reply. I was only extending the DefaultTlsDirContextAuthenticationStrategy to add environment properties. It wasn't really doing anything more than that.

I have already tried using the the Default strategy and it doesn't work as expected. I tried it again following your suggestion.

The reason is the following. I don't land into this 1.2 since my extension handles the naming exception for TLS already started, which is being thrown in 1.3.

Caused by: javax.naming.NamingException: [LDAP: error code 1 - TLS already started]; remaining name ''
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.jav a:3081)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCt x.java:2987)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCt x.java:2794)
at com.sun.jndi.ldap.LdapCtx.extendedOperation(LdapCt x.java:3166)
at javax.naming.ldap.InitialLdapContext.extendedOpera tion(InitialLdapContext.java:164)
at org.springframework.ldap.core.support.AbstractTlsD irContextAuthenticationStrategy.processContextAfte rCreation(AbstractTlsDirContextAuthenticationStrat egy.java:104)
at org.springframework.ldap.core.support.AbstractCont extSource.getContext(AbstractContextSource.java:10 9)

Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 1 - TLS already started]; remaining name '']
org.springframework.ldap.UncategorizedLdapExceptio n: Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 1 - TLS already started]; remaining name ''
at org.springframework.ldap.support.LdapUtils.convert LdapException(LdapUtils.java:215)
at org.springframework.ldap.core.support.AbstractCont extSource.getContext(AbstractContextSource.java:11 4)
at org.springframework.ldap.core.support.AbstractCont extSource.getReadOnlyContext(AbstractContextSource .java:125)
at org.springframework.ldap.core.LdapTemplate.search( LdapTemplate.java:287)
at org.springframework.ldap.core.LdapTemplate.search( LdapTemplate.java:259)
at org.springframework.ldap.core.LdapTemplate.search( LdapTemplate.java:606)
at org.springframework.ldap.core.LdapTemplate.search( LdapTemplate.java:524)
at org.springframework.security.ldap.SpringSecurityLd apTemplate.searchForSingleAttributeValues(SpringSe curityLdapTemplate.java:170)

webuser
Jan 19th, 2011, 09:08 AM
Hi Shanka,

I have the same problem. The business requirement is that I authenticate user supplied credentials with our directory server via LDAP. I first set up the following in Spring configuration XML:


<bean id="SSLKeyStoreAccess" class="org.springframework.beans.factory.config.MethodInv okingFactoryBean">
<property name="targetObject">
<bean class="org.springframework.beans.factory.config.MethodInv okingFactoryBean">
<property name="targetClass" value="java.lang.System" />
<property name="targetMethod" value="getProperties" />
</bean>
</property>
<property name="targetMethod" value="putAll" />
<property name="arguments">
<util:properties>
<!-- JKS trustStore contains server public key -->
<prop key="javax.net.ssl.trustStore">C:/servercacerts</prop>
<prop key="javax.net.ssl.trustStorePassword">servercertspwd</prop>
<prop key="javax.net.ssl.trustStoreType">JKS</prop>
<!-- PKCS12 keyStore contains client's (ldapuser) private key -->
<prop key="javax.net.ssl.keyStore">C:/ldapuser-certificate.PFX</prop>
<prop key="javax.net.ssl.keyStorePassword">ldapuserpwd</prop>
<prop key="javax.net.ssl.keyStoreType">PKCS12</prop>
</util:properties>
</property>
</bean>

<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextS ource">
<property name="url" value="ldaps://192.168.1.10:636" />
<property name="pooled" value="false" />
<!-- Setting authentication strategy seems to be causing a problem that does not exist without this property setting -->
<property name="authenticationStrategy">
<bean class="org.springframework.ldap.core.support.ExternalTlsD irContextAuthenticationStrategy">
<property name="shutdownTlsGracefully" value="true" />
</bean>
</property>
</bean>

<bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>

In Java code, I first determine the actual DN for the user with this method, before invoking the authenticate method on ldapTemplate. This is where I am running into the same error as you, i.e. "TLS already started". If I remove the setAuthenticationStrategy(externalTlsDirContextAut henticationStrategy) in Spring configuration, this method below works just fine.


public String getUserDNByUserName(String userName) {

AndFilter filter = new AndFilter()
.and(new EqualsFilter("objectclass", "person"))
.and(new EqualsFilter("cn", userName));

List result = ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), new AbstractContextMapper() {

@Override
protected Name doMapFromContext(DirContextOperations ctx) {
return ctx.getDn();
}
});

if (result == null || result.size() != 1) {
throw new RuntimeException("User not found or not unique");
}

return result.get(0).toString();
}


Were you able to resolve this eventually?

Thanks.

Ashwin

Veena
Jan 20th, 2011, 11:13 AM
Hi Ashwin,

Why are you using ldaps and 636 port. Ldaps is for app which are accessed via https.
For TLS we don't need ldaps and port 636.


You need to subclass the DefaultSpringSecurityContextSource like this

/**
* ContextSource implementation which overrides setupAuthenticatedEnvironment to allow TLS.
*
* */
public class SecuredLdapContextSource extends DefaultSpringSecurityContextSource {


/**
* Provider url is used in the default constructor of this class. The value for this property is set up from
* ContextSourceHelper bean.
*
* @see ContextSourceHelper
*/
public static String providerUrl;

// default constructor is required by proxy
// DO NOT REMOVE
public SecuredLdapContextSource() {
// for some reason the super class does not have a default constructor
// but the ldap url is autowired in the bean definition
super(providerUrl);
}

}

and your config will be

<bean id="securedContextSource" class ="security.helper.SecuredLdapContextSource">
<property name="url" value=" ldap://servername:389" />
<qualifier value="secured"/>
<property name="base" value="ou=networks,dc=com" />
<property name="userDn" value="cn=test,dc=com" />
<property name="password" value="passMe!" />
<property name="pooled" value="false" />
<property name="authenticationStrategy">
<bean class="org.springframework.ldap.core.support.DefaultTlsDi rContextAuthenticationStrategy">
<property name="shutdownTlsGracefully" value="true"></property>
</bean>
</property>

Keep in mind that using secure connection to ldap server brings down the speed of your app, hence we need to swtich between secured and non-secured contexts. hence qualifier secure is used, you can have contextSource extending org.springframework.security.ldap.DefaultSpringSec urityContextSource with qualified nonsecured.
use secured connection only for password change.

hope it helps,
Best regards,
Veena

webuser
Jan 20th, 2011, 03:28 PM
Hi Veena,

Like I said in my earlier post, I am contacting the LDAP server only for authenticating the user against the domain (Novell, in my case). I need to employ SASL EXTERNAL mechanism over TLS to perform authentication of a user authorized to interact with Novell for this purpose alone (ldapuser, in my case).

Here is an example from the Novell LDAP for Java code libraries:


int ldapVersion = LDAPConnection.LDAP_V3;
String ldapHost = "ldap.server.address";
int ldapSSLPort = 636;
String tStore = "C:/servercacerts";
String tStorePass = "servercertspwd";
String kStore = "C:/ldapuser-certificate.PFX";
String kStorePass = "ldapuserpwd";
String kStoreType = "PKCS12";
String[] mechanism = {"EXTERNAL"};

System.setProperty("javax.net.ssl.trustStore",tStore);
System.setProperty("javax.net.ssl.trustStorePassword",tStorePass);
System.setProperty("javax.net.ssl.keyStore",kStore);
System.setProperty("javax.net.ssl.keyStorePassword",kStorePass);
System.setProperty("javax.net.ssl.keyStoreType",kStoreType);

LDAPJSSESecureSocketFactory ssf = new LDAPJSSESecureSocketFactory();
LDAPConnection conn = new LDAPConnection(ssf);

try {
Security.addProvider(new com.novell.sasl.client.SaslProvider());
}
catch(Exception e) {
System.err.println("Error loading security provider (" + e.getMessage() + ")");
}

try {

conn.connect( ldapHost, ldapSSLPort);
conn.bind((String) null, (String) null, mechanism, null, (Object)null);

System.out.println((conn.isBound()) ? "\n\tAuthenticated to the server ( sslExternal bind )\n": "\n\tNot authenticated to the server\n");

// disconnect with the server
conn.disconnect();
}
catch( LDAPException e ) {
System.out.println( "Error: " + e.toString() );
}


This is why I was trying to use Spring LDAP's ExternalTlsDirContext... authentication strategy. I think I missed another part of my Spring configuration (to add a security provider from the Novell API):


<bean class="org.springframework.beans.factory.config.MethodInv okingFactoryBean">
<property name="staticMethod" value="java.security.Security.addProvider" />
<property name="arguments">
<bean class="com.novell.sasl.client.SaslProvider" />
</property>
</bean>


I do appreciate your suggestion and perhaps I will wait for your opinion based on the above.

Thanks!

Ashwin