Introduction
If you let an IT administrator pick a persistence storage technique, he would probably choose a LDAP directory. But if you asked a system developer, then he would probably choose a RDBMS (Relational Database Management System). Why is that? I would guess because of history.
So is the two different technique so much different? They both stores data. Right. But they also have some key differences.
- LDAP stores data in a tree (hierarchical database) and RDBMS stores data in tables with relationship between them via primary keys and foreign keys.
- LDAP uses path (Distinguished Name, DN) to make entries unique. RDBMS uses primary keys in tables.
- In a RDBMS you design your tables and columns. In LDAP you pick from predefined object class (RDBMS table), with predefined attributes (RDBMS column).
- In RDBMS you define the column data types, but in LDAP everything are strings.
So by that said lets start to discover LDAP, with OpenLDAP.
Installation
openldap A package containing the libraries necessary to run the OpenLDAP server and client applications.
openldap-clients A package containing the command-line utilities for viewing and modifying directories on an LDAP server.
openldap-servers A package containing both the services and utilities to configure and run an LDAP server. This includes the Standalone LDAP Daemon, slapd.
compat-openldap A package containing the OpenLDAP compatibility libraries.
Choosing a Suffix
The LDAP suffix is the global LDAP name space or the toop root of you LDAP tree.
There are two standard approaches:
- The X.500 naming model, which is geographically and organizationally based.
Example: o=Magnus K Karlsson,l=Stockholm,s=Stockholm,c=SE
- The Internet domain naming model, i.e. the organizations's DNS domain.
Example: dc=magnuskkarlsson,dc=com
Abbreviation:
dc, Domain Component
dn, Distinguished Name
cn, Common Name
sn, Surname (family name/last name)
uid, User ID
o, Organization
ou, Organization Unit
l, Location
s, State
c, Country
RDN, Relative Distinuished Name
OID, Object Identifier
DIT, Directory Information Tree
LDIF, LDAP Data Interchange Format
The preferred method is the organizations's DNS domain.
Password Storing Policy
Storing password securily is importand. The default way in OpenLDAP
is SSHA-1, in RHEL 6 it is SSHA-512 with 8-bit salt, see crypt(3).
NOTES
Glibc Notes
The glibc2 version of this function supports additional encryption
algorithms.
If salt is a character string starting with the characters "$id$"
followed by a string terminated by "$":
$id$salt$encrypted
then instead of using the DES machine, id identifies the encryption
method used and this then determines how the rest of the password string
is interpreted. The following values of id are supported:
ID | Method
---------------------------------------------------------
1 | MD5
2a | Blowfish (not in mainline glibc; added in some
| Linux distributions)
5 | SHA-256 (since glibc 2.7)
6 | SHA-512 (since glibc 2.7)
So $5$salt$encrypted is an SHA-256 encoded password and $6$salt$encrypted
is an SHA-512 encoded one.
"salt" stands for the up to 16 characters following "$id$" in the salt.
The encrypted part of the password string is the actual computed password.
The size of this string is fixed:
MD5 | 22 characters
SHA-256 | 43 characters
SHA-512 | 86 characters
The characters in "salt" and "encrypted" are drawn from the set
[a–zA–Z0–9./]. In the MD5 and SHA implementations the entire key is
significant (instead of only the first 8 bytes in DES).
The slappasswd tool can be given options to use crypt(3), see slappasswd(8).
-c crypt-salt-format
Specify the format of the salt passed to crypt(3) when generating
{CRYPT} passwords. This string needs to be in sprintf(3) format
and may include one (and only one) %s conversion. This conversion
will be substituted with a string of random characters from
[A-Za-z0-9./]. For example, ’%.2s’ provides a two character salt
and ’$1$%.8s’ tells some versions of crypt(3) to use an MD5
algorithm and provides 8 random characters of salt. The default is
’%s’, which provides 31 characters of salt.
The recommended way is to use the strongest option, i.e. SSHA-512 with 16 bit salt.
$ slappasswd -c '$6$%.16s'
New password:
Re-enter new password:
{CRYPT}$6$/rq5GLnmg5yVZ8XB$CKypmnBEwy1g09R/8k7w8ZCdyelz04DPagKwBS7MakGNqnKSOcftiqW48pg.LBdI0cxAT6yfb1C8sWeD/qeP01
Configuration
The configuration in newer OpenLDAP versions has been moved from a single
configuration file (/etc/openldap/slapd.conf) to a configuration directory
(/etc/openldap/slapd.d/), containing several configuration files.
For more novice users is the single configuration file more easier to understand
and easier to get an overview of all configuration. Here we will use the single
configuration file.
$ rm -rf /etc/openldap/slapd.d
$ cp /usr/share/openldap-servers/slapd.conf.obsolete /etc/openldap/slapd.conf
Now we are ready to configure LDAP suffix and username and password for LDAP root user.
$ vi /etc/openldap/slapd.conf
...
suffix "dc=magnuskkarlsson,dc=com"
rootdn "cn=admin,dc=magnuskkarlsson,dc=com"
rootpw "{CRYPT}$6$/rq5GLnmg5yVZ8XB$CKypmnBEwy1g09R/8k7w8ZCdyelz04DPagKwBS7MakGNqnKSOcftiqW48pg.LBdI0cxAT6yfb1C8sWeD/qeP01"
...
Start
$ service slapd start
Test
To test we can run a simple search.
$ ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
...
dn:
namingContexts: dc=magnuskkarlsson,dc=com
...
Another test can be to print all configuration.
$ ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config
...
olcRootDN: cn=admin,dc=magnuskkarlsson,dc=com
olcRootPW: {SSHA}nZElz+cA+HvrxmNVKn3tONJhRWphVLTN
...
GUI Administration Tools
Apache Directory Studio Eclipse-based LDAP tools
For Bug on RHEL 6 and CentOS 6:
See resolution https://issues.apache.org/jira/browse/DIRSTUDIO-999
Designing the Name Space
Designing your LDAP tree or Directory Information Tree (DIT) is an important thing.
Flat Name Space
Example:
uid=john,dc=magnuskkarlsson,dc=com
uid=jim,dc=magnuskkarlsson,dc=com
Advantages:
- Names do not need to change when job roles change or the organization changes.
- Simple design avoids need to object categoratization by directory administrators.
Disadvanteges:
- Hard to partition the directory later if needed.
- May be hard to maintain unique DNs.
Deeper Name Space
Example:
uid=peter,ou=Development,ou=People,l=Europe,dc=magnuskkarlsson,dc=com
uid=maria,ou=Sales,ou=People,l=Asia,dc=magnuskkarlsson,dc=com
Advantages:
- Easier to delegate control to organizational units.
- May simplify later partitioning of directory service among several servers.
Disadvanteges:
- Names to tend to change more often: job transfer, organizational changes, etc.
- May require more work to correctly categorize entries, keep up to date.
Compromise Name Space
Example:
ou=People,dc=magnuskkarlsson,dc=com
ou=Group,dc=magnuskkarlsson,dc=com
base.ldif
dn: dc=magnuskkarlsson,dc=com
dc: magnuskkarlsson
objectClass: domain
objectClass: top
dn: ou=People,dc=magnuskkarlsson,dc=com
ou: People
objectClass: organizationalUnit
objectClass: top
dn: ou=Group,dc=magnuskkarlsson,dc=com
ou: Group
objectClass: organizationalUnit
objectClass: top
OpenLDAP Tool
The openldap-clients packages installes a number of tools, the most common used are:
- ldapsearch, tool to search the directory.
- ldapadd and ldapmodify, tool that use LDIF (LDAP Data Interchange Format) files to update the directory.
- ldapdelete, tool to delete entry.
Common options for these tools are:
- -H host
- -x Use simple, not SASL binds (login method)
- -D dn Bind using dn (username)
- -W prompt for simple bind password
Example:
$ ldapadd -x -D "cn=admin,dc=magnuskkarlsson,dc=com" -W -f base.ldif
Common options for ldapsearch:
- -b dn Base DN in tree to start search from.
Example:
$ ldapsearch -x -b 'dc=magnuskkarlsson,dc=com' '(objectclass=*)'
User Class
User Structural Class
After we have designed and created our LDAP tree structure, it's time to create
the actual user entry. But before that we need to decide which base class we
want to use for our user entry.
Note that an entry must have one and only one structural object class. Each
object class have a defined set of attributes, some mandatory and other optional.
You can extend or add one or more addition auxiliary object classes.
The two most frequently used structural classes are:
- account Is useful if you are only using LDAP as a NIS (Network Information Service) replacement.
- inetOrgPerson Is best if you are also using LDAP to provide contact information.
User Auxiliary Classes
If you are planning to use the LDAP directory for RHEL authentication, you need
to add the following auxiliary classes.
posixAccount represents a line from /etc/passwd.
shadowAccount represents a line from /etc/shadow.
Group Structural Class
To complete a UNIX user/authentication you also needs groups.
posixGroup represents a line from /etc/group.
student.ldif
dn: uid=student,ou=People,dc=magnuskkarlsson,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
objectClass: top
cn: student
sn: student
uid: student
uidNumber: 500
gidNumber: 500
homeDirectory: /home/student
userPassword: {crypt}$6$TgMwYtfv6Z0C8Peo$H7p8XjUYuBIspHgTmbo2KKSusssqFuBJFi58uRIcFVsObQJr72RHmBEq9Qz8JcBuA0tCbKvmDawxbQzz112/y0
shadowLastChange: 16467
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
dn: cn=student,ou=Group,dc=magnuskkarlsson,dc=com
objectClass: top
objectClass: posixGroup
cn: student
userPassword: {crypt}x
gidNumber: 500
Access Control Instructions, ACI
Writing ACI is out of the scoop of this blog, so comment out every ACI in /etc/openldap/slapd.conf, which will give everyone read, but restricts updates to rootdn.
Installation Apache Web Server (httpd) and LDAP authentication
Lets test our new LDAP directory, by configure LDAP authentication against httpd manual pages.
$ sudo yum install httpd httpd-manual
The httpd ldap module is alreaddy by default installed.
$ grep authnz /etc/httpd/conf/httpd.conf
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
Lets configure httpd-manual authentication.
$ vi /etc/httpd/conf.d/manual.conf
<Directory "/var/www/manual">
AuthType Basic
AuthName "Restricted Resource"
AuthBasicProvider ldap
AuthLDAPURL "ldap://ldap.magnuskkarlsson.com:389/ou=People,dc=magnuskkarlsson,dc=com?uid"
Require valid-user
Order deny,allow
Deny from all
Allow from all
</Directory>
Restart httpd and test.
$ service httpd restart
RHEL 6 LDAP Authentication Migrations Tools
$ sudo yum install migrationtools
Create LDIF export of local user and its password.
$ /usr/share/migrationtools/migrate_passwd.pl /etc/passwd
Create LDIF export of local groups.
$ /usr/share/migrationtools/migrate_group.pl /etc/group
To export and import everything.
$ /usr/share/migrationtools/migrate_all_online.sh
Enter the X.500 naming context you wish to import into: [dc=padl,dc=com] dc=magnuskkarlsson,dc=com
Enter the hostname of your LDAP server [ldap]: ldap.magnuskkarlsson.com
Enter the manager DN: [cn=manager,dc=magnuskkarlsson,dc=com]: cn=admin,dc=magnuskkarlsson,dc=com
Enter the credentials to bind with:
Do you wish to generate a DUAConfigProfile [yes|no]? no
References
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Directory_Servers.html
https://help.ubuntu.com/lts/serverguide/openldap-server.html
http://wiki.openiam.com/pages/viewpage.action?pageId=7635198
LDAP Schemas
Default installed LDAP schemas.
$ cat /etc/openldap/slapd.conf
...
include /etc/openldap/schema/corba.schema
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/duaconf.schema
include /etc/openldap/schema/dyngroup.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/java.schema
include /etc/openldap/schema/misc.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/ppolicy.schema
include /etc/openldap/schema/collective.schema
...
/etc/openldap/schema/cosine.schema
objectclass ( 0.9.2342.19200300.100.4.5 NAME 'account'
SUP top STRUCTURAL
MUST userid
MAY ( description $ seeAlso $ localityName $
organizationName $ organizationalUnitName $ host )
)
/etc/openldap/schema/nis.schema
objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount'
DESC 'Abstraction of an account with POSIX attributes'
SUP top AUXILIARY
MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
MAY ( userPassword $ loginShell $ gecos $ description ) )
objectclass ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount'
DESC 'Additional attributes for shadow passwords'
SUP top AUXILIARY
MUST uid
MAY ( userPassword $ shadowLastChange $ shadowMin $
shadowMax $ shadowWarning $ shadowInactive $
shadowExpire $ shadowFlag $ description ) )
objectclass ( 1.3.6.1.1.1.2.2 NAME 'posixGroup'
DESC 'Abstraction of a group of accounts'
SUP top STRUCTURAL
MUST ( cn $ gidNumber )
MAY ( userPassword $ memberUid $ description ) )
/etc/openldap/schema/core.schema
objectclass ( 2.5.6.6 NAME 'person'
DESC 'RFC2256: a person'
SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
objectclass ( 2.5.6.7 NAME 'organizationalPerson'
DESC 'RFC2256: an organizational person'
SUP person STRUCTURAL
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
/etc/openldap/schema/inetorgperson.schema
objectclass ( 2.16.840.1.113730.3.2.2
NAME 'inetOrgPerson'
DESC 'RFC2798: Internet Organizational Person'
SUP organizationalPerson
STRUCTURAL
MAY (
audio $ businessCategory $ carLicense $ departmentNumber $
displayName $ employeeNumber $ employeeType $ givenName $
homePhone $ homePostalAddress $ initials $ jpegPhoto $
labeledURI $ mail $ manager $ mobile $ o $ pager $
photo $ roomNumber $ secretary $ uid $ userCertificate $
x500uniqueIdentifier $ preferredLanguage $
userSMIMECertificate $ userPKCS12 )
)