LdapAuth component for CakePHP

Jun 13th
Posted by analogrithems  as CakePHP, ldap

So I was looking for a way to authenticate against LDAP with cake but I’ve found that it doesn’t support it by default. I found one that checks the auth against ldap then creates a local mysql account. This also didn’t use a actual ldap data sourc e either, it just handeled it’s own ldap connection. After I read through the standard cakphp auth component I saw that it wouldn’t be that hard to write an LDAP based auth component.

First you need to download this file ldap_auth.php to your ‘app/controllers/components/’ directory.

Then just like the original auth component you add that component to a model. I followed the usual auth example and created a model called Users.php like so

<?php 
class User extends AppModel {
	var $name = 'User';
	var $useDbConfig = 'ldap';
	var $primaryKey = 'uid';
	var $useTable = 'ou=people';
}
?>

If some of these options are odd looking please have a look at my ldap data source post.

Next you are going to need your controller. Here is the one I used It defines the required functions like login, logout & authorize.

<?php
class UsersController extends AppController {
 
	var $name = 'Users';    
        var $components = array('RequestHandler', 'LdapAuth');
        var $helpers = array('Form','Html','Javascript', 'Ajax');
 
	function login() {
	}
 
	function logout() {
		$this->redirect($this->LdapAuth->logout());
	}
 
        function isAuthorized() {
                return true;
        }
 
}
?>

7

13 Comments

  1. Philippe  15th June 2009  

    Hi,

    Since your component is much more elaborated than mine, it will replace mine very soon ;-) Thank you!
    Just a note: if you authenticate with ldap, you should do this with encryption, otherwise you’ll be passing username and password together in clear text over the network, thus opening a wide security hole.
    As I wrote in my comment (http://memdump.wordpress.com/2008/04/26/ldap-data-source-now-with-full-crud/#comment-33), it is very easy to implement tls support. Just need to add 3 lines of code to the connect function!

    regards

    Philippe

    • analogrithems  16th June 2009  

      I’m looking into doing this right now, but as most people use self signed certs for ldap, I’ve gotta add documentation on how to make PHP/Apache trust unsigned certs. But I’m right on board with you. I haven’t worried about this yet as my development server is also my ldap server and the traffic never actually hits the network.

    • analogrithems  16th June 2009  

      I’ve added support for both TLS and SSL See my database example in my data source for settings

  2. Robert  8th July 2009  

    Very cool component. I need to write a tiny cake-based app this week and need to authenticate users via Microsoft Active directory. I also want to lock down the app to allow only users in a certain group to use any of it. Any suggestions on where to add that logic? I’m a bit new to cake and have been picking things up via the manual.

    Thank You,

    • analogrithems  13th July 2009  

      This shouldn’t be an issue, make it use the ldap datasource http://www.analogrithems.com/rant/2009/06/12/cakephp-with-full-crud-a-living-example/ then add the auth componet in this article. In your config/database.php place an entry for you active directory stuff. like any normal ldap connection. Active directory is just a standard ldap v3 (mostly). Also i believe you must use a proxy user account in your ‘config/database.php’ file for the inital dn lookup. (When you type in your username the script needs to translate that to a dn, it uses the proxy account you initially specify in config/database.php login & password fields to do the inital lookup then binds with the returned dn and the password you passed.)

      The only other thing I can think of is changing the attribute on line 156
      `$dn = $this->getDn(‘uid’, $uid);` to `$dn = $this->getDn(‘samaccountname’, $uid);` if you want to use a regular username format
      of change it to `$dn = $this->getDn(‘userprincipalname’, $uid);` if you are going to use username@domain format

      see http://www.computerperformance.co.uk/Logon/LDAP_attributes_active_directory.htm

      Let me know if you have any trouble and I’ll to try to drum up an AD server to test my code against.

  3. Shawn Parr  6th October 2009  

    I got your ldap_source working, and can do lookups against our Active Directory setup. However I just can’t get this component to work at all.

    I’d like to give more info, but I’m getting the infamous ‘Cannot modify header information – headers already sent by’ error. I’ve done my research, and typically that is caused by white space after the ?> tag, but I’ve searched all my files and do not have any with the extra whitespace outside of my view template files.

    That being said, the one page that does load is my login page /users/login. When it is submitted I get the following on my mostly blank page:

    1 search | scope: sub | cond: samaccountname=user | targetDn: dc=example,dc=com | order: 1: Operations error

    I’m pretty sure that Operations error is an issue, but I’m not sure what is causing it. I have a bind user and password set in my Ldap config in the database config file, and they are obviously working since ldap lookups work fine (trust me, if the bind user can’t connect the lookups wouldn’t work!).

    Any ideas? Any pointers? I’m going nuts trying to figure this out. Feel free to email me if you want more details or have other instructions.

    I should note that I’m pretty new to cakephp, but have done a little bit of MVC php development.

  4. Shawn Parr  9th October 2009  

    I got your auth working. A couple odd things were happening. For some reason on our AD domain, when just searching you can specify the root (dc=example, dc=edu) and it will find everything, however when using authentication it fails. This is especially weird since it is in the getDn function: $userObj$ = $this->ldap->find, which I would have imagined should work since it is seemingly identical to the code that does it when just doing lookups.

    To make things weirder, when that failed, it was returning nothing, which then got passed on to ldapauth, which for some reason would return 1 to the login function when the dn was empty. So I had a situation where anyone could log in with any username/password combo.

    To solve this I first changed the getDn function to individually search the two OU’s set up in our AD where all valid users are stored (in sub OU’s). I then added a statement to ldapauth to return a zero if the dn was empty.

    Technically the above getDn change I had already implemented in my controller and model due to the fact that our AD has a lot of extra stuff in many of the object records. As such a typical search someone would setup for ldap will return computer records and other special items (computers are tagged with objectclass=person for some odd reason), so I added a new line to the model that uses an array to hold multiple OU statements, then use a foreach loop to go through them, then a bit of logic to deal with getting the results back to something the system can deal with as it is.

    I want to thank you for:
    1) creating these ldap tools. They work well, and are pretty well thought out
    2) for creating full documentation for how to do something in cakephp.

    That second one is really what I appreciate most. As I start learning cakephp I tend to find plenty of articles and info on how to do things, but almost all of them require a pretty full knowledge of the logic behind cakephp. Having an article like this to reference which gives full working examples was EXTREMELY helpful.

    • analogrithems  12th October 2009  

      in the getDN function did you have to change the call to look for an attribute besides uid? I recall windows uses something different like userPrincipal. Can you post your code changes so i can make this component more universal?

  5. Kit Peters  16th November 2009  

    it’s worth noting that the call to __getLDAPSchema() will fail if you bind anonymously to an Active Directory 2003 server (see http://serverfault.com/questions/10208/disable-requiring-authentication-to-bind-in-active-directory). You can turn this behavior off in AD, but if you don’t have access to the AD configuration, you’ll have to do a bind with a username/password.

  6. Scott  3rd March 2010  

    You may want to consider adding the following to your component so that the Auth examples from the book still work as described.

    /**
    * Initialize method ensures Auth methods remain working as described in the book.
    */
    function initialize(&$controller) {
    parent::initialize($controller);
    $controller->Auth =& $this;
    }

    Now every reference to $this->Auth is still valid.

  7. Sean Traynor  14th May 2010  

    Hi Analogrithems,

    Firstly – thank you for this article and all of your efforts towards CakePHP’s LDAP integration!

    I am having issues however. If I use the ldap_source listed in the article LDAP is properly queried however I have the issues above with blank output without debug and header already sent with debug on.

    With the latest version of ldap_source on github I recieve the message “-1: Can’t contact LDAP server” – even though it works with the older version of ldap_source! Are there any changes that need to be made to the LdapAuth component to make it compatible with the latest version of the ldap_source datasource?

    Many thanks!
    Sean

    • analogrithems  23rd May 2010  

      I added a new attribute that needs to be added to the database config, Here is my database.php This is to make the datasource work with different ldap servers operational attributes and know how to find the schemas that exists in different locations between them.

      vi config/core.php

      < ?php
       class DATABASE_CONFIG {
              //This will be used for extensions/plugins.  if you plugin needs a db, define it here.
              var $default = array(
                      'driver' => 'mysql',
                      'persistent' => false,
                      'host' => 'localhost',
                      'login' => 'user',
                      'password' => 'password',
                      'database' => 'database_name',
                      'prefix' => '',
              );
              var $ldap = array (
                      'datasource' => 'ldap',
                      'host' => 'localhost',
                      'port' => 389,
                      'basedn' => 'dc=analogrithems,dc=com',
                      'login' => '',     //For Proxy Userdn
                      'password' => '',  //For Proxy UserDN password
                      'database' => '',  //Needed to prevent cakePHP from throwing errors about database missing
                      'tls' => '', //Set this to true if using tls
                      'type' => 'Netscape', //Type Can be either 'Netscape', 'OpenLDAP', 'ActiveDirectory'
                      'version' => 3 //LDAP Version 3
               );
       }
      ?>
      
  8. Jay  1st June 2010  

    I’m trying to use your ldap_auth (which is pretty slick, by the way)…but I’m having a problem in which the ldap lookup is getting sent a full array instead of the username during login, resulting in a login failure. I’m not sure how that’s happening, but could use some help

Trackbacks/Pingbacks

  1. Random Tech Articles » Blog Archive » CakePHP with full CRUD, a living example!

Leave a Reply

Powered By Wordpress || Designed By Ridgey