Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Auth_Adapter_Ldap Component Proposal

Proposed Component Name Zend_Auth_Adapter_Ldap
Developer Notes
Proposers [vincent dot dupont at ausy dot be]
Revision 1.1 - 19 March 2007: First draft.
1.2 - 03 May 2007: First revision based on prototype
1.3 - 10 May 2007: First release of code
1.4 - 24 may 2007: answers to Darby questions (wiki revision: 13)

Table of Contents

1. Overview

Zend_Auth_Adapter_Ldap is a LDAP adapter for the Zend_Auth that should authenticate users from a LDAP connection.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • Zend_Auth_Adapter_Ldap will require the LDAP extension to be loaded into PHP. This is not the case by default (see PHP Native LDAP functions). If the extension is not loaded, a Zend_Auth_Adapter_Exception will be thrown.
  • Zend_Auth_Adapter_Ldap will also require that the LDAP directory is correctly configured and contains some data for testing. This is out of scope for the current adapter.
  • Zend_Auth_Adapter_Ldap will require few general connection settings as the 'host'. Other settings will use default values.
  • Zend_Auth_Adapter_Ldap will require a username and a password to be checked. If these are missing or empty, a Zend_Auth_Adapter_Exception will be thrown.
  • Zend_Auth_Adapter_Ldap will only return a Zend_Auth_Result objet depending on authentication success/failure (or throw Zend_Auth_Adapter_Exception if needed).
  • If success, the Zend_Auth_Result Identity value will be the provided username. No complementary information about the user will be fetched from the LDAP directory (See Zend_Ldap for this)
  • If failure, the Identity will be null, and the message will try to describe the error.
  • Zend_Auth_Adapter_Ldap is not related in anyway to Zend_Ldap. (However, this could be a future implementation). Zend_Ldap is not required
  • Zend_Auth_Adapter_Ldap will create a new LDAP connection on every request, and close it when finished. No connection pooling or re-use is provided.
  • The process should be fast and reliable.
  • Zend_Auth_Adapter_Ldap will not save or store the username and passwords. This means that username and password will only be used to validate the user access, and won't be recorded in any way.
  • Zend_Auth_Adapter_Exception

4. Dependencies on Other Framework Components

5. Theory of Operation

The Zend_Auth_Adapter_Ldap will simply try to find the provided user login into the LDAP directory.
Using the found user information, it will try to connect and bind using the selected user information and provided password. If the bind succeeds, the authentication is ok. Otherwise, the authentication fails.
In Both cases, a Zend_Auth_Result will be returned.
If provided into the configuration settings, a bind user and password will be used for searching the user information into the LDAP directory. Otherwise, the Zend_Auth_Adapter_Ldap will try to connect anonymously.

If any technical problem occurs (LDAP not present, etc) the authentication will fail and a Zend_Auth_Adapter_Exception will be fired.

The available parameters are :

  • 'host' : mandatory, the host IP or servername. Multiple hosts may be added, coma separated. This is a feature of the PHP LDAP extension : if the first host is not available, the extension will try to silently connect to the next one (PHP LDAP API feature).
  • 'port' : the port of the LDAP service. Default to 389
  • 'url' : alternative connection string (see ldap_connect). Will be preferred to the 'host' if provided
  • 'protocol_version' : The LDAP protocol version. Default is V3
  • 'bind_dn' : superuser bind username. This is used to browse the LDAP directory to get the user information
  • 'bind_pw' : superuser bind password.
  • 'base_dn' : base LDAP path to start searching for the user information
  • 'user_dn' : user part of the LDAP path. This will be prepended to base_dn when searching for the user information (Default:'')
  • 'user_oc' : the ObjectClass on which the user login will be searched for (default :posixAccount,ActiveDirectory: user)
  • 'user_attr': the attributes that correspond to the user login (default: UID, ActiveDirectory : SamAccounName)
  • 'group_dn' : the DN of a group the authenticated user should be member of. If the user is authenticated against the LDAP, but is not member of the specified group, the authentication will fail (not implemented yet).

Moreover, some parameters allow special features of MS Active Directory:

  • 'use_direct_bind' : use only a direct bind with the username and password (this will require a NT domain).
  • 'domain' : prepend a domain to the username
  • 'use_domain_from_email' : if the username is formatted as an email, parse the username to get the login + the domain
    The direct bind will be a faster alternative when using a Active Directory authentication.

The constructor will take 3 arguments :

  • the username
  • the password provided by the enduser, and
  • the config array : holds all stable configuration information.
    This will let the developer instanciate the config array from another source like Zend_Config, and simply change the transient information, coming from the login form (username and password).

Expected Exceptions (throw a Zend_Auth_Adapter_Exception):

  • username null or empty (message : 'Username, Password and Host must be set before calling ')
  • password null or empty (message : 'Username, Password and Host must be set before calling ')
  • host config null or empty (message : 'Username, Password and Host must be set before calling ')
  • Ldap extension not present (message :'Ldap extension is not properly loaded')

Expected Zend_Auth_Result::FAILURE : (these are problems)

  • Ldap connection failed (message : 'ldap_connect failed');FAILURE
  • Ldap bind failed (anlonymously or not) (message : 'ldap-bind failed') FAILURE
  • Ldap search failed (search of the username into the Ldap) (Message : 'ldap_search failed') FAILURE
    Expected Authentication failure (wrong user information)
  • Ldap get entries failed (fetch data from Ldap)(message: 'ldap_get_entries failed') FAILURE_IDENTITY_NOT_FOUND
  • Invalid username or password (message : 'Authentication failed, username or password invalid') FAILURE_CREDENTIAL_INVALID
  • zero or more than 1 match for this user (message : 'ldap_get_entries return 0 or too many entries') FAILURE_IDENTITY_AMBIGUOUS

Open questions

  • I figure out here that the constructor AND the authenticate() methods may throw Exceptions. If this is a problem, I can move those exceptions to the authenticate() methods. Maybe this will be more compliant?
    Well I see that the Zend_Auth_Adapter_Http constructor also throw some exceptions...
  • I still do not know what is the impact of authenticate() on a previously existing ldap connection. Is the existing connection reused or not? To be tested
  • Does the Adapter need to provide a storage of the authenticated Identity? I guess not but I may be missing this point in the doc.

6. Milestones / Tasks

  • Milestone 1: design notes will be published here
  • Milestone 2: A working prototype is currently tested. We need to add support for groups.
    source at :
    (* Milestone 3: Working prototype checked into the incubator supporting use cases #3 and #4.)
    (* Milestone 4: Unit tests exist, work, and are checked into SVN.)
    (* Milestone 5: Initial documentation exists.)

If a milestone is already done, begin the description with "[DONE]", like this:

  • Milestone #: [DONE] Unit tests ...

7. Class Index

  • Zend_Auth_Adapter_Exception
  • Zend_Auth_Adapter_Ldap

8. Use Cases


... (see good use cases book)

9. Class Skeletons

Here is a code snippet:



Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Mar 19, 2007

    <p>If I remember correctly, to conform with the coding standard Zend_Auth_Adapter_LDAP should be Zend_Auth_Adapter_Ldap</p>

  2. Apr 02, 2007

    <p>Instead of </p>

    <p>class Zend_Auth_Adapter_Ldap ($username, $password, $host, $domain=NULL, $port=NULL){ </p>

    <p>I would suggest </p>

    <p>class Zend_Auth_Adapter_Ldap ($username, $password, $host, $options=array()){</p>

    <p>where in options you can have the domain and port but also for information like basedn and group and so on. All which are needed for succesfull connection to imap </p>

    1. Apr 11, 2007

      <p>Ok Tom,</p>

      <p>the $options array will be used so as to allow any number of options.</p>

      <p>Maybe we should consider putting the host into the $options too.<br />
      This would let us use a config array, and put only 'dynamic' data (username and password) into the code.<br />
      Moreover, some other 'options' may become mandatory soon or later...<br />
      So we should rename this argument into 'params' instead of 'options' <ac:emoticon ac:name="wink" /></p>

      <p>I plan to default the port to 389.<br />
      also, it seems LDAP_OPT_PROTOCOL_VERSION should default to 3 unless specified .</p>

      <p> vincent</p>

  3. Apr 12, 2007

    <p>params would be a better name indeed. After all you have to specify parameters for the connection.</p>

    <p>As your plan regarding the port. 389 would be the right choice as most ldap servers default to this.<br />
    Defaulting to version 3 of the protocol is also fine. After all version 3 replaced version 2 back in the 90's.</p>

  4. May 11, 2007

    <p>Can this Zend_Auth_Adapter_Ldap be an extension on the (to be implemented) Zend_Ldap component ?</p>

    <p>The Zend_Ldap methods take care of accessing your LDAP service, so you can focus primary on the various authentication implementations.</p>

    <p>Just my 2-cents</p>

  5. May 18, 2007

    <p>I am happy to see the LDAP authentication adapter make it to the proposed stage, and I would like to encourage some more discussions and refinements to the proposal, in order to consider it for inclusion in the framework.</p>

    <p>I notice that in the requirements:</p>

    <blockquote><p>Zend_Auth_Adapter_Ldap will <strong>not save or store</strong> the username and passwords</p></blockquote>

    <p>The LDAP connection must be created with each request, so how does this happen without either requiring the username and password from the request or persisting such data necessary to recreate a connection in the PHP session?</p>

    <p>Maybe it would be worth mentioning in the requirements that this component may be developed independently of any component for generalized LDAP usage (e.g., proposed Zend_Ldap).</p>

    <p>Once an LDAP connection is established, is it discarded, or is it available for subsequent LDAP query purposes? If the LDAP connection is not subsequently available, why not?</p>

    <p>The component dependencies should be described in the proposal (e.g., Zend_Exception).</p>

    <p>Under what circumstances does <code>authenticate()</code>:</p>
    <li>throw an exception? (e.g., LDAP not present [mentioned])</li>
    <li>return an instance of <code>Zend_Auth_Result</code>? (e.g., incorrect password)</li>

    <p>Provide use cases to illustrate typical API usage and to demonstrate available features. For example, how to use this to authenticate a user agent across multiple requests?</p>

    <p>Flesh out the class skeletons a little bit.</p>

    <p>What kind of interoperability issues might we encounter with this component? (e.g., between ActiveDirectory and OpenLDAP)</p>

    <p>What other questions about this component might people share?</p>

  6. May 24, 2007

    <p>Darby,<br />
    Thanks for your comments</p>

    <p>I still had no answers from the auth mailing list, so I sent my mail again.</p>

    <p>Here, I tried to answer your comments into the proposal. <br />
    I defined more precisely the requirements and interactions<br />
    I added a exhaustive list of exceptions and FAILURES.<br />
    I added a list of open questions. </p>

    <p>I'll try to add some Usecases tomorrow.</p>

    <p>We definitely need testing for this component. I hope to get news from the list!<br />

  7. Sep 27, 2007

    <p>I am currently testing this adapter within an application I am building for my organisation (20,000+ users).</p>

    <p>I changed the following username password check, currently at line 147-148:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    if(empty($username) || empty($password)]]></ac:plain-text-body></ac:macro>

    <p>I allow empty passwords for two reasons:</p>
    <li>If the LDAP dir allows empty passwords, that's their security decision, not ours</li>
    <li>If someone does use an empty password, we shouldn't highlight that fact for all to see.</li>

    <p>Upon a sucessful authentication, should we set more than just the username in the $identity parameter when returning a new Zend_Auth_Result? </p>

    <p>Returning the LDAP attributes for the authenticated user would be rather useful and would allow us to do things like:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $auth = Zend_Auth::getInstance();

  8. Oct 02, 2007

    <p>I'm not sure this has been formally decided anywhere, but I would like to see a single API through which all LDAP-capable services (ActiveDirectory, OpenLDAP, etc.) could be accessed. This may mean a strategy, delegation, adapter, or perhaps even service locator pattern applied for this, as we currently have within Zend_Auth itself (both for different authentication mechanisms and for inter-request persistence of the identity) and with other components like Zend_Db_Adapter and Zend_Cache (has variable frontends and backends). The proposal does not seem to address how various LDAP-capable services would be accessible, and I think this should be addressed somehow before we could approve the proposal.</p>

    <p>Any word on when we can move this proposal forward?</p>

  9. Oct 02, 2007

    <p>Thanks to Tzali Sagiv for the following link to Active Directory Application Mode (ADAM), which is an LDAP directory service that runs as a user service, rather than as a system service:</p>

    <p><a class="external-link" href="">;displaylang=en</a></p>