how ldap authentication works with active directory and the uwwi

39
How LDAP Authentication works with Active Directory and the UWWI This document provides background on what LDAP authentication is, what specific LDAP authentication methods and mechanisms Active Directory and UWWI supports, and finally gives some guidance on which method and mechanism you should use. LDAP Authentication LDAP authentication is a loaded term which simply means to issue the LDAP BIND operation. Since the LDAP BIND operation is very flexible, this means there are a variety of forms this authentication might take. These forms include extremes such as: cleartext passwords over the wire no identifying name specified choosing not to authenticate authentication with a certificate authentication using some custom method as well as more traditional forms where a name (username) and password are used, and the password is encrypted on the wire or a private/public key algorithm used to protect the password. Active Directory supports all the LDAP standard authentication mechanisms, as well as a few more, but many of these more extreme forms are not supported by UWWI, usually because they violate computing standards.

Upload: vgprasad

Post on 13-Sep-2015

270 views

Category:

Documents


4 download

DESCRIPTION

On LDAP authantication

TRANSCRIPT

How LDAP Authentication works with Active Directory and the UWWI This document provides background on what LDAP authentication is, what specific LDAP authentication methods and mechanisms Active Directory and UWWI supports, and finally gives some guidance on which method and mechanism you should use. LDAP AuthenticationLDAP authentication is a loaded term which simply means to issue the LDAP BIND operation. Since the LDAP BIND operation is very flexible, this means there are a variety of forms this authentication might take. These forms include extremes such as: cleartext passwords over the wire no identifying name specified choosing not to authenticate authentication with a certificate authentication using some custom methodas well as more traditional forms where a name (username) and password are used, and the password is encrypted on the wire or a private/public key algorithm used to protect the password. Active Directory supports all the LDAP standard authentication mechanisms, as well as a few more, but many of these more extreme forms are not supported by UWWI, usually because they violate computing standards.The LDAP standard introduces the various forms of authentication by first categorizing them as authentication methods, with various authentication mechanisms underlying each method. This document follows that organizational precedent.Authentication MethodsThere are two primary authentication methods that must be supported by RFC standard: Simple Authentication Method SASL Authentication MethodOther authentication methods *may* be supported, but are not part of the LDAP standard and so are likely to be less widely used by LDAP applications.Each method has many authentication mechanisms, and the RFC standards specify that a number of these mechanisms must be supported.Active Directory may accept a number of additional methods, but because of lack of good Microsoft documentation, these additional methods can't be covered here at all. However, this lack of documentation also means that applications won't know how to use them either, so Active Directory might as well not provide these undocumented methods at all.Simple Authentication MethodThe simple authentication method provides three authentication mechanisms: Anonymous Authentication Mechanism of Simple BindA simple LDAP bind operation with a name and password value of zero length. UWWI allows this, but you can't do anything meaningful. Unauthenticated Authentication Mechanism of Simple BindA simple LDAP bind operation with a non-zero length name that corresponds to a valid user entry and a password value of zero length. UWWI allows this, but you can't do anything meaningful. Name/Password Authentication Mechanism of Simple BindA simple LDAP bind operation with a name that corresponds to a valid user entry and the password value corresponding to that user entry. The password is sent in cleartext over the wire.

This is possible with UWWI, however, using this mechanism without first initiating session level encryption is prohibited by UWWI because it fails to meet UW computing standards. Currently there is no way to turn off this functionality, but should a way to turn this mechanism (w/o session-level encryption) become available, it will be turned off.

You can initiate session level encryption via a StartTLS operation or by using IPsec. We *strongly* recommend that a network sniffer first be used with any application that must use this authentication mechanism to verify that it is using session-level encryption and not exposing UW NetID passwords.Fast Bind for Authentication Only

In addition to authentication methods and mechanisms, there is one noteworthy LDAP session option that may be of interest. The Concurrent bind or Fast Bind session option can be used by applications to authenticate users, assuming that only authentication is needed, and no subsequent LDAP operations requiring authorization are needed. A Fast Bind does not build a user token; it only verifies the username and password--so subsequent LDAP operations that would require the authorization information in that token are not allowed. The LDAP Fast Bind requires that the Simple Authentication Method be used, and so TLS or IPsec must be used in association with making use of this option. Sample code and more information are available on MSDN. SASL Authentication MethodThe SASL authentication method is a framework for providing authentication and data security services in connection-oriented protocols via replaceable mechanisms. The SASL standard (RFC4422) only defines one such mechanism, the EXTERNAL authentication mechanism, however the SASL standard expects many authentication mechanisms to be defined to work within its framework.Active Directory supports four SASL authentication mechanisms: GSSAPI Authentication MechanismThe GSSAPI authentication mechanism (RFC2743) allows the client to pass GSSAPI tokens to the server to establish their credentials. In this case, valid GSSAPI tokens are a Kerberos TGT or NTLM token (although some Microsoft documentation erroneously claims that GSSAPI is limited to Kerberos). A confidentiality feature can be employed as part of GSSAPI to encrypt the token and authentication exchange.

A SASL GSSAPI LDAP bind operation with a name that corresponds to a valid user entry and the password value corresponding to that user entry. The password is not sent over the wire at all, instead the token representing the user is sent.

UWWI recommends this authentication mechanism. When it is known that the client can only negotiate NTLMv2, we suggest that a network sniffer be used with any application to verify that the confidentiality feature is used to protect NTLM tokens. GSS-SPNEGO Authentication MechanismThe GSS-SPNEGO authentication mechanism (RFC4178) is actually the GSSAPI authentication mechanism but with a client-server negotiation mechanism that provides for selection of the preferred security mechanism that both client and server support. In this case, the server will prefer Kerberos then NTLMv2 then NTLM (UWWI does not support LM). For that reason, refer to the GSSAPI authentication mechanism for further details. EXTERNAL Authentication MechanismThe EXTERNAL authentication mechanism allows the client to request that the server use credentials established by a means external to the mechanism to authenticate the client. The external means might be via information in IPsec or TLS or some other other means. What means are used depends on the server, and there is no negotiation of what those means are, so the client must know beforehand what the means are, and provide them.

A SASL EXTERNAL LDAP bind operation is issued with either:- a non-zero length name that corresponds to the valid user entry desired or - a zero length name if the client wants the server to map the results of the external mechanism to the appropriate user entry.

Active Directory supports the SASL EXTERNAL authentication mechanism via TLS and user certificates that are mapped onto user accounts. This is considered a very strong authentication mechanism.

UWWI does not support user certificates at this time, so the SASL EXTERNAL authentication mechanism is not an option at this time. DIGEST-MD5 Authentication MechanismThe DIGEST-MD5 authentication mechanism (RFC2831) provides a mechanism for the HTTP Digest authentication (RFC2617) challenge/response paradigm to be used within the SASL framework. Because this mechanism relies on HTTP 1.1, it has a smaller set of uses.

This mechanism sends a MD5 checksum of the password over the wire without encryption. This is superior to sending a cleartext password with a simple bind, but is not considered strong authentication.

UWWI recommends using GSSAPI with Kerberos instead of DIGEST-MD5 authentication. Which Method and Mechanism Should I Use?UWWI supports AND recommends only two authentication methods/mechanisms: Simple Authentication Method, using the Name/Password Authentication Mechanism of Simple Bind, having first initiated session-level encryption SASL Authentication Method, using the GSSAPI Authentication Mechanism, employing Kerberos, NTLMv2, or NTLMWhich method/mechanism you choose, will likely be dependent on which method and mechanism is supported by your operating system and application. Since passwords are sensitive data, you should choose the strongest method and mechanism available. The strongest possible method and mechanism is SASL using Kerberos and employing session-level encryption. From strongest to least, the possible combinations are: SASL, using GSSAPI, employing Kerberos and session-level encryption SASL, using GSSAPI, employing NTLMv2 and session-level encryption SASL, using GSSAPI, employing Kerberos SASL, using GSSAPI, employing NTLMv2 SASL, using GSSAPI, employing NTLM and session-level encryption Simple Authentication, using name/password and employing session-level encryption. SASL, using GSSAPI, employing NTLMAs noted above, Simple Authentication, using name/password without session-level encryption is prohibited by UWWI.For configuration details, see 'How to Configure LDAP so your Application Works with UWWI'Reference DocumentsLDAP Directories ExplainedLDAP: Authentication Methods and Security MechanismsUnderstanding LDAP whitepaperMSDN: Binding to an LDAP ServerMSDN: Using LDAP for Password AuthenticationJNDI, Active Directory, and AuthenticationOracle Directory Server LDAP Authentication MechanismsOracle SASL AuthenicationConfiguring LDAP Authentication Using Active DirectoryTable of Contents1. 1. Overview2. 2. Steps to Complete1. 2.1. Enabling LDAP for the Instance2. 2.2. Explanation of Settings3. 2.3. Enabling LDAP for Users4. 2.4. LDAP With a Firewall3. 3. Related1. 1. Overview2. 2. Steps to Complete1. 2.1. Enabling LDAP for the Instance2. 2.2. Explanation of Settings3. 2.3. Enabling LDAP for Users4. 2.4. LDAP With a Firewall3. 3. RelatedOverviewSugar can be configured to accept Lightweight Directory Access Protocol (LDAP) authentication if your organization has implemented LDAP or Active Directory authentication. When users in your system attempt to log into Sugar, the application will authenticate them against your LDAP directory or Active Directory. If authentication is successful, the user is allowed to log into Sugar. If the authentication is unsuccessful, Sugar will then attempt to verify the provided credentials against its own database of valid usernames and passwords.You will need to add a user to your active directory for the purpose of authenticating from your SugarCRM to your active directory to read the LDAP. The user should be a service account that needs read-only access to Active Directory. Configuring Active Directory to support LDAP is beyond the scope of this document.Steps to CompleteEnabling LDAP for the Instance1. Log into Sugar as an administrator and navigate to Admin > Password Management2. Scroll down to the 'LDAP Support' section at the bottom of the page.3. Select the 'Enable LDAP Authentication' option. Sugar will then display additional fields for entering the necessary information.

4. Enter in the appropriate information and then click the 'Save' button.

Explanation of SettingsHere is a better explanation of the above settings: Enable LDAP - Yes Server enter the FQDN of your Active Directory Server (example: MYSERVER.MYDOMAIN.com. This should be your Domain Controller) Port enter 389 (This is the default port enter it unless you have some custom configuration for LDAP) Base DN enter OU=sugarcrm,DC=MYSERVER,DC=MYDOMAIN,DC=com (The OU OU=sugarcrm is the actual OU in Active Directory that you chose to put your users in. Note this OU does not have to called sugarcrm. It can be called anything you want or any OU that has the users you want to be in your SugarCRM. Please confirm the group is an OU and not a CN, if CN you can use the designator CN=Users for example) Bind Attribute enter userPrincipalName (This is what is used for Active Directory and is case sensitive.) Login Attribute enter sAMAccountName (This is what is used for Active Directory and is case sensitive.) Authenticated User enter [email protected] or domain\userfirstname.userlastname (You need to add a user to your active directory for the purpose of authenticating from your SugarCRM to your active directory to read the LDAP. This user should be a service account that needs only read access to Active Directory. If you chose to enter int his format domain\userfirstname.userlastname enter it with two backslashes like domain\\userfirstname.userlastname because when you click save Sugar will remove one of the backslashes.) Authenticated Password enter the password of the authenticated user you created. Auto Create Users (Leave this option unchecked. When you create an AD user you dont have to create their account in SugarCRM you just have them log in and SugarCRM will create the account automatically.)Enabling LDAP for Users1. Navigate to Admin > User Management > {user name} > Advanced Tab2. Select LDAP Authentication for this user.

Once this is selected, Sugar will synchronize their Active Directory user name and present the password on the LDAP port. When the User Logs in they will use their active directory username and password.

LDAP With a FirewallIf the Active Directory Authentication server is behind a corporate firewall and your instance of Sugar is hosted in our On-Demand environment, then please visit the following article to ensure the appropriate IP range is open on your firewall to allow communication with the Active Directory server. A rule will need to be created allowing the LDAP bi-directional communication for the necessary IP range. This can be the standard LDAP port 389 or you can use LDAP over SSL.Using LDAP for Password AuthenticationConcurrent bind, also known as fast bind, enables an application to determine if multiple users have valid IDs and passwords and if their accounts are enabled. By using concurrent binding, the application can request multiple bind operations by way of a single LDAP connection.Unlike a normal LDAP bind, a concurrent bind does not determine a user group association or build a security token; it only determines if the user has a valid ID and password. This enables the concurrent bind to complete in a fraction of the time of a normal bind.To enable concurrent bind on an LDAP connection, the application sets the LDAP_OPT_FAST_CONCURRENT_BIND session option after the LDAP connection has been initialized, but before any binds are performed. When concurrent binding is enabled for a particular LDAP session, it cannot be disabled without closing the session connection.Concurrent bind cannot be enabled on an LDAP session if signing or data encryption are enabled. Attempting to enable concurrent bind on sessions with signing or data encryption will fail the ldap_set_option call and return an LDAP_UNWILLING_TO_PERFORM error code.When concurrent bind is enabled on an LDAP session, only simple bind operations may be performed in that session and all simple binds are fast binds. As a result all subsequent bind requests will not be serialized internally by the LDAP client and the binds will not generate a security token. Any binds performed in this session are performed as anonymous, and because data encryption is not allowed any data sent through this session will appear on the network in an unencrypted form. If the application attempts to use a non-simple bind on a session with concurrent bind enabled, the call will fail and return an LDAP_UNWILLING_TO_PERFORM error code.The following example code shows how to create an LDAP session with concurrent bind enabled.C++Copy

ULONG ldap_open_fast_bind_session(LPTSTR pHostName, PLDAP pSession){ ULONG lRtn = LDAP_SUCCESS; ULONG version = LDAP_VERSION3; // Initialize session. LDAP_PORT is the default port, 389. pSession = ldap_init(pHostName, LDAP_PORT); if (pLS == NULL) return LdapGetLastError();

// Set the version to 3.0 (default version is 2.0). lRtn = ldap_set_option(pSession, LDAP_OPT_PROTOCOL_VERSION, (void*)&version);

// Enable concurrent bind. if (lRtn == LDAP_SUCCESS) lRtn = ldap_set_option(pSession, LDAP_OPT_FAST_CONCURRENT_BIND, LDAP_OPT_ON);

// Cleanup on error. if (lRtn != LDAP_SUCCESS) ldap_unbind(pSession); return lRtn;}

JNDI, Active Directory and Authentication (part 1)

800477 Dec 15, 2004 12:22 PM Currently Being Moderated Disclaimer, the information presented here is about 3 years old, however it will adequately describe how to use Kerberos & GSS-API to authenticate a Java/JNDI application against the Active Directory.

The sample code presented here is adapted from the original Sun Java/JAAS/GSS_API code samples.

There is a ton of information for integrating non-Windows Kerberos implementaions with Active Directory.

http://www.microsoft.com/windowsserver2003/technologies/security/kerberos/default.mspx

In particular for configuring the MIT Kerberos implementation to work with Active Directory, I would recomend:http://www.microsoft.com/windows2000/techinfo/planning/security/kerbsteps.asp

And for general Unix/Windows integration I would highly recomend the "Solution Guide for Windows Security and Directory Services for UNIX"

I would also recomend the Vintela suite of products that simplify the integration of Linux/Unix clients with Active Directory.

http://www.vintela.com/products/vas/index.php

Anyway, here's a working step-by step guide. If I get some free time I may upgrade this information to include more recent releases of MIT Kerberos V, using PAM and any applicable updates to JAAS.

Note that this assume the Linux host will be joined to an Active Directory domain. If the host is joined to a Kerberos realm, then all you need to do is to establisht a Kerberos trust between the Active Directory & the Kerberos realm.

Step 1. Create a user object in the Active Directory to represent the Unix/Linux host from which the Java application will be run. In this case the user object is called "linux". If you are using the Active Directory Users & Computers snap-in, it doesn't matter what the givenName, Surname, Display names are, but the User Logon (pre-Windows 2000) name in thus example is set to "linux" (without the quotes of course !)

Also remember to have created a user object to represent the user that you will log in as. (Hopefully not root !)

Step 2.Create the keytab from Active Directory. In this example, my Linux host is called "linux", it's fully qualified dns name is linux.antipodes.com, my Active Directory domain is called antipodes.com, the password I have used for the host account is "password", and the resultant keytab is named linux.keytab. (Note that the Active Directory domain, or kerberos realm, must be uppercased, this will make sense later on in the krb5.conf description)

c:> ktpass -princ host/[email protected] -mapuser linux -pass password -out linux.keytab

Note that if you look at the Users & Computer snap-in, the "linux" account will now have a Login name of the form:"host/[email protected]"

Step 3.Securely transfer the linux.keytab file to the Linux host, and install it using ktutil.# ktutil ktutil: read_kt linux.keytabktutil: write_kt /etc/krb5.keytabktutil: quit

To check that the keytab has been merged, use the ktutil list command.# ktutilktutil: listslot KVNO Principal----- ---- ----------------------------------------1 1 host/[email protected]

Step 4.Configure Kerberos on the linux host. My /etc/krb5.conf file looks like this.[libdefaults]default_realm = ANTIPODES.COMdefault_tgs_enctypes = des-cbc-crcdefault_tkt_enctypes = des-cbc-crc

[realms]ANTIPODES.COM = {kdc = mydc.antipodes.com:88admin_server = mydc.antipodes.com:88kpasswd_server = mydc.antipodes.com:464default_domain = ANTIPODES.COM}

Note that this is using a really old version of the MIT Kerberos V that used DES as the common encryption algorithm supported by both Active Directory & the MIT release. Newer MIT releases support stronger encryption algorithms that may or may not be supported by Active Directory such as 3DES or RC4-HMAC. (RC4-HMAC is the default encryption algorithm used by Active Directory & Windows clients)

Step 5.Test that Kerberos actually works.# kinitPassword for [email protected]# klistTicket cache: /tmp/krb5cc_0Default principal: [email protected] Starting Expires Service Principal12/15/2004 09:26:02 12/15/2004 19:24:04 krbtgt/ANTIPODES.COM

You could also configure PAM to use Kerberos as the authentication mechanism.

One common gotcha, the time needs to be synchronized between the Linux client and Active Directory domain controller so that it does not exceed the Kerberos Clock Skew (default 5 minutes).

Step 6.The application. As I said, a simple modification of the Sun sample code:/*** SearchWithAuth.java* 10 July 2001* Sample JNDI application to use Kerberos & GSS-APi for authentication**/

import javax.naming.*;import javax.naming.directory.*;import javax.security.auth.login.*;import javax.security.auth.Subject;import java.util.Hashtable;

class SearchWithAuth {

public static void main(String[] args) {

LoginContext lc = null; try {

lc = new LoginContext(SearchWithAuth.class.getName(), new SampleCallbackHandler());

lc.login();

} catch (LoginException le) { System.err.println("Authentication attempt failed" + le); System.exit(-1); } System.out.println("Authenticated via GSS-API"); Subject.doAs(lc.getSubject(), new LDAPSearch()); }}

//The privileged action that is executed under doAsclass LDAPSearch implements java.security.PrivilegedAction {

public LDAPSearch() { }

public Object run() { performLDAPSearch(); return null; }

private static void performLDAPSearch() {

// Set up environment for creating initial context Hashtable env = new Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");

// Connect to my domain controller env.put(Context.PROVIDER_URL, "ldap://mydc.antipodes.com:389"); // Specify GSSAPI as the SASL provider env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");

try { // Create the initial directory context DirContext ctx = new InitialDirContext(env); // Create the search controls SearchControls searchCtls = new SearchControls(); //Specify the attributes to return String returnedAtts[]={"sn","givenName","mail"}; searchCtls.setReturningAttributes(returnedAtts); //Specify the search scope searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

//specify the LDAP search filter String searchFilter = "(&(objectClass=user)(mail=*))";

//Specify the Base for the search String searchBase = "DC=antipodes,DC=com"; //initialize counter to total the results int totalResults = 0;

// Search for objects using the filter NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);

//Loop through the search results while (answer.hasMoreElements()) { SearchResult sr = (SearchResult)answer.next();

totalResults++;

System.out.println(">>>" + sr.getName());

}

System.out.println("Total results: " + totalResults); ctx.close();

ctx.close();

} catch (NamingException e) { // e.printStackTrace(); }

} }And the corresponding Callback handler. (Question: how does one create a password entry reader, which echos * instead of the password charcters ?)/*** SampleCallbackHandler.java* 10 July 2001* Sample JNDI application to use Kerberos & GSS-APi for authentication**/import javax.security.auth.callback.*;import javax.security.auth.callback.PasswordCallback;import javax.security.auth.callback.NameCallback;import java.io.IOException;import java.io.BufferedReader;import java.io.InputStreamReader;

public class SampleCallbackHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { NameCallback cb = (NameCallback)callbacks;

cb.setName(getClearInput(cb.getPrompt()));

} else if (callbacks[i] instanceof PasswordCallback) {

PasswordCallback cb = (PasswordCallback)callbacks[i];

if (cb.isEchoOn()) {

System.out.println("Echo On");

}

String pw = getProtectedInput(cb.getPrompt());

char[] passwd = new char[pw.length()];

pw.getChars(0, passwd.length, passwd, 0);

cb.setPassword(passwd);

} else {

throw new UnsupportedCallbackException(callbacks[i]);

}

}

}

private String getClearInput(String prompt) throws IOException {

System.out.print(prompt);

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

return in.readLine();

}

private String getProtectedInput(String prompt) throws IOException {

System.out.print(prompt);

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

return in.readLine();

}

public static void main(String[] args) throws IOException,

UnsupportedCallbackException {

// Test handler

CallbackHandler ch = new SampleCallbackHandler();

Callback[] callbacks = new Callback[]{

new NameCallback("user id:"),

new PasswordCallback("password:", true)};

ch.handle(callbacks);

NameCallback ncb = (NameCallback)callbacks[0];

System.out.println("Debug: " + ncb.getName());

}

}

And finally the Java application configuration file, named SearchWithAuh.conf/** * Login Configuration for JAAS. * * Specify that Kerberos v5 is a required login module for the * sample application SearchWithAuth. */SearchWithAuth { com.sun.security.auth.module.Krb5LoginModule required client=TRUE useTicketCache=TRUE;};Note the useTicketCache = TRUE value means that if the user already has a Kerberos ticket they will not be prompted for credentials. If the user does not have a ticket (for example use kdestroy to logout of Kerberos), then the user will be prompted for credentials.

Step 8.

You can avoid steps 1-4 with the Vintela software. It simplifies the integration of Unix & Linux clients with the Active Directory.

It extends the schema with Unix GID, UID attributes, enhances the Active Directory Users & Computers snap-in with additional property pages to enable editing of Unix UID, GID, shell script atributes and allows Active Directory Group Policy to be applied to Unix & Linux clients (including password policy)

There is also a Linux/Unix command line utility that "joins" the machine to the domain (essentially automates the creation of computer account, generation, transfer and import of the keytab, configuration of the kr5.conf ) and extends the crypto libraries to support RC4-HMAC. 854 Views

JNDI, Active Directory & Authentication (part 2)

800477 Dec 21, 2004 5:40 PM Currently Being Moderated A previous topic "JNDI, Active Directiory & Authentication (part 1)" described using JAAS and GSSAPI to utilize Kerberos as the authentication protocol to access Active Directory.

Most of the JNDI sample code illustrates the use of simple (clear text) authentication which is inherently insecure as credentials are sent in clear over the network.

While Kerberos is a much more secure authentication option, it does not protect the LDAP data that is transmitted over the network. For example the results of a LDAP Search operation are tranmitted in clear and may potentially reveal sensitive information.

One solution is to use SSL to protect the LDAP communications.

In addition, for Active Directory, the only way that passwords can be changed or reset using LDAP is for the communications to take place over SSL.

The code changes required to enable a JNDI application to use SSL are minimal.

Step 1. Modify the Java app.The modifications are:Change the LDAP port from 398 to 636String ldapURL = "ldap://mydc.antipodes.com:636";Set the trustStore propertyString keystore = "/usr/java/j2sdk1.4.0/jre/lib/security/cacerts";System.setProperty("javax.net.ssl.trustStore",keystore);and establish ssl as the commications protocol for the context.env.put(Context.SECURITY_PROTOCOL,"ssl");/** * searchssl.java * 5 July 2001 * December 2004 - noted that ldaps url now supported on JSDK 1.5.0 * Sample JNDI application to perform a search for against the Active Directory * over SSL (port 636) */

import java.util.Hashtable;import javax.naming.ldap.*;import javax.naming.directory.*;import javax.naming.*;

public class searchssl{ public static void main (String[] args) { Hashtable env = new Hashtable(); String adminName = "CN=Administrator,CN=Users,DC=ANTIPODES,DC=COM"; String adminPassword = "XXXXXXX"; String ldapURL = "ldap://mydc.antipodes.com:636";

//Access the keystore, this is where the Root CA public key cert was installed //Could also do this via the command line option java -Djavax.net.ssl.trustStore.... //No need to specifiy the keystore password for read operations String keystore = "/usr/java/j2sdk1.4.0/jre/lib/security/cacerts"; System.setProperty("javax.net.ssl.trustStore",keystore); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); //set security credentials env.put(Context.SECURITY_AUTHENTICATION,"simple"); env.put(Context.SECURITY_PRINCIPAL,adminName); env.put(Context.SECURITY_CREDENTIALS,adminPassword);

//specify use of ssl env.put(Context.SECURITY_PROTOCOL,"ssl"); //connect to my domain controller env.put(Context.PROVIDER_URL,ldapURL); try {

// Create the initial directory context DirContext ctx = new InitialLdapContext(env,null); //Create the search controls SearchControls searchCtls = new SearchControls(); //Specify the attributes to return String returnedAtts[]={"sn","givenName","mail"}; searchCtls.setReturningAttributes(returnedAtts); //Specify the search scope searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

//specify the LDAP search filter String searchFilter = "(&(objectClass=user)(mail=*))";

//Specify the Base for the search String searchBase = "DC=ANTIPODES,DC=COM";

//initialize counter to total the results int totalResults = 0;

// Search for objects using the filter NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);

//Loop through the search results while (answer.hasMoreElements()) { SearchResult sr = (SearchResult)answer.next();

totalResults++;

System.out.println(">>>" + sr.getName());

// Print out some of the attributes, catch the exception if the attributes have no values Attributes attrs = sr.getAttributes(); if (attrs != null) { try { System.out.println(" surname: " + attrs.get("sn").get()); System.out.println(" firstname: " + attrs.get("givenName").get()); System.out.println(" mail: " + attrs.get("mail").get());

} catch (NullPointerException e) { System.out.println("Errors listing attributes: " + e); } }

}

System.out.println("Total results: " + totalResults); ctx.close();

} catch (NamingException e) { System.err.println("Problem searching directory: " + e); } }}Step 2. Establish trust with the Active Directory domain PKI certificates.

I have installed an Enterprise CA, with the distinguished name of cn=Antipodes Root,dc=antipodes,dc=com"

By default, domain controllers automatically enroll for domain controller certificates once an Enterprise CA has been installed. The root certificate can be found in the root of the system drive (Eg. if the operating system has been installed in c:\windows, the cert will be found in c:\)

By default the certificate file is named _.crt

#keytool -import -alias antipodes -file "mydc.antipodes.com_Antipodes Root.crt" -keystore /usr/java/j2sdk1.4.0/jre/lib/securitycacerts

There is no need to publish the root certificates in the Active Directory or to add them via Group Policy as an Enterprise CA will automagically publish the root certs and Domain Controllers will automagically enroll for Domain Controller certificates.

An alternative mechanism to obtain the root cert is via the Certicate Authority Web Enrollment tool.

Assuming the Certificate Authority is installed on myca.antipodes.com (and that the CA Web Interface is also running on the same server), via a browser connect to http://myca.antipodes.com/certsrv. From the page, go to "Download a CA Certificate" and then select "Download CA Certificate". Leave the encoding method as Distinguished Encoding Rules (DER). .

By default the certificate file name is "certnew.cer"

In this case, import the cert using:#keytool -import -alias antipodes -file certnew.cer -keystore /usr/java/j2sdk1.4.0/jre/lib/securitycacerts

Note the default password for the java keystore is "changeit"

For information on configuring a certificate authority one good document is:http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/webenroll.mspx

If you are not using a Microsoft Certificate Authority, documention describing how to use a third party certificate authority with Active Directory can be found at:http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q295663

(In this case you will need to establish trust with the third party Certificate Authority by importing it's root cert).

Some Common errors1. javax.net.ssl,SSLHandshakeException: untrusted server cert chainYou haven't installed the cert, or have installed the wrong cert.

2. javaxNamingException: Cannot parse url ldaps://dc dns name:636

You are running an older JDK that doesn't support ldaps as a url. It is ok to use ldap://dc dns name:636, or upgrade to JDK 1.5

3. A little misleading howeverjavax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C09030F, comment AcceptSecurityContext error, data 525, vece]

the Win32 error code (actually it is an error code from ntstatus.h), 525 (0x20D) STATUS_CONNECTION_RESET - The transport connection has been reset, kind of implies a SSL problem, but really is invalid credentials.

4. I haven't looked at expired or revoked certs, but I assume that javax.net.ssl would raise the appropriate exception and display a helpful message.

JNDI, Active Directory & Authentication (part 3)

800477 Dec 23, 2004 11:48 AM Currently Being Moderated Another mechanism that can be used to authenticate users against the Active Directory is DIGEST-MD5.

One benefit of this mechanism, is that the credentials are not sent in clear over the network. Another advantage is that the ldap traffic can be protected from tampering or eavesdropping by providing integrity checking and confidentiality.

However one disadvantage is that user's passwords must be stored in the Active DIrectory using reversible encryption, potentially making it easier for an attacker to compromise users' passwords if they can get access to a domain controller.

The following code demonstrates the use of DIGEST-MD5 authentication:/** * searchdigest.java * December 2004 * Sample JNDI application to perform a search for against the Active Directory * Uses HTTP-DIGEST (DIGEST-MD5) as the Authentication Protocol * */

import java.util.Hashtable;import javax.naming.ldap.*;import javax.naming.directory.*;import javax.naming.*;

public class searchdigest{ public static void main (String[] args) { Hashtable env = new Hashtable();

//Must use either the userPrincipalName or samAccountName, //Cannot use the distinguished name

//String adminName = "[email protected]"; String adminName = "ANTIPODES\\Administrator"; String adminPassword = "XXXXXXX"; String ldapURL = "ldap://mydc.antipodes.com:389"; env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");

//set security credentials, note using DIGEST-MD5 //Requires user account to be stored with reversible encryption env.put(Context.SECURITY_AUTHENTICATION,"DIGEST-MD5"); env.put(Context.SECURITY_PRINCIPAL,adminName); env.put(Context.SECURITY_CREDENTIALS,adminPassword);

//Could also use DIGEST-MD5 to protect the communications //Eg. auth-int;integrity, auth-conf;confidentiality //env.put("javax.security.sasl.qop","auth-conf"); //And could also request the level of crypto //Eg. low, medium, high //env.put("javax.security.sasl.strength","high"); //connect to my domain controller env.put(Context.PROVIDER_URL,ldapURL);

try {

// Create the initial directory context DirContext ctx = new InitialLdapContext(env,null); // Create the search controls SearchControls searchCtls = new SearchControls(); //Specify the attributes to return String returnedAtts[]={"sn","givenName","mail"}; searchCtls.setReturningAttributes(returnedAtts); //Specify the search scope searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

//specify the LDAP search filter String searchFilter = "(&(objectClass=user)(mail=*))";

//Specify the Base for the search String searchBase = "DC=antipodes,DC=com";

//initialize counter to total the results int totalResults = 0;

// Search for objects using the filter NamingEnumeration answer = ctx.search(searchBase, searchFilter, searchCtls);

//Loop through the search results while (answer.hasMoreElements()) { SearchResult sr = (SearchResult)answer.next(); totalResults++; System.out.println(">>>" + sr.getName());

// Print out some of the attributes, catch the exception if the attributes have no values Attributes attrs = sr.getAttributes(); if (attrs != null) { try { System.out.println(" mail: " + attrs.get("mail").get()); } catch (NullPointerException e) { System.out.println(); } }

}

System.out.println("Total results: " + totalResults); ctx.close();

}

catch (NamingException e) { System.err.println("Problem searching directory: " + e); } }}Note that there are two major gotchas.

1. In the application, only NT Domain names (DOMAIN\username) or userPrincipal names ([email protected]) can be used. Distinguished names are not supported.

2. The user's password must be configured to be stored using reversible encryption (Performed either from the Active Directory Users & Computers tool, or by modifying the user's userAccountControl attribute with a JNDI, LDAP, ADSI or LDAP application). Also after the reversible encryption option has been set, the user must change their password for the password to be stored using this format