ldapguru | blog | search filters

LDAP Authentication Best Practices

Who Should Read This Article

LDAP administrators, and LDAP security professionals and other persons who are interested in a highly secure and professionally administered LDAP setup.

LDAP Authentication Overview

An LDAP session (connection from a client) has an authorization state. When a session is established, the authorization state is set to anonymous. LDAP clients use the BIND operation to change the authorization state of a session, including setting the authorization state of the connection back to anonymous. LDAP clients must not send a BIND request while operations are in progress and servers will not process a BIND request while other operations are in progress for a session. If necessary, LDAP clients may ABANDON operations and then transmit a BIND request. BIND requests cannot be abandoned.

When the directory server receives a BIND request from a client, the authorization state of that connection is set to anonymous. If the BIND request is successful, the authorization state of the connection is set to the state for the identity in the BIND request; if the BIND request is not successful, the session remains in the anonymous state. An LDAP directory server considers a BIND operation to be successful if the information transmitted in the BIND request can be verified by the server.

The authorization state includes:

Clients use the LDAP BIND operation to authenticate users. A user submits his username and password and the client transmits that information to the directory server in a BIND request. The BIND response from the directory server indicates whether the provided credentials matched those stored in the directory server database. If the result code in the BIND response is zero (0) then the server as able to verify that the credentials presented matched those in the directory server database.

The server may support pass-through authentication, a mechanism wherein the credentials are stored on a server separate from the server to which the LDAP client presented the credentials. Pass-through authentication allows LDAP Directory Server administrators to store credentials on a server in a more secure location.

If the BIND operation was successful, the LDAP client infers that the credentials presented were correct.

authorization state over time
authorization state over time

BIND operation

The BIND operation consists of a request from the client to the server and a response from the server. If the BIND is a multi-stage BIND, the server transmits a response for each stasge of the BIND process. BIND operations cannot be abandoned.

Single stage LDAP BIND operation request and response
Single stage LDAP BIND operation request and response

Simple Authentication Method

The BIND simple authentication method request consists at a minimum of:

LDAP clients should use the simple authentication method via a secure connection. LDAP directory servers should be configured to reject operations on connections that are not secure with the exception of the StartTLS extended operation.

Best Practice Checklist (simple BIND)

Type Name Password Notes
Anonymousnullnull the directory server should be configured to reject anonymous BIND requests and set the result code to '53' (unwillingToPerform) since no authentication takes place
Unauthenticateddistinguished namenull the directory server should be configured to reject unauthenticated BIND requests and set the result code to '53' (unwillingToPerform) since no authentication takes place
Authenticateddistinguished namenon-null
Undefinednullnon-null In the event that a client transmits a BIND request with a null name and a non-null password, the server behavior is undefined by the standard, therefore, the server should be configured to reject this type of BIND request and set the result code in the BIND response to '53' (unwillingToPerform) since no authentication takes place. This type of BIND request might be transmitted by a client intending an anonymous BIND request but with leftover text in the password field.
Simple BIND Request

SASL Authentication Method

The SASL BIND request uses a pre-defined mechanism for authentication. Some SASL BIND operations are multi-part operations, and some can be used to prevent the client from transmitting the user password on a network (a form of challenge-response). Not transmitting a password on the network sounds good at first blush, but the disadvantage of these challenge-response SASL mechanisms is that the server requires access to the clear-text password, or the server must be able to decrypt the password. Encrypted passwords are inherently less secure than salted hashed passwords.

Mechanism Server Action Notes
ANONYMOUS disable No authentication or authorization has been performed and the resulting LDAP session is unsafe. The directory server should reject this request and set the result code in the BIND response to "unwillingToPerform" (decimal 53)
CRAM-MD5 disable The CRAM-MD5 mechanism uses an MD5 digest and is safer than PLAIN. However, MD5 is much weaker than SSL or StartTLS and the directory server requires access to the clear-text password which must be stored in the clear or in a reversible encryption scheme. Reversible encryption schemes are weaker than a salted cryptographic hash. Therefore, directory server should reject this request and set the result code in the BIND response to "unwillingToPerform" (decimal 53)
DIGEST-MD5 disable Slightly stronger than CRAM-MD5, but shares its weaknesses. Therefore, directory server should reject this request and set the result code in the BIND response to "unwillingToPerform" (decimal 53)
EXTERNAL enable This mechanism is defined the SASL RFC
GSSAPI enable The General Security Services API allows Kerberos implementations to be API compatible
KERBEROSv4 (PDF) disable Kerberos v4 is deprecated in favor of Kerberos v5
LOGIN disable The server should be configured to reject SASL BIND requests using the LOGIN mechanism.
PLAIN disable The credentials are transmitted in clear-text, and even though authentication has been performed, the credentials can be captured from network hardware and therefore cannot be trusted. The directory server should reject this request and set the result code in the BIND response to "unwillingToPerform" (decimal 53)

LDAP Authentication Security Checklist

Topic Server Action Notes
simple BIND request on a non-secure connection Reject Simple BIND requests contain credentials. Non-secure connections are unsafe. The directory server should reject simple BIND requests on a non-secure connection and set the result code of the BIND response to '53' (unwillingToPerform)
anonymous BIND requests Reject Anonymous BIND requests contain no distinguished name or password, therefore operations conducted on LDAP sessions that are anonymous cannot be traced except to a hostname or IP address and no authentication takes place. Anonymous LDAP sessions are unsafe, and directory server should reject them and set the result code in the BIND response to "unwillingToPerform" (decimal 53).
unauthenticated BIND requests BIND requests Reject Unauthenticated simple BIND requests contain distinguished name and no password, therefore no authentication takes place. Unauthenticated simple BIND requests are unsafe and the server should reject them and set the result code in the BIND response to "unwillingToPerform" (decimal 53)
simple BIND request with no distinguished name Reject The behavior of a directory server is undefined when a simple BIND request containing no distinguished name and a non-null password is presented by an LDAP client. The directroy server should reject this BIND request and set the result code in the BIND response to '53' (unwillingToPerform) because no authentication takes place. This type of BIND request is unsafe.
simple BIND request, secure connection, password stored as a salted SHA-2 cryptographic hash Permit Password policies should be configured to store passwords as salted SHA-2 512-bit digests
LDAPv2 Reject

Examples

In Java, using the UnboundID LDAP SDK:

import com.unboundid.ldap.sdk.SimpleBindRequest;
...
final String dn = "uid=user.0,ou=people,dc=example,dc=com";
final String password = "secret";
final SimpleBindRequest bindRequest = new SimpleBindRequest(dn,password);
// exceptions ignored for this example
final BindResult bindResult = ldapConnection.bind(bindRequest);
if(bindResult.getResultCode().equals(ResultCode.SUCCESS)) { // success }

In Perl:

#! /usr/bin/perl
use warnings;
use strict;
use Net::LDAP;
use Getopt::Long;

my $hostname     = "";
my $port         = "";
my $bindDN       = "";
my $bindPassword = "";

my $getOptionsResult = GetOptions(
    "hostname=s"     => \$hostname,
    "port=s"         => \$port,
    "bindDN=s"       => \$bindDN,
    "bindPassword=s" => \$bindPassword,
    );

die "fatal: use --hostname hostname"         if $hostname eq "";
die "fatal: use --port port"                 if $port eq "";
die "fatal: use --bindDN bindDN"             if $bindDN eq "";
die "fatal: use --bindPassword bindPassword" if $bindPassword eq "";

# connect to the specified server
my $ldapConnection = Net::LDAP->new($hostname,
                                    port    => "$port",
                                    scheme  => "ldap",
                                    timeout => "15") or die "$@";

# request that the server change the authorization state of the connection
my $bindResult = $ldapConnection->bind($bindDN,password => $bindPassword);

my $resultCode = $bindResult->code;
printf "bind result: $resultCode \n";

printf "BIND('$bindDN','$bindPassword') successful\n" if $resultCode eq 0;

In PHP:

<?php
    $ldap_dn = "uid=user1,ou=people,dc=example,dc=com";
    $password = "password";

    $ldap_host = "localhost:10389";

    $ldapConnection = ldap_connect($ldap_host);

    if ($ldapConnection) { 
            $bind = ldap_bind($ldapConnection, $ldap_dn, $password);
            if ($bind) {
                echo "the user exists and the given credentials match those stored in the server";
            }
    }
?>

References

© 2012 Terry Gardner