112

I'm looking for a way to authenticate users through LDAP with PHP (with Active Directory being the provider). Ideally, it should be able to run on IIS 7 (adLDAP does it on Apache). Anyone had done anything similar, with success?

  • Edit: I'd prefer a library/class with code that's ready to go... It'd be silly to invent the wheel when someone has already done so.
GEOCHET
  • 21,119
  • 15
  • 74
  • 98
DV.
  • 4,585
  • 9
  • 37
  • 44

6 Answers6

176

Importing a whole library seems inefficient when all you need is essentially two lines of code...

$ldap = ldap_connect("ldap.example.com");
if ($bind = ldap_bind($ldap, $_POST['username'], $_POST['password'])) {
  // log them in!
} else {
  // error message
}
ceejayoz
  • 176,543
  • 40
  • 303
  • 368
  • 48
    Some installations of AD will bind successfully if the password provided is empty. Watch out for this! You may need to ensure a non-empty password before trying to authenticate. – diolemo Oct 20 '11 at 16:32
  • @diolemo Is there any way to prevent this without checking if the password is empty? – Naftali Oct 14 '13 at 22:00
  • 1
    @Neal You may be able to use `ldap_set_option` to make it behave in a different way. Perhaps setting the protocol version? You will have to experiment. I would personally suggest you check for an empty password anyway, just to be safe. – diolemo Oct 15 '13 at 22:54
  • @diolemo [I made a new question related to this.](http://stackoverflow.com/q/19406701/561731) – Naftali Oct 16 '13 at 14:56
  • To the anonymous editor: no, to my knowledge, input sanitization isn't required here as `ldap_bind` would be handling it and special characters aren't an issue. – ceejayoz Jan 08 '14 at 21:34
  • I assume **php_ldap.dll** extension must be enabled on the server. – shasi kanth Jan 29 '14 at 06:55
  • @windowsuser: I had to copy some dlls to the system directory to make it work. Try this: http://wptidbits.com/webs/enable-php-ldap-module-in-xampp/ – Lucian Depold Apr 04 '14 at 11:56
  • You can also use the user's name instead of username for authentication: `$binddn = "CN=Dummy User,CN=Users,DC=domain,DC=local";ldap_bind( $ldap,$binddn , $password );` – Anant Gupta Sep 22 '14 at 14:31
  • Exchange core has written a beautiful working blog article regarding this here: https://www.exchangecore.com/blog/how-use-ldap-active-directory-authentication-php/ – NixMan Oct 20 '18 at 15:04
19

You would think that simply authenticating a user in Active Directory would be a pretty simple process using LDAP in PHP without the need for a library. But there are a lot of things that can complicate it pretty fast:

  • You must validate input. An empty username/password would pass otherwise.
  • You should ensure the username/password is properly encoded when binding.
  • You should be encrypting the connection using TLS.
  • Using separate LDAP servers for redundancy in case one is down.
  • Getting an informative error message if authentication fails.

It's actually easier in most cases to use a LDAP library supporting the above. I ultimately ended up rolling my own library which handles all the above points: LdapTools (Well, not just for authentication, it can do much more). It can be used like the following:

use LdapTools\Configuration;
use LdapTools\DomainConfiguration;
use LdapTools\LdapManager;

$domain = (new DomainConfiguration('example.com'))
    ->setUsername('username') # A separate AD service account used by your app
    ->setPassword('password')
    ->setServers(['dc1', 'dc2', 'dc3'])
    ->setUseTls(true);
$config = new Configuration($domain);
$ldap = new LdapManager($config);

if (!$ldap->authenticate($username, $password, $message)) {
    echo "Error: $message";
} else {
    // Do something...
}

The authenticate call above will:

  • Validate that neither the username or password is empty.
  • Ensure the username/password is properly encoded (UTF-8 by default)
  • Try an alternate LDAP server in case one is down.
  • Encrypt the authentication request using TLS.
  • Provide additional information if it failed (ie. locked/disabled account, etc)

There are other libraries to do this too (Such as Adldap2). However, I felt compelled enough to provide some additional information as the most up-voted answer is actually a security risk to rely on with no input validation done and not using TLS.

ChadSikorra
  • 2,829
  • 2
  • 21
  • 27
  • 1
    For LDAP connections, TLS has been deprecated in favor of StartTLS: http://www.openldap.org/faq/data/cache/605.html. – zenlord Apr 12 '16 at 17:27
  • 2
    @zenlord Using the `ldaps://` format for the connection is deprecated. In my example, when you specify `setUseTls(true)` it uses `ldap://` format and then issues a StartTLS using `ldap_start_tls($connection)`. So TLS itself hasn't been deprecated, just connecting using `ldaps://` (which actually connects to LDAP over a completely different port). – ChadSikorra Apr 12 '16 at 20:34
13

I do this simply by passing the user credentials to ldap_bind().

http://php.net/manual/en/function.ldap-bind.php

If the account can bind to LDAP, it's valid; if it can't, it's not. If all you're doing is authentication (not account management), I don't see the need for a library.

Scott Reynen
  • 3,530
  • 18
  • 17
9

I like the Zend_Ldap Class, you can use only this class in your project, without the Zend Framework.

1234567
  • 946
  • 6
  • 22
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 1
    I went through the trouble of implementing the above to find that was for managing not authenticating. I intend to switch to [zend.auth.adapter.ldap](https://framework.zend.com/manual/1.10/en/zend.auth.adapter.ldap.html) – vdidxho Mar 16 '18 at 14:47
6

PHP has libraries: http://ca.php.net/ldap

PEAR also has a number of packages: http://pear.php.net/search.php?q=ldap&in=packages&x=0&y=0

I haven't used either, but I was going to at one point and they seemed like they should work.

Darryl Hein
  • 142,451
  • 95
  • 218
  • 261
5

For those looking for a complete example check out http://www.exchangecore.com/blog/how-use-ldap-active-directory-authentication-php/.

I have tested this connecting to both Windows Server 2003 and Windows Server 2008 R2 domain controllers from a Windows Server 2003 Web Server (IIS6) and from a windows server 2012 enterprise running IIS 8.

Joe Meyer
  • 4,315
  • 20
  • 28