LDAP
- LDAP is just a type of database specialized for look ups. Reads are fast while writes are supported but relatively slow. That's why LDAP is commonly used to store centralized user accounts.
- In LDAP, data is stored nodes (much like a record in a relational DB). Each node has some named attributes. For example, a node representing a user may have the following attributes (cn stands for "common name", while sn stands for "surname"):
cn: Kent Tong
sn: Tong
givenName: Kent
email: kent@ttdev.com
- Just like a record in a DB or an object in Java, the attributes that a node can have is fixed. This is specified by an attribute named objectClass. For example, there is an objectClass named "person" that says that it can have cn, sn and email, then a node belonging that this "person" class can have such attributes:
cn: Kent Tong
sn: Tong
email: kent@ttdev.com
objectClass: person
- It is possible for a node to belong to multiple object classes. For example, there may be an objectClass named "securityObject" that says that it can have a password attribute, then if you need to put a password into a node, you can do it like:
cn: Kent Tong
sn: Tong
email: kent@ttdev.com
objectClass: person
objectClass: securityObject
password: abc123
- How to use a node to present a department or a company? This is done with the "organizationalUnit" objectClass ("ou" stands for "organizational unit"):
ou: Foo Ltd.
objectClass: organizationalUnit
ou: Finance dept
objectClass: organizationalUnit
- If the person Kent Tong is in that Financial department, how to represent that relationship? Unlike a relative DB where such relationship is represented a foreign keys, in LDAP one node can be put under the other as a child node. For example, let's put the person node as a child node of the financial dept node which is put as a child node of the company node:
dn: ou=Foo Ltd.
ou: Foo Ltd.
objectClass: organizationalUnit
dn: ou=Finance dept,ou=Foo Ltd.
ou: Finance dept
objectClass: organizationalUnit
dn: cn=Kent Tong,ou=Finance dept,ou=Foo Ltd.
cn: Kent Tong
sn: Tong
email: kent@ttdev.com
objectClass: person
- This parent-child relation is represented by an attribute called "dn" (distinguished name, just like an full path to a file). That is, you can determine the dn of the parent node from the dn of the node.
- Usually you will add the cn to the dn of the parent to get the dn of the node itself. However, you don't have to use cn. You are free to any attribute to serve that purpose (called "relative dn") as long as it is unique among the siblings. For example, cn is good if there are no two people with the same cn values the dept. This is so that given a dn, it is very fast to locate the node.
- When you create the top node of the directory, you need to specify its dn. Usually, you will use the DNS domain name of your company (let's say it is foo.com):
dn: dc=foo,dc=com
ou: Foo Ltd.
objectClass: organizationalUnit
dn: ou=Finance dept,dc=foo,dc=com
ou: Finance dept
objectClass: organizationalUnit
dn: cn=Kent Tong,ou=Finance dept,dc=foo,dc=com
cn: Kent Tong
sn: Tong
email: kent@ttdev.com
objectClass: person
- in which dc means "domain component", just a label in a domain name.
- Some object classes such as person or organizationalUnit are designed to be used as the "main" object class for the nodes, while some other object classes such as securityObject (officially, it is called "simpleSecurityObject") are designed to be "auxiliary" and to be added to the nodes. The former is called a "structural object class" while the latter an "auxiliary object class".
- For each node, it must have exactly one structural object class. It can have zero or multiple auxiliary object classes.
Schema
- The attributes and object classes are defined instead of hard-coded. For OpenLDAP on Debian, you can find the schemas in /etc/ldap/schema. For example, you can find the following object class in core.schema:
objectclass ( 2.5.6.6 NAME 'person'
DESC 'RFC2256: a person'
SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
- It says that it must have the "sn" and "cn" attributes and may have a "userPassword" attribute and etc. It says that its super class is "top" which is a built-in object class representing the topmost level object class. It also says that the "person" object class is a structural class.
- You can find the most commonly used object classes and attributes here.
Authenticating with LDAP
- A straightforward way is to retrieve the node according to the username, get the password and compare it to the password the user entered.
- However, this allows retrieving sensitive information (password) of any user over the network by services. Therefore, there is another way: you send dn and the password to the LDAP service and let it perform the checking. This is called "binding" to that dn. Essentially you are logging in as a particular node.
- Both methods above will transfer the password in the clear. So, you should probably use TLS when accessing the LDAP service (using ldaps://)
- The above methods are most commonly used by other services such as mail, Samba or Apache for checking the passwords of the users.
- When performing administration with OpenLDAP, you may use the "bind" approach above to log in as the node representing the administrator. This is called "simple authentication":
# ldapsearch -x -W -D cn=admin,dc=foo,dc=com ...
- However, sometimes it is more convenient to authenticate not as a node in the directory but just as an administrator. For example, if your site is using Kerberos, you can perform single sign-on with OpenLDAP. This is done with its SASL support. SASL in turn supports many mechanisms such as PLAIN (plain text), GSSAPI (Kerberos), EXTERNAL (using the transport such as the client cert with TLS). When SASL to authenticate, OpenLDAP will make up a dn to represent your identity. For example, for user Kent in the Kerberos domain foo.com, the made-up dn will be uid=kent,cn=foo.com,cn=gssapi,cn=auth. This is needed for granting permissions.
Setting up and running OpenLDAP on Debian
- When setting up OpenLDAP on Debian, you need to reconfigure the package so that it creates the initial directory for you as well as the node representing the administrator:
# dpkg-reconfigure -p low openldap
- Then, to check if it is working, you can use SASL EXTERNAL mechanism and use Unix domain socket (ldapi:///) as root to connect to it:
# ldapsearch -b cn=config -H ldapi:/// -Y external
Query
- Just like a relation DB, you can perform queries to retrieve the nodes and their attributes. For example, you can try to find all nodes with cn=Kent Tong (the "filter") under the node whose dn is dc=foo,dc=com (the "base" of the search):
# ldapsearch -b dc=foo,dc=com -H ldapi:/// -Y external "cn=Kent Tong"
- You may try to find all nodes whose objectClass is "person" and whose cn contains the word "Kent":
# ldapsearch -b dc=foo,dc=com ... "(&(objectClass=person)(cn=*Kent*))"
- You may tell it to retrieve only a certain attributes:
# ldapsearch -b dc=foo,dc=com ... "(&(objectClass=person)(cn=*Kent*))" dn sn
Updating the data
- To add a new node, make sure the parent already exists, then specify the dn and other attributes in a text file (called an LDIF file) and mark it as an "add" request:
dn: cn=Paul Chan,ou=Finance dept,dc=foo,dc=com
changetype: add
cn: Paul Chan
sn: Chan
email: paul@ttdev.com
objectClass: person
- Then feed the LDIF file to ldapmodify:
# ldapmodify < myfile.ldif
- To modify (add, change or delete) the attributes of an existing node, specify the node first and then list each attribute change and separate them by a line containing a single hyphen. Finally, end the node with an empty line:
dn: cn=Kent Tong,ou=Finance dept,dc=foo,dc=com
changetype: modify
add: givenName
givenName: Kent
-
replace: email
email: kent@foo.com
-
delete: phoneNumber
dn: cn=Paul Chan,ou=Finance dept,dc=foo,dc=com
changetype: delete