|
|
@@ -1,430 +0,0 @@
|
|
|
-<?xml version="1.0" encoding="UTF-8"?>
|
|
|
-<!-- Reviewed: no -->
|
|
|
-<sect1 id="zend.ldap.using">
|
|
|
-
|
|
|
- <title>Introduction</title>
|
|
|
-
|
|
|
- <note>
|
|
|
- <title>Minimal Functionality</title>
|
|
|
- <para>
|
|
|
- Currently this class is designed only to satisfy the limited functionality necessary for the
|
|
|
- <link linkend="zend.auth.adapter.ldap"><classname>Zend_Auth_Adapter_Ldap</classname></link> authentication adapter.
|
|
|
- Operations such as searching, creating, modifying or renaming entries in the directory are currently not
|
|
|
- supported and will be defined at a later time.
|
|
|
- </para>
|
|
|
- </note>
|
|
|
-
|
|
|
- <para>
|
|
|
- <classname>Zend_Ldap</classname> is a class for performing LDAP operations including but not limited to binding,
|
|
|
- searching and modifying entries in an LDAP directory.
|
|
|
- </para>
|
|
|
-
|
|
|
- <sect2 id="zend.ldap.using.theory-of-operation">
|
|
|
-
|
|
|
- <title>Theory of Operation</title>
|
|
|
-
|
|
|
- <para>
|
|
|
- This component currently consists of two classes, <classname>Zend_Ldap</classname> and
|
|
|
- <classname>Zend_Ldap_Exception</classname>. The <classname>Zend_Ldap</classname> class conceptually represents a binding to a
|
|
|
- single LDAP server. The parameters for binding may be provided explicitly or in the form of an options
|
|
|
- array.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- Using the <classname>Zend_Ldap</classname> class depends on the type of LDAP server and is best summarized with some
|
|
|
- simple examples.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- If you are using OpenLDAP, a simple example looks like the following (note that the
|
|
|
- <code>bindRequiresDn</code> option is important if you are <emphasis>not</emphasis> using AD):
|
|
|
-
|
|
|
- <programlisting language="php"><![CDATA[
|
|
|
-$options = array(
|
|
|
- 'host' => 's0.foo.net',
|
|
|
- 'username' => 'CN=user1,DC=foo,DC=net',
|
|
|
- 'password' => 'pass1',
|
|
|
- 'bindRequiresDn' => true,
|
|
|
- 'accountDomainName' => 'foo.net',
|
|
|
- 'baseDn' => 'OU=Sales,DC=foo,DC=net',
|
|
|
-);
|
|
|
-$ldap = new Zend_Ldap($options);
|
|
|
-$acctname = $ldap->getCanonicalAccountName('abaker',
|
|
|
- Zend_Ldap::ACCTNAME_FORM_DN);
|
|
|
-echo "$acctname\n";
|
|
|
-]]></programlisting>
|
|
|
-
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- If you are using Microsoft AD a simple example is:
|
|
|
-
|
|
|
- <programlisting language="php"><![CDATA[
|
|
|
-$options = array(
|
|
|
- 'host' => 'dc1.w.net',
|
|
|
- 'useStartTls' => true,
|
|
|
- 'username' => 'user1@w.net',
|
|
|
- 'password' => 'pass1',
|
|
|
- 'accountDomainName' => 'w.net',
|
|
|
- 'accountDomainNameShort' => 'W',
|
|
|
- 'baseDn' => 'CN=Users,DC=w,DC=net',
|
|
|
-);
|
|
|
-$ldap = new Zend_Ldap($options);
|
|
|
-$acctname = $ldap->getCanonicalAccountName('bcarter',
|
|
|
- Zend_Ldap::ACCTNAME_FORM_DN);
|
|
|
-echo "$acctname\n";
|
|
|
-]]></programlisting>
|
|
|
-
|
|
|
- Note that we use the <code>getCanonicalAccountName()</code> method to retrieve the account DN here only
|
|
|
- because that is what exercises the most of what little code is currently present in this class.
|
|
|
- </para>
|
|
|
-
|
|
|
- <sect3 id="zend.ldap.using.theory-of-operation.username-canonicalization-automatic">
|
|
|
-
|
|
|
- <title>Automatic Username Canonicalization When Binding</title>
|
|
|
-
|
|
|
- <para>
|
|
|
- If <code>bind()</code> is called with a non-DN username but <code>bindRequiresDN</code> is
|
|
|
- <constant>TRUE</constant> and no username in DN form was supplied as an option, the bind will fail. However, if
|
|
|
- a username in DN form is supplied in the options array, <classname>Zend_Ldap</classname> will first bind with
|
|
|
- that username, retrieve the account DN for the username supplied to <code>bind()</code> and then re-
|
|
|
- bind with that DN.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- This behavior is critical to <classname>Zend_Auth_Adapter_Ldap</classname>, which passes the username supplied by
|
|
|
- the user directly to <code>bind()</code>.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The following example illustrates how the non-DN username '<code>abaker</code>' can be used with
|
|
|
- <code>bind()</code>:
|
|
|
-
|
|
|
- <programlisting language="php"><![CDATA[
|
|
|
-$options = array(
|
|
|
- 'host' => 's0.foo.net',
|
|
|
- 'username' => 'CN=user1,DC=foo,DC=net',
|
|
|
- 'password' => 'pass1',
|
|
|
- 'bindRequiresDn' => true,
|
|
|
- 'accountDomainName' => 'foo.net',
|
|
|
- 'baseDn' => 'OU=Sales,DC=foo,DC=net',
|
|
|
-);
|
|
|
-$ldap = new Zend_Ldap($options);
|
|
|
-$ldap->bind('abaker', 'moonbike55');
|
|
|
-$acctname = $ldap->getCanonicalAccountName('abaker',
|
|
|
- Zend_Ldap::ACCTNAME_FORM_DN);
|
|
|
-echo "$acctname\n";
|
|
|
-]]></programlisting>
|
|
|
-
|
|
|
- The <code>bind()</code> call in this example sees that the username '<code>abaker</code>' is not in DN
|
|
|
- form, finds <code>bindRequiresDn</code> is <constant>TRUE</constant>, uses
|
|
|
- '<code>CN=user1,DC=foo,DC=net</code>' and '<code>pass1</code>' to bind, retrieves the DN for
|
|
|
- '<code>abaker</code>', unbinds and then rebinds with the newly discovered
|
|
|
- '<code>CN=Alice Baker,OU=Sales,DC=foo,DC=net</code>'.
|
|
|
- </para>
|
|
|
-
|
|
|
- </sect3>
|
|
|
-
|
|
|
- <sect3 id="zend.ldap.using.theory-of-operation.options">
|
|
|
-
|
|
|
- <title>Zend_Ldap Options</title>
|
|
|
-
|
|
|
- <para>
|
|
|
- The <classname>Zend_Ldap</classname> component accepts an array of options either supplied to the constructor or
|
|
|
- through the <code>setOptions()</code> method. The permitted options are as follows:
|
|
|
-
|
|
|
- <table id="zend.ldap.using.theory-of-operation.options.table">
|
|
|
- <title>Zend_Ldap Options</title>
|
|
|
- <tgroup cols="2">
|
|
|
- <thead>
|
|
|
- <row>
|
|
|
- <entry>Name</entry>
|
|
|
- <entry>Description</entry>
|
|
|
- </row>
|
|
|
- </thead>
|
|
|
- <tbody>
|
|
|
- <row>
|
|
|
- <entry>host</entry>
|
|
|
- <entry>
|
|
|
- The default hostname of LDAP server if not supplied to <code>connect()</code> (also may be
|
|
|
- used when trying to canonicalize usernames in <code>bind()</code>).
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>port</entry>
|
|
|
- <entry>
|
|
|
- Default port of LDAP server if not supplied to <code>connect()</code>.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>useStartTls</entry>
|
|
|
- <entry>
|
|
|
- Whether or not the LDAP client should use TLS (aka SSLv2) encrypted transport. A value of
|
|
|
- <constant>TRUE</constant> is strongly favored in production environments to prevent passwords from
|
|
|
- be transmitted in clear text. The default value is <constant>FALSE</constant>, as servers
|
|
|
- frequently require that a certificate be installed separately after installation.
|
|
|
- The <code>useSsl</code> and <code>useStartTls</code> options are mutually exclusive.
|
|
|
- The <code>useStartTls</code> option should be favored over <code>useSsl</code> but
|
|
|
- not all servers support this newer mechanism.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>useSsl</entry>
|
|
|
- <entry>
|
|
|
- Whether or not the LDAP client should use SSL encrypted transport. The <code>useSsl</code>
|
|
|
- and <code>useStartTls</code> options are mutually exclusive.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>username</entry>
|
|
|
- <entry>
|
|
|
- The default credentials username. Some servers require that this be in DN form.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>password</entry>
|
|
|
- <entry>
|
|
|
- The default credentials password (used only with username above).
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>bindRequiresDn</entry>
|
|
|
- <entry>
|
|
|
- If <constant>TRUE</constant>, this instructs <classname>Zend_Ldap</classname> to retrieve the DN for the
|
|
|
- account used to bind if the username is not already in DN form. The default value is
|
|
|
- <constant>FALSE</constant>.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>baseDn</entry>
|
|
|
- <entry>
|
|
|
- The default base DN used for searching (e.g., for accounts). This option is required for
|
|
|
- most account related operations and should indicate the DN under which accounts are
|
|
|
- located.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>accountCanonicalForm</entry>
|
|
|
- <entry>
|
|
|
- A small integer indicating the form to which account names should be canonicalized. See the
|
|
|
- <emphasis>Account Name Canonicalization</emphasis> section below.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>accountDomainName</entry>
|
|
|
- <entry>
|
|
|
- The FQDN domain for which the target LDAP server is an authority (e.g., example.com).
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>accountDomainNameShort</entry>
|
|
|
- <entry>
|
|
|
- The 'short' domain for which the target LDAP server is an authority. This is usually used
|
|
|
- to specify the NetBIOS domain name for Windows networks but may also be used by non-AD
|
|
|
- servers.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>accountFilterFormat</entry>
|
|
|
- <entry>
|
|
|
- The LDAP search filter used to search for accounts. This string is a
|
|
|
- <ulink url="http://php.net/printf"><code>printf()</code></ulink> style expression that must
|
|
|
- contain one '<code>%s</code>' to accommodate the username. The default value is
|
|
|
- '<code>(&(objectClass=user)(sAMAccountName=%s))</code>' unless
|
|
|
- <code>bindRequiresDn</code> is set to <constant>TRUE</constant>, in which case the default is
|
|
|
- '<code>(&(objectClass=posixAccount)(uid=%s))</code>'. Users of custom schemas may need
|
|
|
- to change this option.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>allowEmptyPassword</entry>
|
|
|
- <entry>
|
|
|
- Some LDAP servers can be configured to accept an empty string
|
|
|
- password as an anonymous bind. This behavior is almost always
|
|
|
- undesirable. For this reason, empty passwords are explicitly
|
|
|
- disallowed. Set this value to <constant>TRUE</constant> to allow an
|
|
|
- empty string password to be submitted during the bind.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry>optReferrals</entry>
|
|
|
- <entry>
|
|
|
- If set to <constant>TRUE</constant>, this option indicates to the LDAP client that referrals should
|
|
|
- be followed. The default value is <constant>FALSE</constant>.
|
|
|
- </entry>
|
|
|
- </row>
|
|
|
- </tbody>
|
|
|
- </tgroup>
|
|
|
- </table>
|
|
|
-
|
|
|
- </para>
|
|
|
-
|
|
|
- </sect3>
|
|
|
-
|
|
|
- <sect3 id="zend.ldap.using.theory-of-operation.account-name-canonicalization">
|
|
|
-
|
|
|
- <title>Account Name Canonicalization</title>
|
|
|
-
|
|
|
- <para>
|
|
|
- The <code>accountDomainName</code> and <code>accountDomainNameShort</code> options are used for two
|
|
|
- purposes: (1) they facilitate multi-domain authentication and failover capability, and (2) they are
|
|
|
- also used to canonicalize usernames. Specifically, names are canonicalized to the form specified by the
|
|
|
- <code>accountCanonicalForm</code> option. This option may one of the following values:
|
|
|
-
|
|
|
- <table id="zend.ldap.using.theory-of-operation.account-name-canonicalization.table">
|
|
|
- <title>accountCanonicalForm</title>
|
|
|
- <tgroup cols="3">
|
|
|
- <thead>
|
|
|
- <row>
|
|
|
- <entry>Name</entry>
|
|
|
- <entry>Value</entry>
|
|
|
- <entry>Example</entry>
|
|
|
- </row>
|
|
|
- </thead>
|
|
|
- <tbody>
|
|
|
- <row>
|
|
|
- <entry><code>ACCTNAME_FORM_DN</code></entry>
|
|
|
- <entry>1</entry>
|
|
|
- <entry>CN=Alice Baker,CN=Users,DC=example,DC=com</entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry><code>ACCTNAME_FORM_USERNAME</code></entry>
|
|
|
- <entry>2</entry>
|
|
|
- <entry>abaker</entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry><code>ACCTNAME_FORM_BACKSLASH</code></entry>
|
|
|
- <entry>3</entry>
|
|
|
- <entry>EXAMPLE\abaker</entry>
|
|
|
- </row>
|
|
|
- <row>
|
|
|
- <entry><code>ACCTNAME_FORM_PRINCIPAL</code></entry>
|
|
|
- <entry>4</entry>
|
|
|
- <entry>abaker@example.com</entry>
|
|
|
- </row>
|
|
|
- </tbody>
|
|
|
- </tgroup>
|
|
|
- </table>
|
|
|
-
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The default canonicalization depends on what account domain name options were supplied. If
|
|
|
- <code>accountDomainNameShort</code> was supplied, the default <code>accountCanonicalForm</code> value
|
|
|
- is <code>ACCTNAME_FORM_BACKSLASH</code>. Otherwise, if <code>accountDomainName</code> was supplied, the
|
|
|
- default is <code>ACCTNAME_FORM_PRINCIPAL</code>.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- Account name canonicalization ensures that the string used to identify an account is consistent
|
|
|
- regardless of what was supplied to <code>bind()</code>. For example, if the user supplies an account
|
|
|
- name of <emphasis>abaker@example.com</emphasis> or just <emphasis>abaker</emphasis> and the
|
|
|
- <code>accountCanonicalForm</code> is set to 3, the resulting canonicalized name would be
|
|
|
- <emphasis>EXAMPLE\abaker</emphasis>.
|
|
|
- </para>
|
|
|
-
|
|
|
- </sect3>
|
|
|
-
|
|
|
- <sect3 id="zend.ldap.using.theory-of-operation.multi-domain-failover">
|
|
|
-
|
|
|
- <title>Multi-domain Authentication and Failover</title>
|
|
|
-
|
|
|
- <para>
|
|
|
- The <classname>Zend_Ldap</classname> component by itself makes no attempt to authenticate with multiple servers.
|
|
|
- However, <classname>Zend_Ldap</classname> is specifically designed to handle this scenario gracefully. The
|
|
|
- required technique is to simply iterate over an array of arrays of server options and attempt to bind
|
|
|
- with each server. As described above <code>bind()</code> will automatically canonicalize each name, so
|
|
|
- it does not matter if the user passes <code>abaker@foo.net</code> or <code>W\bcarter</code> or
|
|
|
- <code>cdavis</code> - the <code>bind()</code> method will only succeed if the credentials were
|
|
|
- successfully used in the bind.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- Consider the following example that illustrates the technique required to implement multi-domain
|
|
|
- authentication and failover:
|
|
|
-
|
|
|
- <programlisting language="php"><![CDATA[
|
|
|
-$acctname = 'W\\user2';
|
|
|
-$password = 'pass2';
|
|
|
-
|
|
|
-$multiOptions = array(
|
|
|
- 'server1' => array(
|
|
|
- 'host' => 's0.foo.net',
|
|
|
- 'username' => 'CN=user1,DC=foo,DC=net',
|
|
|
- 'password' => 'pass1',
|
|
|
- 'bindRequiresDn' => true,
|
|
|
- 'accountDomainName' => 'foo.net',
|
|
|
- 'accountDomainNameShort' => 'FOO',
|
|
|
- 'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
|
|
|
- 'baseDn' => 'OU=Sales,DC=foo,DC=net',
|
|
|
- ),
|
|
|
- 'server2' => array(
|
|
|
- 'host' => 'dc1.w.net',
|
|
|
- 'useSsl' => true,
|
|
|
- 'username' => 'user1@w.net',
|
|
|
- 'password' => 'pass1',
|
|
|
- 'accountDomainName' => 'w.net',
|
|
|
- 'accountDomainNameShort' => 'W',
|
|
|
- 'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
|
|
|
- 'baseDn' => 'CN=Users,DC=w,DC=net',
|
|
|
- ),
|
|
|
-);
|
|
|
-
|
|
|
-$ldap = new Zend_Ldap();
|
|
|
-
|
|
|
-foreach ($multiOptions as $name => $options) {
|
|
|
-
|
|
|
- echo "Trying to bind using server options for '$name'\n";
|
|
|
-
|
|
|
- $ldap->setOptions($options);
|
|
|
- try {
|
|
|
- $ldap->bind($acctname, $password);
|
|
|
- $acctname = $ldap->getCanonicalAccountName($acctname);
|
|
|
- echo "SUCCESS: authenticated $acctname\n";
|
|
|
- return;
|
|
|
- } catch (Zend_Ldap_Exception $zle) {
|
|
|
- echo ' ' . $zle->getMessage() . "\n";
|
|
|
- if ($zle->getCode() === Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-]]></programlisting>
|
|
|
-
|
|
|
- If the bind fails for any reason, the next set of server options is tried.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The <code>getCanonicalAccountName</code> call gets the canonical account name that the application
|
|
|
- would presumably use to associate data with such as preferences. The
|
|
|
- <code>accountCanonicalForm = 4</code> in all server options ensures that the canonical form is
|
|
|
- consistent regardless of which server was ultimately used.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The special <code>LDAP_X_DOMAIN_MISMATCH</code> exception occurs when an account name with a domain
|
|
|
- component was supplied (e.g., <code>abaker@foo.net</code> or <code>FOO\abaker</code> and not just
|
|
|
- <code>abaker</code>) but the domain component did not match either domain in the currently selected
|
|
|
- server options. This exception indicates that the server is not an authority for the account. In this
|
|
|
- case, the bind will not be performed, thereby eliminating unnecessary communication with the server.
|
|
|
- Note that the <code>continue</code> instruction has no effect in this example, but in practice for
|
|
|
- error handling and debugging purposes, you will probably want to check for
|
|
|
- <code>LDAP_X_DOMAIN_MISMATCH</code> as well as <code>LDAP_NO_SUCH_OBJECT</code> and
|
|
|
- <code>LDAP_INVALID_CREDENTIALS</code>.
|
|
|
- </para>
|
|
|
-
|
|
|
- <para>
|
|
|
- The above code is very similar to code used within
|
|
|
- <link linkend="zend.auth.adapter.ldap"><classname>Zend_Auth_Adapter_Ldap</classname></link>. In fact, we
|
|
|
- recommend that you simply use that authentication adapter for multi-domain + failover LDAP based
|
|
|
- authentication (or copy the code).
|
|
|
- </para>
|
|
|
-
|
|
|
- </sect3>
|
|
|
-
|
|
|
- </sect2>
|
|
|
-
|
|
|
-</sect1>
|
|
|
-<!--
|
|
|
-vim:se ts=4 sw=4 et:
|
|
|
--->
|