ldap cheatsheet

Home

1 Install (OpenLDAP's daemon is slapd)

On CentOS:

1.1 slapd commands:

  • slapacl: Checks the access to a list of attributes
  • slapadd: Adds entries from an LDIF file to an LDAP directory
  • slapauth: Checks a list of IDs for authentication and authorization permissions
  • slapcat: Generates LDIF output from an LDAP directory
  • slapdn: Checks a list of distinguished names (DNs) based on schema syntax
  • slapindex: Re-indexes the directory. Run slapindex whenever indexing options are changed in the configuration file.
  • slappasswd: Is a password utility for creating an encrypted user password
  • slapschema: Checks compliance of a database with the corresponding schema
  • slaptest: Checks the LDAP server configuration

2 OpenLDAP Command Cheats

  • slapcat : concatenate ldap directory in ldif format works great with grep. i.e:
  • slapcat | grep -i group
  • slapcat | grep -i people
  • slapcat | grep -i passwd
  • slapcat | grep -i shadow
  • slapcat | grep -i uid
  • slapcat | grep -i dn
  • slapadd : add a user (in batch)
  • ldapadd : add a user one at a time
  • ldappasswd : change a user's password
  • ldapsearch : search the ldap database
  • ldapsearch john
  • ldapsearch ldaproot
  • ldapwhoami ldaproot

3 Background on LDAP

o LDAP = Lightweight Directory Access Protocol,

LDAPV2 defined in RFC1777 (1995)

LDAPv3 defined in RFC2251 (1997)

LDAPv3 defined in RFC4510 (2006)

A protocol for accessing data from X.500 directory services like:

  • OpenLDAP
  • Microsoft Active Directory, AD
  • Netscape Directory Server
  • Novell eDirectory

What directory?

  • any database that is in a standard format, that stores attribute based data, and that is optimized for read access.
  • examples are a telephone directory offers up name, address, number. a corporate email directory a username / password directory

What format?

Similar to X.500 format, but a simpler subset of X.500, X.500 stores descriptive key: value pairs, a.k.a. attribute: value pairs in a hierarchical tree-like data structure, called the Directory Information Tree (DIT).

3.1 Lightweight DAP

LDAP is an simpler alternative to the X.500 Directory Access Protocol (DAP) but it is still a hierarchical DIT

3.2 Database

A directory database is typically fairly static with reads far outstripping writes. As such they typically have:

  • no transactions
  • no rollback
  • updates are all or nothing, or possibly not allowed at all.
  • tuned for read performance, i.e. high-volume read

Implementations can use various databases. The DIT could be local to an organization, or global. A directory defines a uniform namespace, i.e. the same view is presented regardless of where queried, even in global directories.

Examples of global directory service is the Open Directory Project, dmoz.org This link will not respond to a typicall http request, but a ldap request.

Could be a relational database system, rdbs, or could be LDBS (built-in to OpenLDAP, a.k.a. slapd)

3.3 What is stored in this customized database called a "Directory"?

Typically organization and user authentication and authorization data. i.e. user rights data.

4 LDAP the protocol

LDAP is a client-server protocol.

It uses TCP, (or other connection oriented transport)

Can use UDP as well

TCP port 389 un-encrypted

TCP port 636 over SSL

TCP port 389 over negotiated TLS (tunnelled)

5 Typical terminology

LDAP : Lightweight Directory Access Protocol

DN : Distinguish Name

RDN : Relative Distinuished Name

DIT : Directory Information Tree

LDIF : LDAP Data Interchange Format

OID : Object Identifier

SASL : S authentication S L ?

DSA : Directory System Agents (X.500 servers)

5.1 Typical keys

These are the typical keys in a DIT, typically from the top down.

dc = domain component

cn = common name

ou = organizational unit

mail = email address

sn = surname

5.2 Suffix

A suffix is a branch or subtree whose entire contents are treated as a unit for admin purposes. Allows for splitting up the dit across multiple servers.

The top level tree root is called the root suffix

6 LDAP Resources

Five main online resources for LDAP are:

  1. ldap.com
  2. ldapwiki.com
  3. openldap.org
  4. itzgeek (from lab7 installation notes)
  5. openldap admin guide

7 Directory Structure (DIT)

7.1 DIT (Directory Information Tree)

  • A single tree, with a single root.
  • Hierarchical
  • distributed across 1 or more servers
  • Entries consist of a set of attributes
    • each attribute has one or more values
  • Each entry has a unique DN. ( Distinguished Name )
  • Each unique DN is formed by combining its RDN, one or more attributes of the entry itself, and the RDN of each of the superior entries up to the root of the DIT. An analogy: if named.conf is the RDN, then /etc/named.conf is DN

A DN may change over the lifetime of the entry, for instance when entries are moved within a tree, from one department to another.

Below is an excerpt of a entry, when represented in the LDIF format (LDAP Data Interchange Format, LDIF):

dn: cn=John Doe,dc=zintis,dc=ops
cn: John Doe
givenName: John

sn: Doe
telephoneNumber: +1 888 555 6789
telephoneNumber: +1 888 555 1232
mail: john@example.com
manager: cn=Barbara Doe,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top

dn is the distinguished name, i.e. cn=John Doe,dc=zintis,dc=ops

rdn is John doe, the relative distinguished name

"dn" is neither an attribute nor a part of the entry.

7.1.1 tree structure always on display

Every dn is also uniquely identified in the tree structure by the order you specify the dn. You trace from the dn, back up through the tree struture to the "top" which is the root of the tree. Rememeber that it is an upside-down tree.

7.2 Object Classes

I could try using, or adding, an attribute to an entry. Let's say people that are registered to attend a conference will each get a polo shirt. I could try to add and attribute: ShirtSize: XL

But ldap would complain about that being an Object class violation". Therefore I must first define that attribute somewhere. The place where all attributes are defined, and the rules for attribute types are defined, is called a schema.

7.3 Schema

The set of rules that define the available attributes that you can use. Schemas have certain pre-defined standard attributes,

ou: organizational unit

cn: …

And user defined attributes

ShirtSize:

These attributes are defined under a set of object classes. Put another way, Attributes of the directory server are defined under object classes

Therefore, if you want to use an attribute that is defined in the directory server, you must also specify the object class of the attribute.

Have to mention which object class defines an attribute along with the attribute.

For example: The ojbect class that defines the attribute "ou" is "organizational unit:" would look like this:

dn: ou=engineering,dc=zintis,dc=ops
objectClass: organizationalunit
ou: engineering

You could not just do this. It would give you an error:

dn: ou=engineering,dc=zintis,dc=ops
ou: engineering

7.4 Attributes:

ou is an attribute of the domain, "dc=zintis,dc=ops" To see all attributes, you could run slapcat (but that also dumps all entries which is obviously overkill unless your directory is very small. Better to look at the schema. Can think of the schema as a template too.

7.5 path to schema

/etc/openldap/schema

The file core.schema is included in the slapd.conf file. Every attriute that I define for the entries in my ldap server must match something in this core.schema file. You can add other, additional schemas but they must be mentioned in the slapd.conf file.

Opening up /etc/openldap/schema/core.schema you can see the definitions of the objectClasses. For instance, searching for organizationalUnit will show you this:

objectclass ( 2.5.6.5 NAME 'organizationalUnit'
     DESC 'RFC2256: an organizational unit'
     SUP top STRUCTURAL
     MUST ou
     MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $
             x121Address $ registeredAddress $ destinationIndicator $
             preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
             telephoneNumber $ internationaliSDNNumber $
             facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
             postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )

That shows us that ou is a MUST have. If you are going to use this object class, you must have at least the ou attribute specified.

If you are going to use this object class, you also have the optional "MAY" attributes, ilke address, telephone number, etc..

7.6 Subtrees (a.k.a. subsuffix)

(not covered in OPS335) A server holds a subtree starting from a specific entry, eg. dc=zintis,dc=ops and its children

Servers may hold reference to other servers, so an attempt to access ou=department,dc=zintis,dc=ops could return a referral or continution reference to a server that holds that part of the tree.

Recursive lookups are called "chaining" were the server does the lookup of the related server, on behalf of the client. usually the server just returns the address of the other server to the client and it is up to the client to query the next server.

8 LDIF

LDAP Data Interchange Format

LDIF:

  • represents LDAP enteries in text, human readable format
  • allows easy modification of data

8.1 LDIF struture

It is a key-value database, implementing an upside down tree. i.e. root at the top.

Keys start the line followed by a colon space, then the value.

key: value

key: value

one key: value per line.

key: value (you need the <space> after the colon.)

  1. Multiple lines can be used to provide long values for attribute by beginning

    the extra lines with a single space. LDAP will join these when processing the entry.

  2. Sequencing of items in LDIF

    The order the items appear in your LDIF file must be laid out following the DIT structure, i.e. top down.

  3. Items separated by a blank line

    Entries in the DT can have multiple key: value attributes. They are each separated by a blank line.

  4. List child items after their parent items

    otherwise it does not make sense as where would the child go?

  5. Attributes or object classes must exist in the schema

    Before adding a key: value pair that key must be defined in the schema which also defines the type of value, and ranges the value can have.

  6. DN (Distinguished name comes first)

    For each item in the LDIF file, the first line must be the DN. The DN uniquely identifies a directory object within the directory object's tree. The DN mu st contain the common name (CN) of the directory object.

8.2 LDIF as input to commands

LDIF is used to represent ldap data, but also and interestingly LDIF is used as input by LDAP commands to allow adds and edits of LDAP directory data.

So your interaction with an LDAP directory DIT is going to be via LDIF files.

LDIF can describe any entry within an LDAP system, as well as any changes or modifications to the system. i.e. DIT. Changes to the LDAP DIT are simply written within .ldif files with arbitrary names, and then "applied" to the ldap dit with one of several management commands that read data from this file

  • ldbmcat converts ldbm database to ldif
  • ldif2ldbm coverts ldif back to ldbm database

9 OpenLDAP Components

OpenLDAP has three components

  1. slapd - the LDAP daemon
  2. libraries implementing the LDAP protocol
  3. OpenLDAP client software

10 OpenLDAP client

OpenLDAP provides not only a server, but also a client, openldap-clients This package includes the following command line utilities

  • ldapadd: Adds entries to an LDAP directory either from a file or from standard input.
  • ldapmodify: Modifies entries in an LDAP directory [ ldapmodify -a is identical to ldapadd. ]
  • ldapcompare: Compares a given attribute with an LDAP directory entry
  • ldapdelete: Deletes entries from an LDAP directory
  • ldapexop: Performs extended LDAP operations
  • ldapmodrdn: Modifies the RDN value of an LDAP directory entry
  • ldappasswd: Is a password utility for an LDAP user
  • ldapsearch: Is an LDAP directory search tool
  • ldapurl: Is an LDAP URL formatting tool
  • ldapwhoami: Performs a whoami operation on an LDAP server

There are also several GUI LDAP clients. Use at your own risk.

10.1 slapadd vs ldapadd

slapadd adds users in bulk. Your slapd(8) should not be running when you do this to ensure consistency of the database. Also slapadd may not provide naming or schema checks.

Therefore, it is advisable to use ldapadd when adding new entries into an existing directory.

  1. ldapadd

    ldapadd adds users to an LDAP directory one at a time, with full control over options. ldapadd uses input either from a file or from standard input.

    • ldapmodify: Modifies entries in an LDAP directory [ ldapmodify -a is identical to ldapadd. ]
  2. slapadd

    usr/sbin/slapadd [-b suffix] [-c] [-d debug-level] [-f slapd.conf] [-F confdir] [-g] [-j lineno] [-l ldif-file] [-n dbnum] [-o option[=value]] [-q] [-s] [-S SID] [-u] [-v] [-w]

    Slapadd is used to add entries specified in LDAP Directory Interchange Format (LDIF) to a slapd(8) database. It opens the given database determined by the database number or suffix and adds entries corresponding to the provided LDIF to the database. Databases configured as subordinate of this one are also updated, unless -g is specified. The LDIF input is read from standard input or the specified file.

    All files eventually created by slapadd will belong to the identity slapadd is run as, so make sure you either run slapadd with the same identity slapd(8) will be run as (see option -u in slapd(8)), or change file ownership before running slapd(8).

11 OpenLDAP Operations

11.1 Credentials

  1. ldapadd -v -f jane.ldif -D cn="ldaproot,dc=andrew,dc=ops" -W
  2. ldapadd -v -f jane.ldif -D -x cn="ldaproot,dc=andrew,dc=ops" -W

    Credentials are always needed, so you will always see -D and -w or -W in every Openldap command.

    -D bind a.k.a. authentication user and tree root (top level) the credentials are for a specific user in the DIT, with a distinguished name (dn) at the top of the domain.

    -w password will use simple authentication and need the password (seneca99ldap)

    -W prompt for password

    -x use simple authentication instead of SASL

    -f apply the ldif entries from a file (jane.ldif in this case)

    -v verbose

11.2 Generating an ldif file from user entry in /etc/passwd

To add a use to an ldap directory, you want that user to have the same password as the Linux password. OpenLDAP comes with tools for doing this, called "migratepasswd.pl" (in the /usr/share/migrationtools directory)

First, pull out the line from /etc/passwd for the user in question.

grep -w zintis /etc/passwd > /root/zintispasswd.entry

Then use the migration tool to genearte that user's ldif file.

cd /usr/share/migrationtools
migrate_passwd.pl /root/zintispasswd.entry /root/zintisldap.ldif

less /root/zintisldap.ldif
  1. From my history:

    man ldappasswd grep -w zintis /etc/passwd > /root/ldapusers.entry cat /root/ldapusers.entry /usr/share/migrationtools/migratepasswd.pl /root/ldapusers.entry /root/ldapusers.ldif cat /root/ldapusers.ldif

11.3 ldapadd

  • ldapadd: Adds entries to an LDAP directory either from a file or from standard input.
  • ldapmodify: Modifies entries in an LDAP directory [ ldapmodify -a is identical to ldapadd. ]
  • ldapadd is a symbolic link to ldapmodify -a, and it is used to read a user's ldif file and create an entry in the LDAP DIT for that user.
    ldapadd -x -v -D cn="ldaproot,dc=andrew,dc=ops" -W -f zintisldap.ldif=
    

    Credentials are always needed, so you will always see -D and -w or -W in every Openldap command.

    -D bind a.k.a. authentication user and tree root (top level) the credentials are for a specific user in the DIT, with a distinguished name (dn) at the top of the domain.

    -w password will use simple authentication and need the password (seneca99ldap)

    -W prompt for password

    -x Use simple authentication instead of SASL

    -f the file that as the user info in the LDIF format.

  • the distinguished name, dn, of the ldap administrator is dn: cn=ldaproot,dc=andrew,dc=ops
ldapadd -x -W -D "cn=ldaproot,dc=andrew,dc=ops" -f usertoadd.ldif

The order of options does not matter, except that file has to follow -f and the dn has to follow -D.

11.3.1 Listing Entries to Add to the DIT

The most basic method of defining new entries to add to LDAP is to simply list the entries in their entirety, exactly as they would typically displayed using LDAP tools. This starts with the DN (distinguished name) where the entry will be created, after the dn: indicator:

dn: ou=newgroup,dc=example,dc=com

In the line above, we reference a few key-value pairs in order to construct the DN for our new entry.

  1. : <space> for attribute values

    When setting attribute values, you must use the colon and space.

  2. = when referencing attributes/values

    When referencing attributes/values, an equal sign should be used instead.

    In the simplest LDIF format for adding entries to a DIT, the rest of the entry is simply written out using this format beneath the DN definition. The necessary objectClass declarations and attributes must be set to construct a valid entry. For example, to create an organizational unit to contain the entries for the employees of our organization, we could use this

    dn: ou=People,dc=example,dc=com   "dc ~ domain component"
    objectClass: organizationalUnit
    ou: People
    

    You can add multiple entries in a single file. Each entry must be separated by at least one completely blank line:

    dn: ou=People,dc=example,dc=com
    objectClass: organizationalUnit
    ou: People
    

    As you can see, this LDIF format mirrors almost exactly the format you would see when querying an LDAP tree for entries with this information. You can pretty much just write what you’d like the entry to contain verbatim.

11.4 Changetype: add"

Now if you are making several modifications within the same LDIF file, or even some mods as well as additions, OpenLDAP offers "Changetype: Add"

So, we could be modifying several entries, and adding a new entry. It looks much like above where we were just adding new entries, but we just add the line changetype: add directly below the dn: specification.

Let's say your directory information tree, DIT, already has ou=People,dc=worldtour2020,dc=com Then adding like this:

dn: uid=roadie22,ou=People,dc=worldtour2020,dc=com
changetype: add
objectClass: inetOrgPerson
description: Roadie Dude.  Roadie is a contracted roadie for
our North America leg of this world tour.
cn: Roadie-No.22
sn: Smith
uid: roadie22

11.5 BIND (AUTHENTICATE)

Most every authentication looks the same:

-D "cn=ldaproot,dc=andrew,dc=ops" -W
-D "cn=admin,dc=acme,dc=com" -W
-D "cn=netops,dc=cisco,dc=com" -W

This first one is the bind of the user ldaproot in the andrew.ops tree with a prompted password (-W)

The "D" refers to a Bind "dn". The distinguised name that is used to bind you to the directory.

11.6 DELETE

To delete an entry from an DIT, the process only needs the unique dn. So it is fairly easy. For instance, if we wanted to remove the ou=othergroup entry from our DIT, our LDIF file, rm-group.ldif, would only need to contain:

dn: ou=othergroup,dc=example,dc=com
changetype: delete

To actually do the deletion:

ldapmodify -x -D "cn=admin,dc=example,dc=com" -W -f rm-group.ldif

11.7 ldapmodify

If you specify changetype and ommit the -a flag, then it is a true modifiy type. So if we make changes to certain fields in the .ldif file for a user, we can apply those changes in the DIT database with:

ldapmodify -x -D "cn=ldaproot,dc=andrew,dc=ops" -W -f modifyfile.ldif

-D …. -W are credentials -x use simple authentication vs SASL -f ldif file that has entries such as this:

dn: entryDN
changetype: modify
add: attribute 
attribute: value...
-
replace: attribute 
attribute: newValue...
-
delete: attribute 
[attribute: value]
...

11.7.1 Example from ops

root@vm4~[835]$  # Pre change 
ldapsearch -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap -b dc=andrew,dc=ops uid=john

# extended LDIF
#
# LDAPv3
# base <dc=andrew,dc=ops> with scope subtree
# filter: uid=john
# requesting: ALL
#

# john, People, andrew.ops
dn: uid=john,ou=People,dc=andrew,dc=ops
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
cn: john
uid: john
uidNumber: 9999
gidNumber: 100
homeDirectory: /home/john
loginShell: /bin/bash
gecos: John Someone
shadowLastChange: 17058
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
userPassword:: e1NTSEF9TDkvTEUzM2tHY3h4L1FxSUZWMm0waENqeGplYURKQ04=
-------------------------------------------------------------------

root@vm4~[841]$  cat changejohn.ldif

cat changejohn.ldif 
dn: uid=john,ou=People,dc=andrew,dc=ops
changetype: modify
replace: cn
cn: John Baldry
-------------------------------------------------------------------

root@vm4~[842]$ 
ldapmodify -x -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap  -f changejohn.ldif
modifying entry "uid=john,ou=People,dc=andrew,dc=ops"
-------------------------------------------------------------------

root@vm4~[843]$ 
ldapsearch -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap -b dc=andrew,dc=ops uid=john
# extended LDIF
#
# LDAPv3
# base <dc=andrew,dc=ops> with scope subtree
# filter: uid=john
# requesting: ALL
#

# john, People, andrew.ops
dn: uid=john,ou=People,dc=andrew,dc=ops
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
uid: john
uidNumber: 9999
gidNumber: 100
homeDirectory: /home/john
loginShell: /bin/bash
gecos: John Someone
shadowLastChange: 17058
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
userPassword:: e1NTSEF9TDkvTEUzM2tHY3h4L1FxSUZWMm0waENqeGplYURKQ04=
cn: John Baldry

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
-------------------------------------------------------------------


root@vm4~[844]$ 
cat changejohn.ldif
dn: uid=john,ou=People,dc=andrew,dc=ops
changetype: modify
replace: cn
cn: John Baldry
root@vm4~[845]$ 
vi changejohn.ldif
root@vm4~[846]$ 
!c
cat changejohn.ldif
dn: uid=john,ou=People,dc=andrew,dc=ops
changetype: modify
replace: gecos
gecos: John Long Baldry
-------------------------------------------------------------------



root@vm4~[847]$ 
ldapmodify -x -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap  -f changejohn.ldif
modifying entry "uid=john,ou=People,dc=andrew,dc=ops"

root@vm4~[848]$ 
ldapsearch -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap -b dc=andrew,dc=ops uid=john
# extended LDIF
#
# LDAPv3
# base <dc=andrew,dc=ops> with scope subtree
# filter: uid=john
# requesting: ALL
#

# john, People, andrew.ops
dn: uid=john,ou=People,dc=andrew,dc=ops
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
uid: john
uidNumber: 9999
gidNumber: 100
homeDirectory: /home/john
loginShell: /bin/bash
shadowLastChange: 17058
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
userPassword:: e1NTSEF9TDkvTEUzM2tHY3h4L1FxSUZWMm0waENqeGplYURKQ04=
cn: John Baldry
gecos: John Long Baldry

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
-------------------------------------------------------------------


root@vm4~[849]$ 
cat changejohn.ldif
dn: uid=john,ou=People,dc=andrew,dc=ops
changetype: modify
replace: gecos
gecos: John Long Baldry
-------------------------------------------------------------------


root@vm4~[850]$ 

11.8 history commands using ldapmodify from lab 7 OPS335

Can use the same ldif file repeatedly, just be editing it and re-applying the new edits with the ldapmodify command. So for example, you can have an editing window open to changejohn.ldif then writing every change, one at a time with each change applied from another windowo that has the following two commands, repeated over and over, until the changes are done.

ldapmodify -x -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap
           -f changejohn.ldif
ldapsearch -x -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap
           -b dc=andrew,dc=ops uid=john

Similarily for another user, say, "jane"

ldapmodify -x -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap  
           -f changejane.ldif
ldapsearch -x -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap
           -b dc=andrew,dc=ops uid=jane

ldapmodify -x -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap -f changejane.ldif

11.9 Default host and port

These two are the same, while local host and port 389 are the defaults. ldapsearch -h localhost -p 389 -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap -b dc=andrew,dc=ops uid=john ldapsearch -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap -b dc=andrew,dc=ops uid=john

11.10 Sample change ldif files:

  1. replace and existing attribute:

    dn: uid=john,ou=People,dc=andrew,dc=ops changetype: modify replace: gecos gecos: John Long Baldry

  2. Add a new attribute:

    dn: uid=john,ou=People,dc=andrew,dc=ops changetype: modify add: roomNumber roomNumber: 1729

  3. Delete an attribute

    dn: uid=john,ou=People,dc=andrew,dc=ops delete: title title: Grand Poobah

add: jpegPhoto jpegPhoto:< modme.jpeg

delete: description

  1. ldapmodify example changing a password

    So if you are changing a password for user John, AND you have already chnaged the password entry in the file john.ldif, you could use the command:

    ldapmodify -x -D "cn=ldaproot,dc=andrew,dc=ops" -W -H ldap:// -f john.ldif
    

    The man page on ldapmodify provides a good examples, duplicated here:

               Assuming that the file /tmp/entrymods exists and has the contents:
    
               dn: cn=Modify Me,dc=example,dc=com
               changetype: modify
               replace: mail
               mail: modme@example.com
               -
               add: title
               title: Grand Poobah
               -
               add: jpegPhoto
               jpegPhoto:< file:///tmp/modme.jpeg
               -
               delete: description
               -
    
           the command:
    
               ldapmodify -f /tmp/entrymods
    
           will replace the contents of the "Modify Me" entry's mail attribute with
           the value "modme@example.com", add a title of  "Grand  Poobah",  and
           the contents of the file "/tmp/modme.jpeg" as a jpegPhoto, and completely
           remove the description attribute.
    :
           Assuming that the file /tmp/newentry exists and has the contents:
    
               dn: cn=Barbara Jensen,dc=example,dc=com
               objectClass: person
               cn: Barbara Jensen
               cn: Babs Jensen
               sn: Jensen
               title: the world's most famous mythical manager
               mail: bjensen@example.com
               uid: bjensen
    
           the command:
    
               ldapadd -f /tmp/newentry
    
           will add a new entry for Babs Jensen, using the values from the
           file /tmp/newentry.
    
           Assuming that the file /tmp/entrymods exists and has the contents:
    
               dn: cn=Barbara Jensen,dc=example,dc=com
               changetype: delete
    
           the command:
    
               ldapmodify -f /tmp/entrymods
    
           will remove Babs Jensen's entry.
    
    

11.11 ldappasswd

ldappasswd -s password123 -W -D "cn=ldaproot,dc=andrew,dc=ops"
           -x "uid=john,ou=people,dc=andrew,dc=ops"

-x username for which the password is changed -s specify the password for the username -D Distinguished name to bind (authenticate) to the LDAP server

11.12 ldapsearch

ldapsearch -x -h localhost -p 389 -D cn="Manager,dc=acme,dc=com" -W
            -b dc=acme,dc=com objectClass=*

-h the host where you want to search (the defaul is localhost)

-p the port 389[default] over ldap, 636 over SSL-ldap, 389 over TLS

-D is the "binding" or authentication to the server. so specify the user, and its hierarchy? This is referred to as the "bind dn" is that what cn="…." is?

-W is not a password, but asking to be prompted for a password

-b is the search base dn." It is the place where you wish to start the search. If you are using an ldif file that has the base distinguished name clearly indluded as part of the add/modify, you won't need to specify -b.

finally "objectClass=*" is the filter you want to search for.

11.12.1 Searching with objectClass = *

This is a convenient way of listing everything in an ldap database as everything in an ldap directory has an objectClass attribute, so making that * will match everything.

ldapsearch -D cn="Manager,dc=acme,dc=com" -b dc=acme,dc=com objectclass=*

11.12.2 ldapsearch anonymously.

Typically some organizations require you to have a proper login, but some organizations allow anonymous searches. Depends on the company and what is being searched.

ldapsearch -h localhost -p 389 -D cn="ldaproot,dc=andrew,dc=ops"
  -W -b dc=andrew,dc=obs objectClass=*

ldapsearch -h localhost -p 389 -D cn="ldaproot,dc=andrew,dc=ops"
ldapsearch -h localhost -p 389 -D cn="ldaproot,dc=andrew,dc=ops"
   -W -b dc=andrew,dc=obs objectclass=*
   -W -b dc=andrew,dc=ops objectclass=*

  • h localhost -p 389 /* these are the defaults so optional
  • D cn="ldaproot,dc=andrew,dc=ops" # known as the Bind cn because it is the authentiction piece
  • W /* prompt for a password vs -w <secrtpass>
  • b dc=andrew,dc=obs # know as the base
  • objectclass=* # the filter object. i.e. search entries where the objectclass=* which would result in searches for EVERYTHING

/* as every directory entry must have an objectclass

  1. -h localhost and -p 389 are defaults so they can be omitted.

    The search becomes:

    ldapsearch -D cn="ldaproot,dc=andrew,dc=ops"
       -W -b dc=andrew,dc=ops objectclass=*    
    
    # extended LDIF
    #
    # LDAPv3
    # base <dc=andrew,dc=obs> with scope subtree
    # filter: objectClass=*
    # requesting: ALL
    #
    

    If things go right:

    # search result
    search: 2
    result: 0 Success
    # numResponses: 9
    # numEntries: 8
    

    If things do NOT go right.

    # search result
    search: 2
    result: 32 No such object
    # numResponses: 1
    

11.13 ldapsearch and grep vs slapcat and grep

The following example shows that the results of these two operations are the same, even though the way they were queried are very different:

root@vm4~[798]$ 
ldapsearch -h localhost -p 389 -D cn="ldaproot,dc=andrew,dc=ops" -w seneca99ldap -b dc=andrew,dc=ops objectClass=* | grep "dn:"
dn: dc=andrew,dc=ops
dn: cn=ldaproot,dc=andrew,dc=ops
dn: ou=People,dc=andrew,dc=ops
dn: ou=Group,dc=andrew,dc=ops
dn: uid=john,ou=People,dc=andrew,dc=ops
dn: uid=zintis,ou=People,dc=andrew,dc=ops
dn: uid=jane,ou=People,dc=andrew,dc=ops
dn: uid=guest,ou=People,dc=andrew,dc=ops
dn: uid=deleteme,ou=People,dc=andrew,dc=ops

root@vm4~[799]$ 
slapcat | grep "dn:"
5e8397f1 The first database does not allow slapcat; using the first available one (2)
dn: dc=andrew,dc=ops
dn: cn=ldaproot,dc=andrew,dc=ops
dn: ou=People,dc=andrew,dc=ops
dn: ou=Group,dc=andrew,dc=ops
dn: uid=john,ou=People,dc=andrew,dc=ops
dn: uid=zintis,ou=People,dc=andrew,dc=ops
dn: uid=jane,ou=People,dc=andrew,dc=ops
dn: uid=guest,ou=People,dc=andrew,dc=ops
dn: uid=deleteme,ou=People,dc=andrew,dc=ops

root@vm4~[800]$ 

11.14 UNBIND

"Binding means authentication." So the unbind operation simply abandons any outstanding operations and closes the connection. Think of it "logoff".

It has no response. The name is of historical origin, and is NOT the opposite Bind.

Using Linux commandline ldapxxx commands are one-offs and you don't need to unbind, or rather every command finishes by undbinding. So you need to bind again at each new command.

12 LDAP URI Scheme

LDAP URI (uniform resource identified) scheme exists. Clients support it to a varying level. ldap://host:port/DN?attributes?scope?filter?extensions

  • host is the FQDN or IP address of the LDAP server to search.
  • port is the network port (default port 389) of the LDAP server.
  • DN is the distinguished name to use as the search base.
  • attributes is a comma-separated list of attributes to retrieve.
  • scope specifies the search scope and can be "base" (the default), "one" or "sub".
  • filter is a search filter. For example, (objectClass=*) as defined in RFC 4515.
  • extensions are extensions to the LDAP URL format.

For example, ldap://ldap.example.com/cn="John Doe,dc=example,dc=com" refers to all user attributes in John Doe's entry in ldap.example.com, while "ldap:///dc=example,dc=com??sub?(givenName=John)" searches for the entry in the default server (note the triple slash, omitting the host, and the double question mark, omitting the attributes). As in other URLs, special characters must be percent-encoded.

There is a similar non-standard ldaps URI scheme for LDAP over SSL. This should not be confused with LDAP with TLS, which is achieved using the StartTLS operation using the standard ldap scheme.

13 SASL

From ldapwiki.com and I quote: Simple Authentication and Security Layer (SASL) is a framework for Authentication and data Security Layer that can provide data integrity, data confidentiality, and other services for Internet Protocols

SASL allows Authentication Method to be decoupled from application protocols, in theory allowing any Authentication Method supported by SASL to be used in any application protocol that uses SASL.

Authentication Methods may also support Delegation. They may also provide a data Security Layer offering data integrity and data confidentiality services.

DIGEST-MD5 provides an example of mechanisms which can provide a data Security Layer.

The original SASL specification RFC 2222 while at Carnegie Mellon University. In 2006 that document was made obsolete by RFC 4422, but a number of specific SASL Mechanisms are described in other specifications. [2]

As SASL Mechanisms are External to the Protocol, they may be referred to as EXTERNAL SASL Mechanism even though the SASL Mechanism may reside on and be done on by the same server.

Generic Operation [1]# The basic operation of SASL is straightforward. The server provides a list of supported authentication mechanisms, and then the client determines which of the supported authentication mechanisms will be used (based on the client’s capabilities and security requirements. Protocols that contain SASL support include:

LDAP (Internet Standard Lightweight Directory Access Protocol)

SMTP (Internet Standard Simple Message Transfer Protocol)

POP3 (Internet Standard Post Office Protocol v3)

IMAP (Internet Standard Internet Mail Access Protocol)

XMPP: Extensible Messaging and Presence Protocol

Isode's SOM (Switch Operations and Management) Protocol

To be used with SASL, a new authentication mechanism needs to be registered, and any authentication mechanism specific capabilities need to be agreed upon.

14 Examples from lab 7, Seneca OPS335

14.1 ldapusers.ldif

dn: uid=zintis,ou=People,dc=andrew,dc=ops
uid: zintis
cn: zintis
sn: zintis
mail: zintis@zintis.ops
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword: {crypt}$6$mjRyTHR5$ARM0BM7g1dPc422iHK3BGVHqcXVty0FETrE6yj/N47sudpjivy0ExxSNpvzW.
shadowLastChange: 18348
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 10000
gidNumber: 10000
homeDirectory: /home/zintis

14.2 slapcat output from original directory

slapcat
5e80f53b The first database does not allow slapcat; using the first available one (2)
dn: dc=andrew,dc=ops
dc: andrew
objectClass: top
objectClass: domain
structuralObjectClass: domain
entryUUID: 0192e632-da18-1038-83ca-ef40d5fa4d01
creatorsName: cn=ldaproot,dc=andrew,dc=ops
createTimestamp: 20190313201201Z
entryCSN: 20190313201201.126862Z#000000#000#000000
modifiersName: cn=ldaproot,dc=andrew,dc=ops
modifyTimestamp: 20190313201201Z

dn: cn=ldaproot,dc=andrew,dc=ops
objectClass: organizationalRole
cn: ldaproot
description: LDAP Manager
structuralObjectClass: organizationalRole
entryUUID: 019a13f8-da18-1038-83cb-ef40d5fa4d01
creatorsName: cn=ldaproot,dc=andrew,dc=ops
createTimestamp: 20190313201201Z
entryCSN: 20190313201201.174170Z#000000#000#000000
modifiersName: cn=ldaproot,dc=andrew,dc=ops
modifyTimestamp: 20190313201201Z

dn: ou=People,dc=andrew,dc=ops
objectClass: organizationalUnit
ou: People
structuralObjectClass: organizationalUnit
entryUUID: 01a1a870-da18-1038-83cc-ef40d5fa4d01
creatorsName: cn=ldaproot,dc=andrew,dc=ops
createTimestamp: 20190313201201Z
entryCSN: 20190313201201.223848Z#000000#000#000000
modifiersName: cn=ldaproot,dc=andrew,dc=ops
modifyTimestamp: 20190313201201Z

dn: ou=Group,dc=andrew,dc=ops
objectClass: organizationalUnit
ou: Group
structuralObjectClass: organizationalUnit
entryUUID: 01ac22f0-da18-1038-83cd-ef40d5fa4d01
creatorsName: cn=ldaproot,dc=andrew,dc=ops
createTimestamp: 20190313201201Z
entryCSN: 20190313201201.292521Z#000000#000#000000
modifiersName: cn=ldaproot,dc=andrew,dc=ops
modifyTimestamp: 20190313201201Z

dn: uid=john,ou=People,dc=andrew,dc=ops
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
cn: john
uid: john
uidNumber: 9999
gidNumber: 100
homeDirectory: /home/john
loginShell: /bin/bash
gecos: John Someone
shadowLastChange: 17058
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
structuralObjectClass: account
entryUUID: bfa78756-da1b-1038-83d1-ef40d5fa4d01
creatorsName: cn=ldaproot,dc=andrew,dc=ops
createTimestamp: 20190313203848Z
userPassword:: e1NTSEF9a0ljTGtXdVkxNXBQL0labDN3TklBaE5MSm94cWU4ZVQ=
entryCSN: 20190709215232.858989Z#000000#000#000000
modifiersName: cn=ldaproot,dc=andrew,dc=ops
modifyTimestamp: 20190709215232Z

14.3 Adding user zintis to directory:

This ldapusers.ldif file had an error that shows up with error: "no global superior knowledge"

root@vm4~[604]$ 
ldapadd -v -f ldapusers.ldif -D cn="ldaproot,dc=zintis,dc=ops" -W 
ldap_initialize( <DEFAULT> )
Enter LDAP Password: seneca99ldap
add uid:
     zintis
add cn:
     zintis
add sn:
     zintis
add mail:
     zintis@zintis.ops
add objectClass:
     person
     organizationalPerson
     inetOrgPerson
     posixAccount
     top
     shadowAccount
add userPassword:
     {crypt}$6$mjRyTHR5$ARM0hiRWKGdBM7g1dPc422i4Ut9TQ7HKty0FETrE6yj/NxudpjitlrhkNpvzW.
add shadowLastChange:
     18348
add shadowMin:
     0
add shadowMax:
     99999
add shadowWarning:
     7
add loginShell:
     /bin/bash
add uidNumber:
     10000
add gidNumber:
     10000
add homeDirectory:
     /home/zintis
adding new entry "uid=zintis,ou=People,dc=zintis,dc=op"s
ldap_add: Server is unwilling to perform (53)
     additional info: no global superior knowledge

root@vm4~[604]$ 

The error above occurs because we were trying to add entries specified for the zintis.ops tree, where the tree was actually andrew.ops.

Fix was to correct the config file in : /usr/share/migrationtools/migrate-passwd.pl so that the migratepasswd step would generate ldif data correctly (i.e. dc=andrew,dc=ops)

14.4 Error "no global superior knowledge"

This specific error means that slapd doesn't know where to put the new entry. This typically means that you have not defined an appropriate database, or you have made a typo in the higher in the tree. With newer systems (ones using cn=config instead of slapd.conf), you would typically first add a new database or modify an existing database entry using ldapadd or ldapmodify.

For example, let's say you are trying to add "uid=zintis,ou=People,dc=zintis,dc=ops" But you are in a tree with dc=zint,dc=ops slapd cannot find the root tree dc=zint,dc=ops so it says "No superior knowledge".

14.5 Adding three users to ldap

useradd zintis -u 10000
useradd -c "Jane Greystoke" jane -u 10001
useradd -c "Andrew's Guests" guest -u 10002

if user jane already exists, delete her with userdel jane
also chown her mailbox with chown jane /var/spool/mail/jane
And delete /var/spool/mail/andrew

grep -w zintis /etc/passwd > /root/zintis.entry
grep -w Jane /etc/passwd > /root/jane.entry
grep -w Andrew /etc/passwd > /root/guest.entry

/usr/share/migrationtools/migrate_passwd.pl /root/zintis.entry /root/zintis.ldif
/usr/share/migrationtools/migrate_passwd.pl /root/jane.entry /root/jane.ldif
/usr/share/migrationtools/migrate_passwd.pl /root/guest.entry /root/guest.ldif

ldapadd -v -f ldapusers.ldif -D cn="ldaproot,dc=andrew,dc=ops" -W 
ldapadd -v -f jane.ldif -D cn="ldaproot,dc=andrew,dc=ops" -W 
ldapadd -v -f guest.ldif -D cn="ldaproot,dc=andrew,dc=ops" -W 

14.6 Changing an existing user's password

slapcat shows user John as:

dn: uid=john,ou=People,dc=andrew,dc=ops
objectClass: top
objectClass: account
objectClass: posixAccount
objectClass: shadowAccount
cn: john
uid: john
uidNumber: 9999
gidNumber: 100
homeDirectory: /home/john
loginShell: /bin/bash
gecos: John Someone
shadowLastChange: 17058
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
structuralObjectClass: account
entryUUID: bfa78756-da1b-1038-83d1-ef40d5fa4d01
creatorsName: cn=ldaproot,dc=andrew,dc=ops
createTimestamp: 20190313203848Z
userPassword:: e1NTSEF9a0ljTGtXdVkxNXBQL0labDN3TklBaE5MSm94cWU4ZVQ=
entryCSN: 20190709215232.858989Z#000000#000#000000
modifiersName: cn=ldaproot,dc=andrew,dc=ops
modifyTimestamp: 20190709215232Z

14.6.1 Change John's password with ldapppasswd

ldappasswd -s Jan1sparole -W -D "cn=ldaproot,dc=andrew,dc=ops" 
           -x "uid=john,ou=people,dc=andrew,dc=ops"

14.6.2 Confirm the change with ldapsearch

ldapsearch -h localhost -p 389 -D cn="ldaproot,dc=andrew,dc=ops" 
           -W -b dc=andrew,dc=ops uid=john

15 ldap client

To let a VM authenticate to an ldap server.

15.1 Install the necessary LDAP client packages on the client machine.

This is PAM the "Pluggable Authentication Module" and NSS the "Name Service Switch"

yum install -y openldap-clients nss-pam-ldapd Since CentOS8 does not see nss-pam-ldap I did the following:

First: dnf provides nss-pam-ldapd Then, based on the above this: dnf install -y nss-pam-ldapd-0.9.9-3.el8.x8664

15.2 About nss-pam-ldapd

From arthurdejong.org: This is nss-pam-ldapd which provides a Name Service Switch (NSS, nsswitch) module that allows your LDAP server to provide user account, group, host name, alias, netgroup, and basically any other information that you would normally get from /etc flat files or NIS. It also provides a Pluggable Authentication Module (PAM) to do identity and authentication management with an LDAP server on unix systems.

This is implemented using thin NSS and PAM modules which delegate to a dedicated service (nslcd) that queries the LDAP server with persistent connections, authentication, attribute translation, etc.

The NSS module was originally a fork of nssldap with some structural design improvements. The most important features of nss-pam-ldapd are:

  • light and simple NSS and PAM libraries
  • avoid loading LDAP and SSL libraries in all programs
  • separation between NSS, PAM and LDAP code
  • fewer connections to the LDAP server
  • better debugging possibilities
  • better performance
  • See the documentation section for more detai

16 Configuring LDAP Authentication on CentOS 8

From tylers guides I have dnf installed nss-pam-ldapd, and nss ? which one?

I have edited /etc/nslcd.conf according to tyler's website

I skipped the TLS section.

And I have enbled and started nslcd

I have authselect ready to go, after running these commands as root with the goal of replacing the SSSD related text with NSLCD equivalent in the relevant files.

root@vm1/etc[1038]$ tar cf /root/pre-ldap-config.tar nsswitch.conf pam.d root@vm1/etc[1039]$ date Mon Mar 30 18:52:43 EDT 2020

authselect select custom/nslcd –force Profile "custom/nslcd" was selected. The following nsswitch maps are overwritten by the profile:

  • passwd
  • group
  • netgroup
  • automount
  • services

Make sure that NSLCD service is configured and enabled. See NSLCD documentation for more information.

16.1 Centos7 only (I think: )

Configure the client VM to use LDAP To add the client machine to LDAP server for single sign-on. Replace “192.168.1.10” with your LDAP server’s IP address or hostname.

authconfig –enableldap –enableldapauth –ldapserver=192.168.1.10 –ldapbasedn="dc=itzgeek,dc=local" –enablemkhomedir –update

Restart the LDAP client service. O.K, so this will make this VM defer logins to the LDAP server rather than looking in its own /etc/passwd file ??? That would mean that the users defined in the ldap server would require a local prescence on this VM, including home directory, and entry in /etc/passwds. I guess this is just centralizing the passwords themselves I guess?? Confirm this!

systemctl restart nslcd To verify LDAP Login, use the getent command to get the LDAP entries from the LDAP server.

getent passwd raj Output:

raj:x:9999:100:Raj [Admin (at) ITzGeek]:/home/raj:/bin/bash Screenshot:

OpenLDAP Server Configuration on CentOS 7 - Verify LDAP Login OpenLDAP Server Configuration on CentOS 7 – Verify LDAP Login

To verify the LDAP, log in using the LDAP user “raj” on the client machine. Like this:

16.2 LDAP Youtube Videos:

These two videos explain LDAP nicely. Worth the 40 minutes of watching.

https://youtu.be/9x6_ALb76sQ

https://youtu.be/SJ5WYGTHQnY

17 Appendix 1 LDAP Response codes:

Easiest just to look them up.

Result Code Name Code
success 0
operationsError 1
protocolError 2
timeLimitExceeded 3
sizeLimitExceeded 4
compareFalse 5
compareTrue 6
authMethodNotSupported 7
strongerAuthRequired 8
referral 10
adminLimitExceeded 11
unavailableCriticalExtension 12
confidentialityRequired 13
saslBindInProgress 14
noSuchAttribute 16
undefinedAttributeType 17
inappropriateMatching 18
constraintViolation 19
attributeOrValueExists 20
invalidAttributeSyntax 21
noSuchObject 32
aliasProblem 33
invalidDNSyntax 34
isLeaf 35
aliasDereferencingProblem 36
inappropriateAuthentication 48
invalidCredentials 49
insufficientAccessRights 50
busy 51
unavailable 52
unwillingToPerform 53
loopDetect 54
sortControlMissing 60
offsetRangeError 61
namingViolation 64
objectClassViolation 65
notAllowedOnNonLeaf 66
notAllowedOnRDN 67
entryAlreadyExists 68
objectClassModsProhibited 69
resultsTooLarge 70
affectsMultipleDSAs 71
virtualListViewError or
other 80
serverDown 81
localError 82
encodingError 83
decodingError 84
timeout 85
authUnknown 86
filterError 87
userCanceled 88
paramError 89
noMemory 90
connectError 91
notSupported 92
controlNotFound 93
noResultsReturned 94
moreResultsToReturn 95
clientLoop 96
referralLimitExceeded 97
invalidResponse 100
ambiguousResponse 101
tlsNotSupported 112
intermediateResponse 113
unknownType 114
canceled 118
noSuchOperation 119
tooLate 120
cannotCancel 121
assertionFailed 122
authorizationDenied 123
e-syncRefreshRequired 4096
noOperation 16654

18 Files / Directories

From my vm4 CentOS8 guest I have:

  • /root/ldapusers.entry
  • /root/ldapusers.ldif
  • ~/bin/backup-ldap-config.bash
  • /etc/openldap

18.1 Home