Category Archives: OpenLDAP

Connect to OpenLDAP server with PHP5 (CentOS 7)

Here is a short PHP sample script of how to connect to an OpenLDAP server using the secure LDAPS protocol (port 636).

PHP uses the LDAP settings from the LDAP base packages. in the case of CentOS 7 they are configured in /etc/openldap/ldap.conf . Following two entries are the only ones that are important:

TLS_CACERTDIR   /etc/openldap/certs
TLS_REQCERT     demand

The first line gives the location of the public CA certificate that was used to sign the LDAP server certificate. The second line rejects all invalid certificates. To make the first line work, we need to import the public CA certificate into the local NSS database. For that we use the certutil command line utility (root privileges required):

certutil -A -n ldap -t "C,," -d dbm:/etc/openldap/certs -i /etc/ssl/certs/ldap-ca.pem
certutil -L -d dbm:/etc/openldap/certs

The first line imports an existing CA certificate into the database (with the nickname “ldap” which should be unique). The certificate database uses the old Berkeley DB format, so we need to prefix the location with “dbm:”. There are 2 files that make up the certificate database:

  • cert8.db
  • key3.db

The second line of the code example merely lists all existing database entries. It should now include our new CA certificate for LDAP connections:

[root@centos7]# certutil -L -d dbm:/etc/openldap/certs 
Certificate Nickname                                         Trust Attributes 
                                                             SSL,S/MIME,JAR/XPI 
 
ldap                                                         C,,

Notice the 3 trust attributes for our new CA certificate. In our case the first field needs to include the trust “C”. For a description of all possible values, see “man certutil”.

Now that we installed the CA certificate for LDAPS connections, we can actually try to make a connection to the LDAP server with PHP5.

<?php 
$server = "ldaps://ldap.example.org"; 
 
echo "Connecting to $server ...n"; 

#ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7); 
 
$ldapconn = ldap_connect($server, 636) 
        or die("ERROR: Unable to connect to $servern"); 
 
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3); 
 
$ldapbind = ldap_bind($ldapconn) 
        or die("ERROR: Unable to bind to $servern"); 
 
echo "Ok, now connected to $servern"; 
 
ldap_unbind($ldapconn); 
?>

Here we make an anonymous connection to the LDAP server. You can also provide a username and password for the ldap_bind() function call. Now call this script from the command line (needs yum package “php-cli”):

$ php php-test.php
Connecting to ldaps://ldap.example.org ... 
Ok, now connected to ldaps://ldap.example.org

Important things to note:

  • Call ldap_set_option() to activate debug output.
  • ldap_connect() does not actually connect to the LDAP server. It only initializes internal data structures and variables. The network connection to port 636 will be made by ldap_bind().
  • You need to explicitly set the LDAP protocol version to 3. Otherwise version 2 will be used, which will not work with contemporary OpenLDAP servers.

Connect to OpenLDAP server with Perl

This little code example in Perl shows how to connect to an OpenLDAP server using the ldaps protocol. It tries several servers and uses the first one it can connect to.

#!/usr/bin/perl
use strict;

use Net::LDAP;
use Net::LDAP::Extension::WhoAmI;
# LDAPS is basically the same as the LDAP-Module using ldaps:// URIs
#use Net::LDAPS;

my $userName = 'USERNAME';
my $passWord = 'PASSWORD';

my @Servers = ("server1", "server2", "server3");
my $ldap = undef;

# Code = 34, Name: LDAP_INVALID_DN_SYNTAX (dn is not a full path)
# Code = 48, Name: LDAP_INAPPROPRIATE_AUTH (empty dn or password)
# Code = 49, Name: LDAP_INVALID_CREDENTIALS (wrong dn or password)
sub lErr {
  my $mesg = shift;
  printf STDERR "Error: %sn", $mesg->error();
  printf STDERR "Error Code: %sn", $mesg->code();
  printf STDERR "Error Name: %sn", $mesg->error_name();
  printf STDERR "Error Text: %s", $mesg->error_text();
  printf STDERR "Error Description: %sn", $mesg->error_desc();
  printf STDERR "Server Error: %sn", $mesg->server_error();
}

foreach my $server (@Servers) {
  $ldap = Net::LDAP->new("ldaps://$server:636",
  verify => 'require',
  inet4 => 1,
  timeout => 3,
  cafile => '/etc/ssl/certs/ldap_slapd_cacert.pem' );

  if($ldap) {
    print "Ok connecting to $servern";
    last;
  }
  else {
    print "Error connecting to $server: $@n";
  }
}

if($ldap) {
  print "Now connected to " . $ldap->host() . "n";
}
else {
  exit -1;
}
my $mesg = $ldap->bind("uid=$userName,ou=People,dc=example,dc=com",
  password => "$passWord");
if($mesg->is_error()) {
  exit $mesg->code;
}

# Using $ldap->bind again after $ldap->unbind doesn't work
$ldap->unbind;

There is also an option to connect to an array of servers with only one function call. It basically does the same thing: Looping through a list of servers and use the first successful connection. But you have to be careful, there is a known bug if “verify” is set to “optional” (s. https://rt.cpan.org/Public/Bug/Display.html?id=118477).

Password encryption in OpenLDAP

Passwords in OpenLDAP are SSHA encrypted by default (Salted SHA1).

Changing it to SHA512 (salted with 16 Bytes):

olcPasswordHash: {CRYPT},{SSHA}
olcPasswordCryptSaltFormat: "$6$%.16s"

Or if you want to increase the number of rounds:

olcPasswordHash: {CRYPT},{SSHA}
olcPasswordCryptSaltFormat: "$6$rounds=2000000$%.16s"

This will still accept already existing passwords that are SSHA encrypted. New or changed passwords will be SHA512 encrypted. The max. number of rounds is 9 999 999. This increases computational time to create a password hash in order to prevent brute force attacks.

For this to work, the GNU C library has to support SHA512:
– /etc/login.defs: ENCRYPT_METHOD SHA512
– man pam_unix (should include sha512)

Also OpenLDAP has to be compiled with crypt support (–enable-crypt).

SHA512 passwords for LDAP can be generated with slappasswd:

slappasswd -c '$6$%.16s'

Important things to note:

  • OpenLDAP provides its own native SHA-2 password module supporting SHA512, but that one lacks support for modifying rounds.
  • OpenLDAP also provides a module for the key derivation function PBKDF2. Currently there are no reliable sources on the internet which suggest that PBKDF2 is more secure than salted SHA512 with rounds.
  • The next step up would be using key derivation function scrypt or Argon2 because they impose much higher requirements on memory.