~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/auth_ldap/docs/index.rst

mergeĀ lp:~hingo/drizzle/drizzle-auth_ldap-fix-and-docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
using an :abbr:`LDAP (Lightweight Directory Access Protocol)` server.  An
8
8
LDAP server is required to provide authentication.
9
9
 
 
10
Note that a typical use case for using LDAP based authentication, and the
 
11
intention with this module, is to be able to consolidate your Drizzle usernames
 
12
and passwords in cases where you are already using LDAP in your organization
 
13
(such as for Linux or Windows or other system passwords). 
 
14
 
 
15
If you are not currently using LDAP for any kind of authentication, you should 
 
16
be aware that this is not the simplest authentication method available. For other 
 
17
alternatives for managing Drizzle users and passwords, see 
 
18
:doc:`/administration/authentication`. A simple authentication module, whose 
 
19
behavior will be familiar to those familiar with MySQL and its method for 
 
20
storing usernames and passwords, is the :doc:`/plugins/auth_schema/index` plugin.
 
21
 
10
22
.. note::
11
23
 
12
24
   Unload the :doc:`/plugins/auth_all/index` plugin before using this plugin.
22
34
 
23
35
   --plugin-add=auth_ldap
24
36
 
25
 
Loading the plugin may not enable or configure it.  See the plugin's
 
37
Or, to disable the ability to login without a password, use::
 
38
 
 
39
   --plugin-add=auth_pam --plugin-remove=auth_all
 
40
 
 
41
Just loading this plugin will not enable or configure it. To actually bind to an
 
42
LDAP directory you also need to configure it. See the plugin's
26
43
:ref:`auth_ldap_configuration` and :ref:`auth_ldap_variables`.
27
44
 
28
45
.. seealso:: :ref:`drizzled_plugin_options` for more information about adding and removing plugins.
45
62
 
46
63
   DN to use when searching.
47
64
 
48
 
.. option:: --auth-ldap.bind-db ARG
 
65
   Drizzle uses the ``LDAP_SCOPE_ONELEVEL`` option when searching the LDAP 
 
66
   directory. This means you must specify the full base-dn. For instance, if
 
67
   you have users defined in the dn ``ou=people,dn=example,dn=com`` authentication
 
68
   will fail if you only specify ``dn=example,dn=com``. (See 
 
69
   :ref:`auth_ldap_limitations`)
 
70
 
 
71
.. option:: --auth-ldap.bind-dn ARG
49
72
 
50
73
   :Default: 
51
74
   :Variable: :ref:`auth_ldap_bind_dn <auth_ldap_bind_dn>`
52
75
 
53
76
   DN to use when binding to the LDAP server.
54
77
 
 
78
   Until Drizzle 2011.11.29 (a Drizzle 7.1 beta release) this option was mistakenly
 
79
   called ``bind-db``. Starting with release 2011.12.30 that option will no longer
 
80
   work, the correct option is ``bind-dn``. (The corresponding variable was
 
81
   always ref:`auth_ldap_bind_dn <auth_ldap_bind_dn>` and is unchanged.)
 
82
   
 
83
 
55
84
.. option:: --auth-ldap.bind-password ARG
56
85
 
57
86
   :Default: 
58
87
   :Variable: :ref:`auth_ldap_bind_password <auth_ldap_bind_password>`
59
88
 
60
 
   Password to use when binding the DN.
 
89
   Password to use when binding the DN, ie. your LDAP admin password.
61
90
 
62
91
.. option:: --auth-ldap.cache-timeout ARG
63
92
 
64
 
   :Default: ``0``
 
93
   :Default: ``600``
65
94
   :Variable: :ref:`auth_ldap_cache_timeout <auth_ldap_cache_timeout>`
66
95
 
67
 
   How often to empty the users cache, 0 to disable.
 
96
   How often to empty the users cache. The default is 10 minutes.
 
97
 
 
98
   A value of 0 means never: if a user has once connected to Drizzle, his 
 
99
   credentials will then be cached until the next restart. Any changes to the 
 
100
   LDAP directory, such as changing the password, would not be visible in 
 
101
   drizzled as long as it wasn't restarted.
68
102
 
69
103
.. option:: --auth-ldap.mysql-password-attribute ARG
70
104
 
71
 
   :Default: ``mysqlUserPassword``
 
105
   :Default: ``drizzleMysqlUserPassword``
72
106
   :Variable: :ref:`auth_ldap_mysql_password_attribute <auth_ldap_mysql_password_attribute>`
73
107
 
74
108
   Attribute in LDAP with MySQL hashed password.
75
109
 
 
110
   Until Drizzle 2011.11.29 (a Drizzle 7.1 beta release) the default value of this
 
111
   option was ``mysqlUserPassword``. Beginning with release 2011.12.30
 
112
   it was changed to ``drizzleMysqlUserPassword`` to match the provided
 
113
   openldap ldif schema.
 
114
 
76
115
.. option:: --auth-ldap.password-attribute ARG
77
116
 
78
117
   :Default: ``userPassword``
111
150
 
112
151
   :Scope: Global
113
152
   :Dynamic: No
114
 
   :Option: :option:`--auth-ldap.bind-db`
 
153
   :Option: :option:`--auth-ldap.bind-dn`
115
154
 
116
155
   DN to use when binding to the LDAP server.
117
156
 
125
164
 
126
165
   Password to use when binding the DN.
127
166
 
 
167
   Note: This variable existed until Drizzle 2011.11.29, in particular it was part
 
168
   of the Drizzle 7 stable release. For security reasons this variable has been 
 
169
   removed in Drizzle release 2011.12.30, a Drizzle 7.1 beta release. There was 
 
170
   no valid reason to expose your LDAP admin password to every Drizzle user. 
 
171
 
128
172
.. _auth_ldap_cache_timeout:
129
173
 
130
174
* ``auth_ldap_cache_timeout``
170
214
Examples
171
215
--------
172
216
 
173
 
Sorry, there are no examples for this plugin.
 
217
Setting up an LDAP directory
 
218
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
219
 
 
220
Using and configuring an LDAP server is outside the scope of this manual, but 
 
221
for the purpose of showing some examples we need an LDAP server to connect to.
 
222
Below are some minimal steps you need to do to have in place first.
 
223
 
 
224
The following example was tried on Ubuntu Linux, version 11.04 natty. Some
 
225
earlier versions of Ubuntu require more steps to configure your empty LDAP
 
226
directory, see `this Ubuntu tutorial for more detailed 
 
227
instructions <http://https://help.ubuntu.com/11.04/serverguide/C/openldap-server.html>`_
 
228
and similarly see tutorials for your own Linux distribution if those do not work
 
229
for you.
 
230
 
 
231
To install OpenLDAP:
 
232
 
 
233
.. code-block:: bash
 
234
   
 
235
   sudo apt-get install slapd ldap-utils
 
236
 
 
237
The installation asks you to provide an administrator password. In this example
 
238
we've used `secret`.
 
239
 
 
240
Copy the following text into a file backend.example.com.ldif [1]_:
 
241
 
 
242
.. code-block:: none
 
243
    
 
244
    # Load dynamic backend modules
 
245
    dn: cn=module,cn=config
 
246
    objectClass: olcModuleList
 
247
    cn: module
 
248
    olcModulepath: /usr/lib/ldap
 
249
    olcModuleload: back_hdb.la
 
250
 
 
251
    # Database settings
 
252
    dn: olcDatabase=hdb,cn=config
 
253
    objectClass: olcDatabaseConfig
 
254
    objectClass: olcHdbConfig
 
255
    olcDatabase: {1}hdb
 
256
    olcSuffix: dc=example,dc=com
 
257
    olcDbDirectory: /var/lib/ldap
 
258
    olcRootDN: cn=admin,dc=example,dc=com
 
259
    olcRootPW: secret
 
260
    olcDbConfig: set_cachesize 0 2097152 0
 
261
    olcDbConfig: set_lk_max_objects 1500
 
262
    olcDbConfig: set_lk_max_locks 1500
 
263
    olcDbConfig: set_lk_max_lockers 1500
 
264
    olcDbIndex: objectClass eq
 
265
    olcLastMod: TRUE
 
266
    olcDbCheckpoint: 512 30
 
267
    olcAccess: to attrs=userPassword by dn="cn=admin,dc=example,dc=com" write by anonymous auth by self write by * none
 
268
    olcAccess: to attrs=shadowLastChange by self write by * read
 
269
    olcAccess: to dn.base="" by * read
 
270
    olcAccess: to * by dn="cn=admin,dc=example,dc=com" write by * read
 
271
 
 
272
Copy the following text into a file frontend.example.com.ldif:
 
273
 
 
274
.. code-block:: none
 
275
    
 
276
    # Create top-level object in domain
 
277
    dn: dc=example,dc=com
 
278
    objectClass: top
 
279
    objectClass: dcObject
 
280
    objectclass: organization
 
281
    o: Example Organization
 
282
    dc: Example
 
283
    description: LDAP Example 
 
284
 
 
285
    # Admin user.                                                                                                                                                                       
 
286
    dn: cn=admin,dc=example,dc=com                                                                                                                                                      
 
287
    objectClass: simpleSecurityObject                                                                                                                                                   
 
288
    objectClass: organizationalRole                                                                                                                                                     
 
289
    cn: admin                                                                                                                                                                           
 
290
    description: LDAP administrator                                                                                                                                                     
 
291
    userPassword: secret
 
292
 
 
293
    dn: ou=people,dc=example,dc=com
 
294
    objectClass: organizationalUnit
 
295
    ou: people
 
296
 
 
297
    dn: ou=groups,dc=example,dc=com
 
298
    objectClass: organizationalUnit
 
299
    ou: groups
 
300
 
 
301
    dn: uid=john,ou=people,dc=example,dc=com
 
302
    objectClass: inetOrgPerson
 
303
    objectClass: posixAccount
 
304
    objectClass: shadowAccount
 
305
    uid: john
 
306
    sn: Doe
 
307
    givenName: John
 
308
    cn: John Doe
 
309
    displayName: John Doe
 
310
    uidNumber: 1000
 
311
    gidNumber: 10000
 
312
    userPassword: password
 
313
    gecos: John Doe
 
314
    loginShell: /bin/bash
 
315
    homeDirectory: /home/john
 
316
    shadowExpire: -1
 
317
    shadowFlag: 0
 
318
    shadowWarning: 7
 
319
    shadowMin: 8
 
320
    shadowMax: 999999
 
321
    shadowLastChange: 10877
 
322
    mail: john.doe@example.com
 
323
    postalCode: 31000
 
324
    l: Toulouse
 
325
    o: Example
 
326
    mobile: +33 (0)6 xx xx xx xx
 
327
    homePhone: +33 (0)5 xx xx xx xx
 
328
    title: System Administrator
 
329
    postalAddress: 
 
330
    initials: JD
 
331
 
 
332
    dn: cn=example,ou=groups,dc=example,dc=com
 
333
    objectClass: posixGroup
 
334
    cn: example
 
335
    gidNumber: 10000
 
336
 
 
337
Now we create our database and settings, along with the standard 
 
338
"inetOrgPerson" LDAP schema:
 
339
 
 
340
.. code-block:: none
 
341
    
 
342
    $ sudo ldapadd -Y EXTERNAL -H ldapi:/// -f backend.example.com.ldif
 
343
    SASL/EXTERNAL authentication started
 
344
    SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
 
345
    SASL SSF: 0
 
346
    adding new entry "cn=module,cn=config"
 
347
 
 
348
    adding new entry "olcDatabase=hdb,cn=config"
 
349
 
 
350
    $ sudo ldapadd -x -D cn=admin,dc=example,dc=com -W -f frontend.example.com.ldif
 
351
    Enter LDAP Password: secret
 
352
    adding new entry "dc=example,dc=com"
 
353
 
 
354
    adding new entry "cn=admin,dc=example,dc=com"
 
355
 
 
356
    adding new entry "ou=people,dc=example,dc=com"
 
357
 
 
358
    adding new entry "ou=groups,dc=example,dc=com"
 
359
 
 
360
    adding new entry "uid=john,ou=people,dc=example,dc=com"
 
361
 
 
362
    adding new entry "cn=example,ou=groups,dc=example,dc=com"
 
363
 
 
364
In the above we first created the database and defined a method to access it.
 
365
As you see, in the second ldapadd command we now need to provide the admin 
 
366
password `secret` to do further changes, and will need to use it in all further
 
367
commands too.
 
368
 
 
369
The second command creates a classic `inetOrgPerson` schema, with a user
 
370
"John Doe" (Common Name) who has a uid "john" and various other information
 
371
commonly part of a UNIX system account. In fact the LDAP object type is called
 
372
posixAccount! User john is part of the Organizational Unit "people" in the
 
373
domain example.com.
 
374
 
 
375
You can verify that everything is working so far by searching for John:
 
376
 
 
377
.. code-block:: none
 
378
    
 
379
    $ ldapsearch -xLLL -b "ou=people,dc=example,dc=com" uid=john
 
380
    dn: uid=john,ou=people,dc=example,dc=com
 
381
    objectClass: inetOrgPerson
 
382
    objectClass: posixAccount
 
383
    objectClass: shadowAccount
 
384
    uid: john
 
385
    sn: Doe
 
386
    givenName: John
 
387
    cn: John Doe
 
388
    displayName: John Doe
 
389
    uidNumber: 1000
 
390
    gidNumber: 10000
 
391
    gecos: John Doe
 
392
    loginShell: /bin/bash
 
393
    homeDirectory: /home/john
 
394
    shadowExpire: -1
 
395
    shadowFlag: 0
 
396
    shadowWarning: 7
 
397
    shadowMin: 8
 
398
    shadowMax: 999999
 
399
    shadowLastChange: 10877
 
400
    mail: john.doe@example.com
 
401
    postalCode: 31000
 
402
    l: Toulouse
 
403
    o: Example
 
404
    mobile: +33 (0)6 xx xx xx xx
 
405
    homePhone: +33 (0)5 xx xx xx xx
 
406
    title: System Administrator
 
407
    postalAddress:
 
408
    initials: JD
 
409
 
 
410
If you look closely you see that the userPassword field is not shown. Don't 
 
411
worry! It is stored in the directory, it is just not shown in search results for
 
412
security reasons.
 
413
 
 
414
.. _auth_ldap_examples_add_user:
 
415
 
 
416
Adding a Drizzle user to LDAP
 
417
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
418
 
 
419
You could just setup Drizzle to authenticate against standard LDAP accounts like
 
420
John Doe above. But the recommended way is to add a specific Drizzle schema.
 
421
You will find this in ``$DRIZZLE_ROOT/share/drizzle7/drizzle_openldap.ldif``.
 
422
You can add it to your LDAP schema like this:
 
423
 
 
424
.. code-block:: none
 
425
    
 
426
    $ sudo ldapadd -Y EXTERNAL -H ldapi:/// -f share/drizzle7/drizzle_openldap.ldif 
 
427
    SASL/EXTERNAL authentication started
 
428
    SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
 
429
    SASL SSF: 0
 
430
    adding new entry "cn=drizzle,cn=schema,cn=config"
 
431
 
 
432
Now we can add a Drizzle user to our directory. At this point we will need to 
 
433
store the users Drizzle password. Note that Drizzle, just like MySQL, will
 
434
prefer to store and use a doubly hashed version of the user password. Other 
 
435
Drizzle authentication plugins, like auth_schema, do the same. (But some plugins
 
436
do not and Drizzle can use either, since it supports two different 
 
437
authentication protocols for this purpose). 
 
438
 
 
439
Drizzle 7.1 ships with a nice utility to calculate those hashes called
 
440
``drizzle_password_hash``. You simply give it the password and it outputs
 
441
the doubly hashed string:
 
442
 
 
443
.. code-block:: none
 
444
    
 
445
    $ bin/drizzle_password_hash secret
 
446
    14E65567ABDB5135D0CFD9A70B3032C179A49EE7
 
447
 
 
448
We will use this utility when creating the LDAP entry for our Drizzle user.
 
449
 
 
450
Note that the above value is different from what the LDAP directory as the
 
451
userPassword entry. The Unix or Posix way to store passwords is to just hash
 
452
them once. You can have a look in your ``/etc/shadow`` file to see what they
 
453
look like. Anyway, for this reason our Drizzle schema that we just added has
 
454
an additional field ``drizzleUserPassword`` to store the Drizzle encoded form
 
455
of the same password. (Or the passwords can also be different, but we will
 
456
assume most people like to use the same password.)
 
457
 
 
458
Since Drizzle 7.1 there is also a nice helper script included to create the ldif
 
459
records you need to add new Drizzle users to your LDAP. Using this script is
 
460
of course voluntary and you can use any LDAP manager tool you want. But we will
 
461
use it for this tutorial.
 
462
 
 
463
Let's create the user hingo:
 
464
 
 
465
.. code-block:: none
 
466
    
 
467
    $ share/drizzle7/drizzle_create_ldap_user -p secret -b bin/drizzle_password_hash -u hingo -n 1 -l "ou=people,dc=example,dc=com" > hingo.example.com.ldif
 
468
    $ cat hingo.example.com.ldif 
 
469
    dn: uid=hingo,ou=people,dc=example,dc=com                                                                                                                                           
 
470
    objectclass: top                                                                                                                                                                    
 
471
    objectclass: posixAccount
 
472
    objectclass: account
 
473
    objectclass: drizzleUser
 
474
    drizzleUserMysqlPassword: 14E65567ABDB5135D0CFD9A70B3032C179A49EE7
 
475
    uidNumber: 500
 
476
    gidNumber: 500
 
477
    uid: hingo
 
478
    homeDirectory: /home/hingo
 
479
    loginshell: /sbin/nologin
 
480
    userPassword: secret
 
481
    cn: hingo
 
482
 
 
483
If you want, you could use this as a template to further edit the entry.
 
484
Drizzle will only care about the `drizzleUserMySQLPassword`, `uid` and sometimes
 
485
(at your option) the `userPassword`. So you can freely edit the rest of the 
 
486
entries to suit you. For instance if this user will also be a user on your Linux 
 
487
system, make sure to set the loginshell to ``/bin/bash`` and check the uid and
 
488
gid numbers. The ``cn`` field is often used to store the full name of the person,
 
489
like "Henrik Ingo". (But this is not used by Drizzle.)
 
490
 
 
491
We now add the above user to the directory:
 
492
 
 
493
.. code-block:: none
 
494
 
 
495
    $ sudo ldapadd -x -D cn=admin,dc=example,dc=com -W -f hingo.example.com.ldif 
 
496
    Enter LDAP Password: 
 
497
    adding new entry "uid=hingo,ou=people,dc=example,dc=com"
 
498
 
 
499
.. _auth_ldap_examples_start_server:
 
500
 
 
501
Starting Drizzle Server and binding to the LDAP server
 
502
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
503
 
 
504
It is now time to start the Drizzle server with the needed options so that we
 
505
can use the LDAP directory for authentication services:
 
506
 
 
507
.. code-block:: none
 
508
 
 
509
    $ sbin/drizzled --plugin-remove=auth_all 
 
510
                    --plugin-add=auth_ldap 
 
511
                    --auth-ldap.bind-password=secret 
 
512
                    --auth-ldap.bind-dn="cn=admin,dc=example,dc=com" 
 
513
                    --auth-ldap.base-dn="ou=people,dc=example,dc=com"
 
514
 
 
515
`(Give all options on one line.)`
 
516
 
 
517
``bind-password`` and ``bind-dn`` are used by drizzled to bind to the LDAP
 
518
server. ``base-dn`` is the DN where our Drizzle users are stored.
 
519
 
 
520
.. _auth_ldap_examples_connect:
 
521
 
 
522
Connecting to Drizzle with the client
 
523
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
524
 
 
525
We can now use a username and password from the LDAP directory when connecting 
 
526
to Drizzle:
 
527
 
 
528
.. code-block:: none
 
529
 
 
530
    $ bin/drizzle --user=hingo --password
 
531
    Enter password: 
 
532
    Welcome to the Drizzle client..  Commands end with ; or \g.
 
533
    Your Drizzle connection id is 2
 
534
    Connection protocol: mysql
 
535
    Server version: 2011.10.28.2459 Source distribution (drizzle-auth_ldap-fix-and-docs)
 
536
 
 
537
    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
 
538
 
 
539
    drizzle> 
 
540
 
 
541
.. _auth_ldap_examples_connect_clear_password:
 
542
 
 
543
Using the userPassword system password with Drizzle
 
544
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
545
 
 
546
It is also possible to use the password from the userPassword field when 
 
547
connecting with Drizzle. This could be beneficial or necessary to allow
 
548
all users who already exist in the directory, but didn't have a 
 
549
drizzleUserPassword set for them, to connect to Drizzle.
 
550
 
 
551
To do this, you have to give the extra option ``--protocol mysql-plugin-auth``
 
552
to the drizzle client. This will tell the drizzle client to send the password
 
553
in cleartext to the server, using the MySQL old-password protocol.
 
554
 
 
555
We could use this to connect to Drizzle with the username john, that
 
556
we added in the beginning of this tutorial.
 
557
 
 
558
.. code-block:: none
 
559
 
 
560
    $ drizzle --password --protocol mysql-plugin-auth --user=john
 
561
    Enter password: 
 
562
    Welcome to the Drizzle client..  Commands end with ; or \g.
 
563
    Your Drizzle connection id is 2
 
564
    Connection protocol: mysql-plugin-auth
 
565
    Server version: 2011.10.28.2459 Source distribution (drizzle-auth_ldap-fix-and-docs)
 
566
 
 
567
    Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
 
568
 
 
569
    drizzle> 
 
570
 
 
571
.. note::
 
572
 
 
573
   Using cleartext passwords is **not recommended**. Please note that
 
574
   the connection between drizzle client and drizzled server is completely
 
575
   unencrypted, so other people on your network could easily find out the
 
576
   password if this method is used.
 
577
 
 
578
 
 
579
.. _auth_ldap_limitations:
 
580
 
 
581
Limitations
 
582
-----------
 
583
 
 
584
The option ``LDAP_SCOPE_ONELEVEL`` option is used when searching the LDAP 
 
585
directory. This means you must specify the full base-dn. For instance, if
 
586
you have users defined in the dn ``ou=people,dn=example,dn=com`` authentication
 
587
will fail if you only specify ``dn=example,dn=com``. A consequence of this is
 
588
that all your Drizzle users must belong to the same LDAP organizationalUnit.
 
589
 
 
590
This is currently a fixed option and can only be changed by editing source code. 
 
591
However, there is no reason why it couldn't be a configurable option to also
 
592
allow multi level searches. Please contact the Drizzle developers if you have
 
593
such needs. (See :doc:`/help`)
 
594
 
174
595
 
175
596
.. _auth_ldap_authors:
176
597
 
177
598
Authors
178
599
-------
179
600
 
180
 
Eric Day
 
601
:Code: Eric Day, Edward "Koko" Konetzko, Henrik Ingo
 
602
:Documentation: Henrik Ingo
181
603
 
182
604
.. _auth_ldap_version:
183
605
 
184
606
Version
185
607
-------
186
608
 
187
 
This documentation applies to **auth_ldap 0.1**.
 
609
This documentation applies to **auth_ldap 0.2**.
188
610
 
189
611
To see which version of the plugin a Drizzle server is running, execute:
190
612
 
195
617
Changelog
196
618
---------
197
619
 
 
620
v0.2
 
621
^^^^
 
622
* Add proper documentation.
 
623
* Fix various bugs found while documenting, including:
 
624
* drizzle_create_ldap_user would append a counter at the end of each username, such as hingo0. Now it's just the username.
 
625
* LDAP directory is now searched for uid field, not cn.
 
626
* Change default value of --auth-ldap.mysql-password-attribute to drizzleMysqlUserPassword.
 
627
* --auth-ldap.bind-db was changed to --auth-ldap.bind-dn
 
628
* Variable auth_ldap_bind_password is no longer shown in SHOW VARIABLES.
 
629
 
 
630
 
198
631
v0.1
199
632
^^^^
200
633
* First release.
 
634
 
 
635
.. [1] Configuration scripts courtesy of `Ubuntu OpenLDAP server tutorial <https://help.ubuntu.com/11.04/serverguide/C/openldap-server.html>`_
 
 
b'\\ No newline at end of file'