Differences between revisions 36 and 37
Revision 36 as of 2016-03-01 10:42:27
Size: 15835
Editor: vauss
Comment: translation menu
Revision 37 as of 2017-04-12 15:23:31
Size: 16531
Deletions are marked like this. Additions are marked like this.
Line 149: Line 149:

An alternative way for "logins on a per-group basis" is nslcd.
With `pam_authz_search` option one can define not only primary groups as with `pam_access` but also check against secondary groups or even mixture of primary and secondary groups.

For example we want to allow users whose primary ldap group is `admins` ( `gidNumber` `1234` ) and also members of group `developers` ( secondary group )
The following filter should do the trick:

#allow only memebers of secondary group developers and users with primary group admins
pam_authz_search (|(&(objectClass=posixGroup)(cn=developers)(memberUid=$username))(&(objectClass=posixAccount)(uid=$username)(gidNumber=1234)))

Translation(s) : English - Français

(!) ?Discussion

Configuring LDAP Authentication

There are basically two ways to configure PAM to use an LDAP server. The first option utilizes the pam_ldap module from the libpam-ldap package to check credentials against the LDAP server. The second way uses password hashes sent from the LDAP server to the client using NSS. A traditional pam_unix module then does the authentication. In the later option, pam_ldap can still be used to change passwords. Both solutions have their pros and cons.

In both cases the users are exposed through NSS. Of note, the pam_unix option is required if using getent shadow to return password hashes when run as root.

The pure pam_ldap solution allows limiting logins by how users are stored in the directory (e.g. only allow logins for users in a certain piece of the directory, require some attribute, etc). It also requires less access rights to the LDAP directory and does not expose password hashes.

The pam_unix solution is possibly more familiar to system administrators.

PAM Setup with libpam-ldapd

libpam-ldapd is a newer alternative pam_ldap module implementation of the original PADL libpam-ldap. libpam-ldapd uses the same backend (nslcd) as libnss-ldapd, and thus also shares the same configuration file (/etc/nslcd.conf) for LDAP connection parameters. If you're already using libnss-ldapd for NSS, it may be more convenient to use libpam-ldapd's pam_ldap implementation.

As of pam 1.0.1-6 (Debian squeeze?), the /etc/pam.d/common-* files are managed by pam-auth-update (from libpam-runtime, see PAMConfigFrameworkSpec). The libpam-ldapd package includes /usr/share/pam-configs/ldap, and a dpkg-reconfigure libpam-runtime will let you configure the pam_unix/pam_ldap module(s) to use in /etc/pam.d/common-*.

Installing the libpam-ldapd package will automatically select the pam_ldap module for use in /etc/pam.d/common-*. The generated configuration is more suitable for use via @include in the various services in /etc/pam.d than the example configuration given below for libpam-ldap (e.g. login applies the auth optional pam_group.so after the @include common-auth).

PAM setup with libpam-ldap

In order to globally enable LDAP authentication through PAM, configure /etc/pam_ldap.conf accordingly and edit the /etc/pam.d/common-* files so that they contain something like this:


account     required      pam_unix.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     [default=bad success=ok user_unknown=ignore] pam_ldap.so
account     required      pam_permit.so


auth    sufficient      pam_unix.so nullok_secure
auth    requisite       pam_succeed_if.so uid >= 1000 quiet
auth    sufficient      pam_ldap.so use_first_pass
auth    required        pam_deny.so


password    sufficient    pam_unix.so md5 obscure min=4 max=8 nullok try_first_pass
password    sufficient    pam_ldap.so
password    required      pam_deny.so


session     required      pam_limits.so
session     required      pam_unix.so
session     optional      pam_ldap.so

Note that there are numerous ways to configure PAM, depending on your particular situation and preference. The above only attempts to use pam_ldap if the userid is not below 1000 (i.e. normal user accounts).

PAM setup with pam_unix

(there have been reports that the following does not work as described, please correct if needed)

It is also possible to use plain old pam_unix by making sure /etc/nsswitch.conf contains something like shadow: files ldap and getent shadow shows password hashes.

If only authentication is needed, no changes to PAM configuration files should be necessary. For changing passwords, login shell and gecos install libpam-ldap, configure /etc/pam_ldap.conf and edit /etc/pam.d/common-password to contain something like this:

password   required   pam_ldap.so ignore_unknown_user md5
password   optional   pam_unix.so nullok obscure min=4 max=8 md5 try_first_pass

Note the 'md5' setting. This will ensure passwords are encrypted into MD5 digests when they are changed. You may also need to add pam_password md5 to /etc/pam_ldap.conf for this to work.

Creating home directory on login

Until Bug #568577 not closed, you need to manually сreate file /usr/share/pam-configs/mkhomedir

Name: Create home directory during login
Default: yes
Priority: 900
Session-Type: Additional
        required        pam_mkhomedir.so umask=0022 skel=/etc/skel

and run command

sudo pam-auth-update

Allowing logins on a per-host basis

The pam_ldap module provides the ability to specify a list of hosts a user is allowed to log into, in the "host" attribute in LDAP. The host attribute can be specified multiple times for each user. If any of the entries match the hostname (of the machine logging in to), login is succesful. Otherwise, login is denied.

This feature is enabled by specifying pam_check_host_attr yes in /etc/pam_ldap.conf. When it is enabled, the account facility of pam_ldap will perform the checks and return an error when no proper host attribute is present.

The hostname in the "host" attribute on the user can be prefixed with "!" to deny access to that host for that user. This is mostly useful in conjunction with the special entry "*", which allows access to all hosts.

To add the "host" attribute to a user, he should have an objectClass that supports this. The "account" objectClass has the attribute, but is not compatible with the "inetOrgPerson" objectClass. To work around this, you can use the "ldapns" schema, supplied with the libpam-ldap package. This schema provides the "hostObject" objectClass, which has the proper "host" attribute.

To enable this schema, add the following line to your slapd.conf:

include         /usr/share/doc/libpam-ldap/ldapns.schema

Finally, take care that the hostname of the server is resolvable. pam_ldap will try to resolve the hostname, to find any aliasses (such as listed in /etc/hosts). If the hostname is not resolvable, access is denied.

In order to enable host based authentication with libpam-ldapd one can use nslcd with pam_authz_search option.

The pam_check_host_attr option can be emulated with this filter:


You might need something more elaborate if you want to have negation (!host) capability. E.g.:


see man nslcd.conf for more details.

Allowing logins on a per-group basis

A common task is to restrict logins to a given LDAP group. With NIS, you would do this with careful tweaking of your /etc/passwd file. With LDAP, the easiest way is to use the pam_access module that comes with libpam-modules.

Add the following line to /etc/pam.d/common-auth:

auth required    pam_access.so

(This doesn't seem to affect logins using an SSH key unless auth is replaced by account?)

This will activate /etc/security/access.conf, to which you can tweak as follows:

# disallow all except people in the login group and root

This assumes you have a posixGroup named login in your LDAP tree with LDAP/NSS set up properly. Be careful about ensuring that you can still allow local users to login in case LDAP fails.

An alternative way for "logins on a per-group basis" is nslcd. With pam_authz_search option one can define not only primary groups as with pam_access but also check against secondary groups or even mixture of primary and secondary groups.

For example we want to allow users whose primary ldap group is admins ( gidNumber 1234 ) and also members of group developers ( secondary group ) The following filter should do the trick:

#allow only memebers of secondary group developers and users with primary group admins
pam_authz_search (|(&(objectClass=posixGroup)(cn=developers)(memberUid=$username))(&(objectClass=posixAccount)(uid=$username)(gidNumber=1234)))

Permissions on the LDAP server

To get 'chsh' and 'chfn' to work for updating LDAP, you have to have the right settings in their /etc/pam.d/ entries, and you have to setup slapd.conf to allow access for users to update their entries. If needed, add something like this to slapd.conf:

  access to attrs=loginShell
         by dn="cn=admin,dc=FOO,dc=BAR" write
         by self write
         by * read

  access to attrs=gecos
         by dn="cn=admin,dc=FOO,dc=BAR" write
         by self write
         by * read

Caching LDAP credentials for offline use (Laptops)

Disclaimer: This information was tested with Debian Lenny.

While contineous LDAP connectivity can be assumed for workstations and servers in a LAN, laptop users often do not have network connectivity. From a system administrators point of view it is tempting to create local users on the laptop but this causes trouble because you have to manage several password stores. On the other side, the situation where a user cannot login because the laptop cannot reach the LDAP server is unacceptable too.

Luckily the PAM stack has a way to cache the password information through the use of the PAM module libpam-ccreds. In short terms this module stores the password hash if a user has correctly authenticated through the PAM LDAP module. If the LDAP server is later unavailable to PAM, it uses ccred's locally cached credentials to authenticate the user.

The documentation in /usr/share/doc/libpam-ccreds/ is not using the default Debian Lenny scheme of splitted PAM config files in /etc/pam.d/ but it is easy to split the pam.conf in the examples dir into the several common-* files in /etc/pam.d/. At a minimum /etc/pam.d/common-auth has to be changed.

Unfortunately the example PAM configuration does not work out of the box with a standard Lenny installation. In some offline situations the ccred module is not used at all (you get a message in a text-mode login when libpam-ccreds is used). You can change /etc/pam.d/common-auth like this to get it working:

auth sufficient /lib/security/pam_unix.so
auth [authinfo_unavail=ignore success=1 default=2] /lib/security/pam_ldap.so use_first_pass
auth [default=done]     /lib/security/pam_ccreds.so action=validate use_first_pass
auth [default=done]     /lib/security/pam_ccreds.so action=store
auth [default=bad]      /lib/security/pam_ccreds.so action=update

Other alternatives:

  • sss (see Petter Reinholdtsens Blog)

  • after all, if you just have a single laptop user who does not change his password very often it is far easier to just add a local user with the same username and the same UID as found in the LDAP database ;-)

Hint: Offline caching of LDAP credentials is only useful if LDAP information about users and groups is also available offline through NSS. This can be accomplished through the use of NSCD. See LDAP/NSS for more information.

LDAP server in Pass-through-mode

(Tested with wheezy.)

This setup example is a solution, if you have your own LDAP-server for e.g. a workgroup, but account management is done from a central LDAP server e.g. from a university. Point is: You have to be able to authenticate to 2 different LDAP servers. If server 1 accepts you, you should be logged in. If not, you should be delegated to server 2.

Solution 1 would be to configure the pam-stack with 2 pam_ldap.so entries with different config files, cf. this debian bug report. However, as mentioned there, you have to patch and build your own version of pam_ldap - at least at the moment. Furthermore, this is not the most elegant solution. Your client and server 1 both have 1 unsuccessful authentication attempt each time a user from server 2 logs in.

Solution 2 is LDAP pass-through authentication. It's an elegant solution, but it's not easy to configure:

  • aptitude install sasl2-bin

  • in /etc/default/saslauthd:

  • in /etc/saslauthd.conf (maybe you have to create it):

    ldap_servers: ldaps://dc1.example.com ldaps://dc2.example.com
    ldap_search_base: dc=example,dc=com
    ldap_bind_dn: cn=exampleuser,ou=host,dc=blarz,dc=example,dc=com
    ldap_bind_pw: your-secret-password
    ldap_filter: (uid=%U)
    ldap_scope: sub
    #ldap_group_attr: memberUid
    #ldap_group_match_method: filter
    #ldap_group_filter: (memberUid=%u)
    #ldap_group_search_base: ou=group,dc=domain,dc=de
    #ldap_size_limit: 0
    ldap_tls_check_peer: yes
    ldap_tls_cacert_file: /etc/ldap/certs.txt
    ldap_tls_cacert_dir: /etc/ssl/certs/
    ldap_time_limit: 15
    ldap_timeout: 15
    ldap_version: 3
    • change accordingly to your setup
    • especially for initial setup it might be easier to switch of peer certificate checks
    • for debugging use ldap_verbose: on and watch /var/log/{syslog,daemon.log,auth.log} 

  • in /usr/lib/sasl2/slapd.conf (sic!):

    pwcheck_method: saslauthd
  • configure LDAP:
    ldapmodify -Y external -H ldapi:/// <<EOF
    dn: cn=config
    add: olcSaslHost
    add: olcSaslSecProps
    olcSaslSecProps: none
  • add user openldap to group sasl

Testing your solution

  • Check correctness of user/password for binding against external LDAP:
    ldapsearch -x -H ldap://dc1.example.com/ \
          -D cn=exampleuser,ou=host,dc=blarz,dc=example,dc=com \
          -w secret \
          -b '' \
          -s base
  • Check existence of test user on external LDAP:
    ldapsearch -x -H ldap://dc1.example.com/ \
          -D cn=exampleuser,ou=host,dc=blarz,dc=example,dc=com \
          -w secret \
          -b ou=people,dc=blarz,dc=example,dc=com \
  • Check if test user can bind to external LDAP:
    ldapsearch -x -H ldap://dc1.example.com/ \
          -D uid=user,ou=people,DC=blarz,DC=example,DC=com \
          -w userpassword \
          -b uid=user,ou=people,DC=blarz,DC=example,DC=com \
          -s base \
  • check if saslauthd can do the same:
     testsaslauthd -u user@blarz.example.com -p userpassword
     testsaslauthd -u user@blarz.example.com -p wrongpassword
    • don't forget to wipe your history or better yet: prepend a space so password information gets forgotten immediately
  • Test all together by binding to your internal LDAP:
    ldapwhoami -x -D 'uid=user,ou=yourusers,dc=yourinternal,dc=example,dc=com' -W
    • it should check authentication correctly for internal and external users now
  • If using OpenSSH, you may need to add "UsePAM yes" to sshd_config or it will not use PAM by default.

See also