Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Commit f1a18f3

Browse files
committed
Merge branch 'hotfix/48'
Close #48
2 parents eef2052 + 74bbe5a commit f1a18f3

20 files changed

+1252
-698
lines changed

.gitignore

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
.vagrant/
77
.*.sw*
88
.*.un~
9+
doc/html/
10+
tmp/
11+
vendor/
12+
zf-mkdoc-theme/
13+
914
clover.xml
1015
coveralls-upload.json
1116
nbproject
1217
phpunit.xml
13-
tmp/
14-
vendor/

.travis.yml

+14
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ branches:
1010
cache:
1111
directories:
1212
- $HOME/.composer/cache
13+
- $HOME/.local
14+
- zf-mkdoc-theme
1315

1416
addons:
1517
apt:
@@ -21,6 +23,11 @@ env:
2123
global:
2224
- TESTS_ZEND_LDAP_ONLINE_ENABLED=true
2325
- COMPOSER_ARGS="--no-interaction --ignore-platform-reqs"
26+
- SITE_URL: https://zendframework.github.io/zend-ldap
27+
- GH_USER_NAME: "Matthew Weier O'Phinney"
28+
- GH_USER_EMAIL: [email protected]
29+
- GH_REF: github.com/zendframework/zend-ldap.git
30+
- secure: "oyutreHfOP5k3jQ3zZ28iJj64OSVCNqnCVfQrWnTDf3woV63vK0Le4X1O6WopAbd8yoEaN30nJ49X81zAUFN4lneulvitFHjEHvzNkOxFPWxfBK+APCnu0U0Z/a0BiFyoo1A5CGS3OrRpT1WL+CpTy49gpaqlfCnUVP/EnOP1uisKQIVQFbzoKl+0yAMzIXZ8rS5uFTej9lKbGi0V3+Gg896xXsmhLkb4ElNNNkccvB11cgDBLUarM43qL/s7kINv1uPbJ51WERujlZkcRH/s4OcYKPRREeDr+9aMZTELTuGFKLQKrhuA13YkHOSB/j6NnXEuEIVCpaVndrMXm69NBe/IfOuvSQoa4m0E7Ks6DZlX7nkj3rudlmX/+KakI+uJQdQLs7JDYKchuhX5hDO0dHGNTdwsPJAb06zDKR2HIfgzVZTX27//5PAKSU5DLOEM9sDYJAhQkxt0iC1L4xmQo/XOG8VNXL7usARouVI9FhmgPezmUDaN4CzvrD6kYtOVL3I9UwklnBQ0tJbO/CHnaq/eiWeNFL4tPDNim6c4pz9YayFQbOlu3SUy6lE/fwbXS1YtMl3t0MlO62B8wt+x0XlIJVTmMK0PFVj/cl93WUYZxxTZnFNvcy3VtmK7g6aNtHpAJaDQCl6Fu8K4xrWoTewG9m78KXu7p21gv9BjW8="
2431

2532
matrix:
2633
fast_finish: true
@@ -42,6 +49,8 @@ matrix:
4249
env:
4350
- DEPS=locked
4451
- TEST_COVERAGE=true
52+
- DEPLOY_DOCS="$(if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then echo -n 'true' ; else echo -n 'false' ; fi)"
53+
- PATH="$HOME/.local/bin:$PATH"
4554
- php: 5.6
4655
env:
4756
- DEPS=latest
@@ -91,6 +100,11 @@ script:
91100
- if [[ $TEST_COVERAGE == 'true' ]]; then composer test-coverage ; fi
92101
- if [[ $TEST_COVERAGE != 'true' ]]; then composer test ; fi
93102
- if [[ $CHECK_CS == 'true' ]]; then composer cs-check ; fi
103+
- if [[ $DEPLOY_DOCS == "true" && "$TRAVIS_TEST_RESULT" == "0" ]]; then wget -O theme-installer.sh "https://raw.githubusercontent.com/zendframework/zf-mkdoc-theme/master/theme-installer.sh" ; chmod 755 theme-installer.sh ; ./theme-installer.sh ; fi
104+
105+
after_success:
106+
- if [[ $DEPLOY_DOCS == "true" ]]; then echo "Preparing to build and deploy documentation" ; ./zf-mkdoc-theme/deploy.sh ; echo "Completed deploying documentation" ; fi
107+
94108

95109
after_script:
96110
- if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer upload-coverage ; fi

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ All notable changes to this project will be documented in this file, in reverse
66

77
### Added
88

9-
- Nothing.
9+
- [#48](https://github.com/zendframework/zend-ldap/pull/48) adds and publishes
10+
the documentation to https://zendframework.github.io/zend-ldap/
1011

1112
### Deprecated
1213

README.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
[![Build Status](https://secure.travis-ci.org/zendframework/zend-ldap.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-ldap)
44
[![Coverage Status](https://coveralls.io/repos/zendframework/zend-ldap/badge.svg?branch=master)](https://coveralls.io/r/zendframework/zend-ldap?branch=master)
55

6-
`Zend\Ldap\Ldap` is a class for performing LDAP operations including but not
7-
limited to binding, searching and modifying entries in an LDAP directory.
8-
6+
zend-ldap provides functionality for performing LDAP operations, including, but
7+
not limited to, binding, searching and modifying entries in an LDAP directory.
98

109
- File issues at https://github.com/zendframework/zend-ldap/issues
11-
- Documentation is at http://framework.zend.com/manual/current/en/index.html#zend-ldap
10+
- Documentation is at https://zendframework.github.io/zend-ldap/

doc/book/api.md

+605
Large diffs are not rendered by default.

doc/book/index.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<div class="container">
2+
<div class="jumbotron">
3+
<h1>zend-ldap</h1>
4+
5+
<p>
6+
Perform LDAP operations, including binding, searching and modifying entries in an LDAP directory.
7+
</p>
8+
9+
<pre><code class="language-bash">$ composer require zendframework/zend-ldap</code></pre>
10+
</div>
11+
</div>
12+

doc/book/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../README.md

doc/book/intro.md

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# Introduction
2+
3+
zend-ldap lets you perform LDAP operations, including, but not limited to,
4+
binding, searching and modifying entries in an LDAP directory.
5+
6+
## Theory of operation
7+
8+
This component currently consists of the main `Zend\Ldap\Ldap` class, which
9+
conceptually represents a binding to a single LDAP server and allows for
10+
executing operations against a LDAP server such as OpenLDAP or ActiveDirectory
11+
(AD) servers. The parameters for binding may be provided explicitly or in the
12+
form of an options array. `Zend\Ldap\Node` provides an object-oriented interface
13+
for single LDAP nodes and can be used to form a basis for an active-record-like
14+
interface for a LDAP-based domain model.
15+
16+
The component provides several helper classes to perform operations on LDAP
17+
entries (`Zend\Ldap\Attribute`) such as setting and retrieving attributes (date
18+
values, passwords, boolean values, ...), to create and modify LDAP filter
19+
strings (`Zend\Ldap\Filter`) and to manipulate LDAP distinguished names (DN)
20+
(`Zend\Ldap\Dn`).
21+
22+
Additionally the component abstracts LDAP schema browsing for OpenLDAP and
23+
ActiveDirectory servers `Zend\Ldap\Node\Schema` and server information retrieval
24+
for OpenLDAP-, ActiveDirectory- and Novell eDirectory servers
25+
(`Zend\Ldap\Node\RootDse`).
26+
27+
Usage of zend-ldap depends on the type of LDAP server, and is best summarized with
28+
some examples.
29+
30+
If you are using OpenLDAP, consider the following example (note that the
31+
`bindRequiresDn` option is important if you are **not** using AD):
32+
33+
```php
34+
use Zend\Ldap\Ldap;
35+
36+
$options = [
37+
'host' => 's0.foo.net',
38+
'username' => 'CN=user1,DC=foo,DC=net',
39+
'password' => 'pass1',
40+
'bindRequiresDn' => true,
41+
'accountDomainName' => 'foo.net',
42+
'baseDn' => 'OU=Sales,DC=foo,DC=net',
43+
];
44+
45+
$ldap = new Ldap($options);
46+
$acctname = $ldap->getCanonicalAccountName('abaker', Ldap::ACCTNAME_FORM_DN);
47+
echo "$acctname\n";
48+
```
49+
50+
If you are using Microsoft AD:
51+
52+
```php
53+
use Zend\Ldap\Ldap;
54+
55+
$options = [
56+
'host' => 'dc1.w.net',
57+
'useStartTls' => true,
58+
'username' => '[email protected]',
59+
'password' => 'pass1',
60+
'accountDomainName' => 'w.net',
61+
'accountDomainNameShort' => 'W',
62+
'baseDn' => 'CN=Users,DC=w,DC=net',
63+
];
64+
65+
$ldap = new Ldap($options);
66+
$acctname = $ldap->getCanonicalAccountName('bcarter', Ldap::ACCTNAME_FORM_DN);
67+
echo "$acctname\n";
68+
```
69+
70+
Note that we use the `getCanonicalAccountName()` method to retrieve the account
71+
DN here only because that is what exercises the most of what little code is
72+
currently present in this class.
73+
74+
### Automatic Username Canonicalization When Binding
75+
76+
If `bind()` is called with a non-DN username but `bindRequiresDN` is `true`
77+
and no username in DN form was supplied as an option, the bind will fail.
78+
However, if a username in DN form is supplied in the options array,
79+
`Zend\Ldap\Ldap` will first bind with that username, retrieve the account DN for
80+
the username supplied to `bind()` and then re-bind with that DN.
81+
82+
This behavior is critical to [Zend\\Authentication\\Adapter\\Ldap](http://zendframework.github.io/zend-authentication/adapter/ldap/),
83+
which passes the username supplied by the user directly to `bind()`.
84+
85+
The following example illustrates how the non-DN username 'abaker' can be used
86+
with `bind()`:
87+
88+
```php
89+
use Zend\Ldap\Ldap;
90+
91+
$options = [
92+
'host' => 's0.foo.net',
93+
'username' => 'CN=user1,DC=foo,DC=net',
94+
'password' => 'pass1',
95+
'bindRequiresDn' => true,
96+
'accountDomainName' => 'foo.net',
97+
'baseDn' => 'OU=Sales,DC=foo,DC=net',
98+
];
99+
100+
$ldap = new Ldap($options);
101+
$ldap->bind('abaker', 'moonbike55');
102+
$acctname = $ldap->getCanonicalAccountName('abaker', Ldap::ACCTNAME_FORM_DN);
103+
echo "$acctname\n";
104+
```
105+
106+
The `bind()` call in this example sees that the username 'abaker' is not in DN
107+
form, finds `bindRequiresDn` is `TRUE`, uses `CN=user1,DC=foo,DC=net` and
108+
`pass1` to bind, retrieves the DN for 'abaker', unbinds and then rebinds with
109+
the newly discovered `CN=Alice Baker,OU=Sales,DC=foo,DC=net`.
110+
111+
### Account Name Canonicalization
112+
113+
The `accountDomainName` and `accountDomainNameShort` options are used for two
114+
purposes: (1) they facilitate multi-domain authentication and failover
115+
capability, and (2) they are also used to canonicalize usernames. Specifically,
116+
names are canonicalized to the form specified by the `accountCanonicalForm`
117+
option. This option may one of the following values:
118+
119+
The default canonicalization depends on what account domain name options were
120+
supplied. If `accountDomainNameShort` was supplied, the default
121+
`accountCanonicalForm` value is `ACCTNAME_FORM_BACKSLASH`. Otherwise, if
122+
`accountDomainName` was supplied, the default is `ACCTNAME_FORM_PRINCIPAL`.
123+
124+
Account name canonicalization ensures that the string used to identify an
125+
account is consistent regardless of what was supplied to `bind()`. For example,
126+
if the user supplies an account name of `[email protected]` or just `abaker`
127+
and the `accountCanonicalForm` is set to 3, the resulting canonicalized name
128+
would be `EXAMPLE\\abaker`.
129+
130+
### Multi-domain Authentication and Failover
131+
132+
The `Zend\Ldap\Ldap` component by itself makes no attempt to authenticate with
133+
multiple servers. However, `Zend\Ldap\Ldap` is specifically designed to handle
134+
this scenario gracefully. The required technique is to simply iterate over an
135+
array of arrays of serve options and attempt to bind with each server. As
136+
described above `bind()` will automatically canonicalize each name, so it does
137+
not matter if the user passes `[email protected]` or `Wbcarter` or `cdavis`; the
138+
`bind()` method will only succeed if the credentials were successfully used in
139+
the bind.
140+
141+
Consider the following example that illustrates the technique required to
142+
implement multi-domain authentication and failover:
143+
144+
```php
145+
use Zend\Ldap\Exception\LdapException;
146+
use Zend\Ldap\Ldap;
147+
148+
$acctname = 'W\\user2';
149+
$password = 'pass2';
150+
151+
$multiOptions = [
152+
'server1' => [
153+
'host' => 's0.foo.net',
154+
'username' => 'CN=user1,DC=foo,DC=net',
155+
'password' => 'pass1',
156+
'bindRequiresDn' => true,
157+
'accountDomainName' => 'foo.net',
158+
'accountDomainNameShort' => 'FOO',
159+
'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
160+
'baseDn' => 'OU=Sales,DC=foo,DC=net',
161+
],
162+
'server2' => [
163+
'host' => 'dc1.w.net',
164+
'useSsl' => true,
165+
'username' => '[email protected]',
166+
'password' => 'pass1',
167+
'accountDomainName' => 'w.net',
168+
'accountDomainNameShort' => 'W',
169+
'accountCanonicalForm' => 4, // ACCT_FORM_PRINCIPAL
170+
'baseDn' => 'CN=Users,DC=w,DC=net',
171+
],
172+
];
173+
174+
$ldap = new Ldap();
175+
176+
foreach ($multiOptions as $name => $options) {
177+
echo "Trying to bind using server options for '$name'\n";
178+
179+
$ldap->setOptions($options);
180+
try {
181+
$ldap->bind($acctname, $password);
182+
$acctname = $ldap->getCanonicalAccountName($acctname);
183+
echo "SUCCESS: authenticated $acctname\n";
184+
return;
185+
} catch (LdapException $zle) {
186+
echo ' ' . $zle->getMessage() . "\n";
187+
if ($zle->getCode() === LdapException::LDAP_X_DOMAIN_MISMATCH) {
188+
continue;
189+
}
190+
}
191+
}
192+
```
193+
194+
If the bind fails for any reason, the next set of server options is tried.
195+
196+
The `getCanonicalAccountName()` call gets the canonical account name that the
197+
application would presumably use to associate data with such as preferences. The
198+
`accountCanonicalForm = 4` in all server options ensures that the canonical form
199+
is consistent regardless of which server was ultimately used.
200+
201+
The special `LDAP_X_DOMAIN_MISMATCH` exception occurs when an account name with
202+
a domain component was supplied (e.g., `[email protected]` or `FOO\\abaker` and not
203+
just `abaker`) but the domain component did not match either domain in the
204+
currently selected server options. This exception indicates that the server is
205+
not an authority for the account. In this case, the bind will not be performed,
206+
thereby eliminating unnecessary communication with the server. Note that the
207+
`continue` instruction has no effect in this example, but in practice for error
208+
handling and debugging purposes, you will probably want to check for
209+
`LDAP_X_DOMAIN_MISMATCH` as well as `LDAP_NO_SUCH_OBJECT` and
210+
`LDAP_INVALID_CREDENTIALS`.
211+
212+
The above code is very similar to code used within
213+
[Zend\\Authentication\\Adapter\\Ldap](http://zendframework.github.io/zend-authentication/adapter/ldap/).
214+
In fact,we recommend that you use that authentication adapter for multi-domain +
215+
failover LDAP based authentication (or copy the code).

0 commit comments

Comments
 (0)