Zend_Ldap-Introduction.xml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 16828 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="zend.ldap.introduction">
  5. <title>Einführung</title>
  6. <para>
  7. <classname>Zend_Ldap</classname> ist eine Klasse, mit der <acronym>LDAP</acronym>
  8. Operationen, wie das Durchsuchen, das Bearbeiten oder die Bindung an Einträge im
  9. <acronym>LDAP</acronym> Verzeichnis, durchgeführt werden können.
  10. </para>
  11. <sect2 id="zend.ldap.introduction.theory-of-operations">
  12. <title>Theorie der Verwendung</title>
  13. <para>
  14. Diese Komponente besteht aus der Hauptklasse <classname>Zend_Ldap</classname> welche
  15. konzeptionell eine Bindung an einen einzelnen <acronym>LDAP</acronym> Server
  16. repräsentiert und die Ausführung von Operationen an diesem <acronym>LDAP</acronym>
  17. Server erlaubt, wie zum Beispiel OpenLDAP oder ActiveDirectory (AD) Server. Die
  18. Parameter für das Binden können explizit oder in der Form eines Options Arrays
  19. angegeben werden. <classname>Zend_Ldap_Node</classname> bietet ein Objektorientiertes
  20. Interface für einen einzelnen <acronym>LDAP</acronym> Node und kann verwendet werden
  21. um eine Basis für ein Active-Record artiges Interface für ein <acronym>LDAP</acronym>
  22. basiertes Domain-Modell zu bieten.
  23. </para>
  24. <para>
  25. The component provides several helper classes to perform operations on
  26. <acronym>LDAP</acronym> entries (<classname>Zend_Ldap_Attribute</classname>) such as
  27. setting and retrieving attributes (date values, passwords, boolean values, ...), to
  28. create and modify <acronym>LDAP</acronym> filter strings
  29. (<classname>Zend_Ldap_Filter</classname>) and to manipulate <acronym>LDAP</acronym>
  30. distinguished names (DN) (<classname>Zend_Ldap_Dn</classname>).
  31. </para>
  32. <para>
  33. Additionally the component abstracts <acronym>LDAP</acronym> schema browsing
  34. for OpenLDAP and ActiveDirectoy servers <classname>Zend_Ldap_Node_Schema</classname>
  35. and server information retrieval for OpenLDAP-, ActiveDirectory- and Novell
  36. eDirectory servers (<classname>Zend_Ldap_Node_RootDse</classname>).
  37. </para>
  38. <para>
  39. Using the <classname>Zend_Ldap</classname> class depends on the type of
  40. <acronym>LDAP</acronym> server and is best summarized with some simple examples.
  41. </para>
  42. <para>
  43. If you are using OpenLDAP, a simple example looks like the following
  44. (note that the <emphasis>bindRequiresDn</emphasis> option is important if you are
  45. <emphasis>not</emphasis> using AD):
  46. </para>
  47. <programlisting language="php"><![CDATA[
  48. $options = array(
  49. 'host' => 's0.foo.net',
  50. 'username' => 'CN=user1,DC=foo,DC=net',
  51. 'password' => 'pass1',
  52. 'bindRequiresDn' => true,
  53. 'accountDomainName' => 'foo.net',
  54. 'baseDn' => 'OU=Sales,DC=foo,DC=net',
  55. );
  56. $ldap = new Zend_Ldap($options);
  57. $acctname = $ldap->getCanonicalAccountName('abaker',
  58. Zend_Ldap::ACCTNAME_FORM_DN);
  59. echo "$acctname\n";
  60. ]]></programlisting>
  61. <para>
  62. If you are using Microsoft AD a simple example is:
  63. </para>
  64. <programlisting language="php"><![CDATA[
  65. $options = array(
  66. 'host' => 'dc1.w.net',
  67. 'useStartTls' => true,
  68. 'username' => 'user1@w.net',
  69. 'password' => 'pass1',
  70. 'accountDomainName' => 'w.net',
  71. 'accountDomainNameShort' => 'W',
  72. 'baseDn' => 'CN=Users,DC=w,DC=net',
  73. );
  74. $ldap = new Zend_Ldap($options);
  75. $acctname = $ldap->getCanonicalAccountName('bcarter',
  76. Zend_Ldap::ACCTNAME_FORM_DN);
  77. echo "$acctname\n";
  78. ]]></programlisting>
  79. <para>
  80. Note that we use the <methodname>getCanonicalAccountName()</methodname> method
  81. to retrieve the account DN here only because that is what exercises the
  82. most of what little code is currently present in this class.
  83. </para>
  84. <sect3 id="zend.ldap.introduction.theory-of-operations.automatic-username-canonicalization">
  85. <title>Automatic Username Canonicalization When Binding</title>
  86. <para>
  87. If <methodname>bind()</methodname> is called with a non-DN username but
  88. <emphasis>bindRequiresDN</emphasis> is <constant>TRUE</constant> and no username in
  89. DN form was supplied as an option, the bind will fail. However, if a username in DN
  90. form is supplied in the options array, <classname>Zend_Ldap</classname> will
  91. first bind with that username, retrieve the account DN for the username
  92. supplied to <methodname>bind()</methodname> and then re-bind with that DN.
  93. </para>
  94. <para>
  95. This behavior is critical to <link
  96. linkend="zend.auth.adapter.ldap"><classname>Zend_Auth_Adapter_Ldap</classname></link>,
  97. which passes the username supplied by the user directly to
  98. <methodname>bind()</methodname>.
  99. </para>
  100. <para>
  101. The following example illustrates how the non-DN username
  102. '<emphasis>abaker</emphasis>' can be used with <methodname>bind()</methodname>:
  103. </para>
  104. <programlisting language="php"><![CDATA[
  105. $options = array(
  106. 'host' => 's0.foo.net',
  107. 'username' => 'CN=user1,DC=foo,DC=net',
  108. 'password' => 'pass1',
  109. 'bindRequiresDn' => true,
  110. 'accountDomainName' => 'foo.net',
  111. 'baseDn' => 'OU=Sales,DC=foo,DC=net',
  112. );
  113. $ldap = new Zend_Ldap($options);
  114. $ldap->bind('abaker', 'moonbike55');
  115. $acctname = $ldap->getCanonicalAccountName('abaker',
  116. Zend_Ldap::ACCTNAME_FORM_DN);
  117. echo "$acctname\n";
  118. ]]></programlisting>
  119. <para>
  120. The <methodname>bind()</methodname> call in this example sees that
  121. the username '<emphasis>abaker</emphasis>' is not in DN form, finds
  122. <emphasis>bindRequiresDn</emphasis> is <constant>TRUE</constant>, uses
  123. '<command>CN=user1,DC=foo,DC=net</command>' and '<emphasis>pass1</emphasis>' to
  124. bind, retrieves the DN for '<emphasis>abaker</emphasis>', unbinds and then rebinds
  125. with the newly discovered
  126. '<command>CN=Alice Baker,OU=Sales,DC=foo,DC=net</command>'.
  127. </para>
  128. </sect3>
  129. <sect3 id="zend.ldap.introduction.theory-of-operations.account-name-canonicalization">
  130. <title>Account Name Canonicalization</title>
  131. <para>
  132. The <emphasis>accountDomainName</emphasis> and
  133. <emphasis>accountDomainNameShort</emphasis>
  134. options are used for two purposes: (1) they facilitate multi-domain
  135. authentication and failover capability, and (2) they are also used to
  136. canonicalize usernames. Specifically, names are canonicalized to the
  137. form specified by the <emphasis>accountCanonicalForm</emphasis> option.
  138. This option may one of the following values:
  139. </para>
  140. <table id="zend.ldap.using.theory-of-operation.account-name-canonicalization.table">
  141. <title>Options for accountCanonicalForm</title>
  142. <tgroup cols="3">
  143. <thead>
  144. <row>
  145. <entry>Name</entry>
  146. <entry>Value</entry>
  147. <entry>Example</entry>
  148. </row>
  149. </thead>
  150. <tbody>
  151. <row>
  152. <entry>
  153. <constant>ACCTNAME_FORM_DN</constant>
  154. </entry>
  155. <entry>1</entry>
  156. <entry>CN=Alice Baker,CN=Users,DC=example,DC=com</entry>
  157. </row>
  158. <row>
  159. <entry>
  160. <constant>ACCTNAME_FORM_USERNAME</constant>
  161. </entry>
  162. <entry>2</entry>
  163. <entry>abaker</entry>
  164. </row>
  165. <row>
  166. <entry>
  167. <constant>ACCTNAME_FORM_BACKSLASH</constant>
  168. </entry>
  169. <entry>3</entry>
  170. <entry>EXAMPLE\abaker</entry>
  171. </row>
  172. <row>
  173. <entry>
  174. <constant>ACCTNAME_FORM_PRINCIPAL</constant>
  175. </entry>
  176. <entry>4</entry>
  177. <entry><filename>abaker@example.com</filename></entry>
  178. </row>
  179. </tbody>
  180. </tgroup>
  181. </table>
  182. <para>
  183. The default canonicalization depends on what account domain name options
  184. were supplied. If <emphasis>accountDomainNameShort</emphasis> was supplied, the
  185. default <emphasis>accountCanonicalForm</emphasis> value is
  186. <constant>ACCTNAME_FORM_BACKSLASH</constant>. Otherwise, if
  187. <emphasis>accountDomainName</emphasis> was supplied, the
  188. default is <constant>ACCTNAME_FORM_PRINCIPAL</constant>.
  189. </para>
  190. <para>
  191. Account name canonicalization ensures that the string used to identify
  192. an account is consistent regardless of what was supplied to
  193. <methodname>bind()</methodname>. For example, if the user supplies an account
  194. name of <filename>abaker@example.com</filename> or just
  195. <emphasis>abaker</emphasis> and the <emphasis>accountCanonicalForm</emphasis>
  196. is set to 3, the resulting canonicalized name would be
  197. <emphasis>EXAMPLE\abaker</emphasis>.
  198. </para>
  199. </sect3>
  200. <sect3 id="zend.ldap.introduction.theory-of-operations.multi-domain-failover">
  201. <title>Multi-domain Authentication and Failover</title>
  202. <para>
  203. The <classname>Zend_Ldap</classname> component by itself makes no attempt
  204. to authenticate with multiple servers. However, <classname>Zend_Ldap</classname>
  205. is specifically designed to handle this scenario gracefully. The
  206. required technique is to simply iterate over an array of arrays of serve
  207. options and attempt to bind with each server. As described above
  208. <methodname>bind()</methodname> will automatically canonicalize each name, so
  209. it does not matter if the user passes <filename>abaker@foo.net</filename> or
  210. <emphasis>W\bcarter</emphasis> or <emphasis>cdavis</emphasis> - the
  211. <methodname>bind()</methodname> method will only succeed if the credentials were
  212. successfully used in the bind.
  213. </para>
  214. <para>
  215. Consider the following example that illustrates the technique required to
  216. implement multi-domain authentication and failover:
  217. </para>
  218. <programlisting language="php"><![CDATA[
  219. $acctname = 'W\\user2';
  220. $password = 'pass2';
  221. $multiOptions = array(
  222. 'server1' => array(
  223. 'host' => 's0.foo.net',
  224. 'username' => 'CN=user1,DC=foo,DC=net',
  225. 'password' => 'pass1',
  226. 'bindRequiresDn' => true,
  227. 'accountDomainName' => 'foo.net',
  228. 'accountDomainNameShort' => 'FOO',
  229. 'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
  230. 'baseDn' => 'OU=Sales,DC=foo,DC=net',
  231. ),
  232. 'server2' => array(
  233. 'host' => 'dc1.w.net',
  234. 'useSsl' => true,
  235. 'username' => 'user1@w.net',
  236. 'password' => 'pass1',
  237. 'accountDomainName' => 'w.net',
  238. 'accountDomainNameShort' => 'W',
  239. 'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
  240. 'baseDn' => 'CN=Users,DC=w,DC=net',
  241. ),
  242. );
  243. $ldap = new Zend_Ldap();
  244. foreach ($multiOptions as $name => $options) {
  245. echo "Trying to bind using server options for '$name'\n";
  246. $ldap->setOptions($options);
  247. try {
  248. $ldap->bind($acctname, $password);
  249. $acctname = $ldap->getCanonicalAccountName($acctname);
  250. echo "SUCCESS: authenticated $acctname\n";
  251. return;
  252. } catch (Zend_Ldap_Exception $zle) {
  253. echo ' ' . $zle->getMessage() . "\n";
  254. if ($zle->getCode() === Zend_Ldap_Exception::LDAP_X_DOMAIN_MISMATCH) {
  255. continue;
  256. }
  257. }
  258. }
  259. ]]></programlisting>
  260. <para>
  261. If the bind fails for any reason, the next set of server options is tried.
  262. </para>
  263. <para>
  264. The <methodname>getCanonicalAccountName()</methodname> call gets the canonical
  265. account name that the application would presumably use to associate data with such
  266. as preferences. The <emphasis>accountCanonicalForm = 4</emphasis> in all server
  267. options ensures that the canonical form is consistent regardless of which
  268. server was ultimately used.
  269. </para>
  270. <para>
  271. The special <constant>LDAP_X_DOMAIN_MISMATCH</constant> exception occurs when an
  272. account name with a domain component was supplied (e.g.,
  273. <filename>abaker@foo.net</filename> or <emphasis>FOO\abaker</emphasis> and not just
  274. <emphasis>abaker</emphasis>) but the domain component did not match either domain
  275. in the currently selected server options. This exception indicates
  276. that the server is not an authority for the account. In this
  277. case, the bind will not be performed, thereby eliminating unnecessary
  278. communication with the server. Note that the <emphasis>continue</emphasis>
  279. instruction has no effect in this example, but in practice for error handling and
  280. debugging purposes, you will probably want to check for
  281. <constant>LDAP_X_DOMAIN_MISMATCH</constant> as well as
  282. <constant>LDAP_NO_SUCH_OBJECT</constant> and
  283. <constant>LDAP_INVALID_CREDENTIALS</constant>.
  284. </para>
  285. <para>
  286. The above code is very similar to code used within <link
  287. linkend="zend.auth.adapter.ldap"><classname>Zend_Auth_Adapter_Ldap</classname></link>.
  288. In fact, we recommend that you simply use that authentication adapter for
  289. multi-domain + failover <acronym>LDAP</acronym> based authentication
  290. (or copy the code).
  291. </para>
  292. </sect3>
  293. </sect2>
  294. </sect1>