Koha 3.0 LDAP Configuration

© Copyright 2007

Author: Joe Atzberger, LibLime License: Like Koha, this document is released under GPL v2.0. Warranty: Absolutely none.

Introduction

This document describes LDAP-based authentication and user records in Koha.

Prerequisites:

  • Install Net::LDAP module.
  • Get access to user accounts on working LDAP server.
  • Configure KOHA_CONF (as below), satifying all required fields.
  • Switch “on” LDAP w/ <useldapserver>.

Improvements in LDAP Authentication for Koha 3.0:

  • Supports anonymous bind or bind with (DN) account/password.
  • Configuration externalized to XML in KOHA_CONF.
  • Per field mapping in config with optional defaults.
  • Full featured LDIF and configuration examples with corresponding test script.

Configuration: KOHA_CONF and field mapping

There are two parts of the KOHA_CONF file (default location: /etc/koha.xml) relevant to LDAP authentication: the configuration stanza itself, and the “switch” line that enables or disables LDAP. The switch appears in the main <config> section, 0 for “off” and 1 for “on”, like this:

<useldapserver>1</useldapserver>

The configuration section (”<config>”) is where the customization occurs. An example:

 
<!-- LDAP SERVER (optional) -->
<ldapserver id="ldapserver"  listenref="ldapserver">
 <hostname>localhost</hostname>
 <base>dc=metavore,dc=com</base>
 <user>cn=Manager,dc=metavore,dc=com</user>             <!-- DN, if not anonymous -->
 <pass>metavore</pass>          <!-- password, if not anonymous -->
 <replicate>1</replicate>       <!-- add new users from LDAP to Koha database -->
 <update>1</update>             <!-- update existing users in Koha database -->
 <auth_by_bind>0</auth_by_bind> <!-- set to 1 to authenticate by binding instead of
                                     password comparison, e.g., to use Active Directory -->
 <mapping>             <!-- match koha SQL field names to your LDAP record field names -->
                <firstname    is="givenname"      ></firstname>
                <surname      is="sn"             ></surname>
                <address      is="postaladdress"  ></address>
                <city         is="l"              >Athens, OH</city>
                <zipcode      is="postalcode"     ></zipcode>
                <branchcode   is="branch"         >MAIN</branchcode>
                <userid       is="uid"            ></userid>
                <password     is="userpassword"   ></password>
                <email        is="mail"           ></email>
                <categorycode is="employeetype"   >PT</categorycode>
                <phone        is="telephonenumber"></phone>
 </mapping>
</ldapserver>

In particular, the <mapping> element deserves special attention. Its subelements establish the relationship between DB table fields and LDAP attributes. The element name is that of the column in the borrowers table, with the “is” characteristic set to the LDAP attribute name. Optionally, any content between the element tags is taken as the default value. In this example, the default categorycode is “PT” (for patron).

This example reflects user records being stored according to the inetOrgPerson schema, RFC#2798. Thus the username must match the “uid” field, and the password must match the “userpassword” field. Your organizational schema may differ in part, or in entirety.

Required Fields

Make sure that the required fields are populated in your LDAP database (and mapped in KOHA_CONF). What are the required fields? Well, in sql you can check the database table “borrowers” like this:

mysql> show COLUMNS from borrowers;
+------------------+--------------+------+-----+---------+----------------+
| Field            | Type         | Null | Key | Default | Extra          |
+------------------+--------------+------+-----+---------+----------------+
| borrowernumber   | int(11)      | NO   | PRI | NULL    | auto_increment |
| cardnumber       | varchar(16)  | YES  | UNI | NULL    |                |
| surname          | mediumtext   | NO   |     |         |                |
| firstname        | text         | YES  |     | NULL    |                |
| title            | mediumtext   | YES  |     | NULL    |                |
| othernames       | mediumtext   | YES  |     | NULL    |                |
| initials         | text         | YES  |     | NULL    |                |
| streetnumber     | varchar(10)  | YES  |     | NULL    |                |
| streettype       | varchar(50)  | YES  |     | NULL    |                |
| address          | mediumtext   | NO   |     |         |                |
| address2         | text         | YES  |     | NULL    |                |
| city             | mediumtext   | NO   |     |         |                |
| zipcode          | varchar(25)  | YES  |     | NULL    |                |
| email            | mediumtext   | YES  |     | NULL    |                |
| phone            | text         | YES  |     | NULL    |                |
| mobile           | varchar(50)  | YES  |     | NULL    |                |
| fax              | mediumtext   | YES  |     | NULL    |                |
| emailpro         | text         | YES  |     | NULL    |                |
| phonepro         | text         | YES  |     | NULL    |                |
| B_streetnumber   | varchar(10)  | YES  |     | NULL    |                |
| B_streettype     | varchar(50)  | YES  |     | NULL    |                |
| B_address        | varchar(100) | YES  |     | NULL    |                |
| B_city           | mediumtext   | YES  |     | NULL    |                |
| B_zipcode        | varchar(25)  | YES  |     | NULL    |                |
| B_email          | text         | YES  |     | NULL    |                |
| B_phone          | mediumtext   | YES  |     | NULL    |                |
| dateofbirth      | date         | YES  |     | NULL    |                |
| branchcode       | varchar(10)  | NO   | MUL |         |                |
| categorycode     | varchar(10)  | NO   | MUL |         |                |
| dateenrolled     | date         | YES  |     | NULL    |                |
| dateexpiry       | date         | YES  |     | NULL    |                |
| gonenoaddress    | tinyint(1)   | YES  |     | NULL    |                |
| lost             | tinyint(1)   | YES  |     | NULL    |                |
| debarred         | tinyint(1)   | YES  |     | NULL    |                |
| contactname      | mediumtext   | YES  |     | NULL    |                |
| contactfirstname | text         | YES  |     | NULL    |                |
| contacttitle     | text         | YES  |     | NULL    |                |
| guarantorid      | int(11)      | YES  |     | NULL    |                |
| borrowernotes    | mediumtext   | YES  |     | NULL    |                |
| relationship     | varchar(100) | YES  |     | NULL    |                |
| ethnicity        | varchar(50)  | YES  |     | NULL    |                |
| ethnotes         | varchar(255) | YES  |     | NULL    |                |
| sex              | varchar(1)   | YES  |     | NULL    |                |
| password         | varchar(30)  | YES  |     | NULL    |                |
| flags            | int(11)      | YES  |     | NULL    |                |
| userid           | varchar(30)  | YES  | MUL | NULL    |                |  # UNIQUE in next release.
| opacnote         | mediumtext   | YES  |     | NULL    |                |
| contactnote      | varchar(255) | YES  |     | NULL    |                |
| sort1            | varchar(80)  | YES  |     | NULL    |                |
| sort2            | varchar(80)  | YES  |     | NULL    |                |
+------------------+--------------+------+-----+---------+----------------+
50 rows in set (0.01 sec)

Where the Null column is set to “NO”, that field is required. Here, that would be:

  • borrowernumber
  • surname
  • address
  • city
  • branchcode
  • categorycode

Note that the primary key “borrowernumber” will auto_increment, so no mapping is required (and would likely cause error).

If you do not have a corresponding LDAP field, you may still account for a required field with a default value (and no “is” characteristic):

<categorycode>PT</categorycode>

Other Implementations, Other Features Other versions of Auth_with_ldap have been developed by members of the Koha community, most notably the original implementation by Paul Poulain. While that version is stable, it requires Auth.pm to be replaced with a hand edited version of Auth_with_ldap.pm. With Koha 3.0, the configurations are kept separate from the running code, and can thereby be preserved as updates are released. The code running on production servers will be common to all, and therefore more likely to be tested, patched, documented, etc.

A more recent alternative Auth_with_ldap version provides advanced mappings and composition of fields, controlled by storing the mappings themselves in a SQL table and performing evaluations based on them. If you require such functionality and your system can absorb the performance cost, you might consider that version. Integrating a similar functionality (in the XML model) will be considered if there is demand for it.

Bind-as-Auth vs. $ldap->compare()

Several members of the community have reported changing Auth_with_ldap to attempt a bind with each username and password, rather than retrieve the user account and compare passwords. On the one hand, this was a means for using LDAP when anonymous connections were disabled, since previously only anonymous connections were supported. Koha 3.0 removes that consideration by supporting both named and anonymous connections. On the other hand, there was also a contention was that with encrypted/hashed passwords, Koha could not reliably determine what hashing mechanism to employ for comparison. This concern is legitimate, but LDAP itself provides the solution via the “compare” function, optionally defined and inherited per field as part of a schema. (See ldapcompare(1).) Koha 3.0 accesses this functionality via the compare() method of the Net::LDAP object.

The bind-as-auth approach also has the following drawbacks:

 1. Bind by any user unsupported by many LDAP servers for security reasons.
 2. As implemented, does not distinguish between LDAP server being unavailable and auth rejection.
 3. Reduces potential performance benefits from cached/persistent LDAP connection(s) via daemon (e.g. mod_ldap).

In short, the compare() method seems to be the most appropriate approach, provided you have an admin user and password, which will reveal the userpassword to the ldap search (otherwise insufficient access error is reported). If anonymous bind is the only way to connect to the server, then use auth_by_bind = 1 option in the config file (as shown above). However the latter currently requires a patch to Bug 2726, at least as of the Koha 3.0.3 release.

Files

  • C4/Auth_with_LDAP.pm
  • t/Auth_with_LDAP.t
  • t/LDAP/example3.ldif
  • t/LDAP/test_ldap_add.pl

See Also

 
en/development/ldap.txt · Last modified: 2009/11/21 17:08 by pabloab
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki