6.0.0-git
2024-03-19
Last Modified 2012-07-12 by Ralf Lang

Horde Authentication by LDAP group

After quite a lot of playing with LDAP ACL's, I discovered the way to authenticate users normally using IMP and LDAP, and then restrict them by membership in a particular LDAP group. This allows us to run multiple different Horde installations on the same box and restrict who can log into each by creating an appropriate group. It also allows us to use IMP for authentication resulting in a single login for the users.

postauthenticate hook

There are multiple custom hooks available in Horde. Two of these are the preauthenticate and postauthenticate hooks. The basic idea is to allow IMP to authenticate with IMAP and the use the postauthenticate hook to enforce the further requirement of specific LDAP group membership. postauthenticate hook for openldap groups

I took the example provided for Active Directory groups and modified it to use openLDAP groups. The major difference is that in Active Directory, it appears that the group membership information is stored in the user account using the "memberof" attribute. In openLDAP, the group membership information is (typically, in my experience) stored in the group object using the "member" attribute, so instead of searching the user dn for a list of groups, we end up searching the group object for a list of members.

Here is the modified hook.

// Here is an example of validating the user's right to login to Horde by
// consulting group membership in an LDAP directory.  That way, if your Horde
// installation is configured to authenticate against IMP which in turn
// authenticate via IMAP, it is still possible to limit access to Horde by
// group membership.  The following example had been made with an openLDAP
// Directory in mind.  Note that if the LDAP directory is unavailable or some
// other error occur, authentication will fail.

if (!function_exists('_horde_hook_postauthenticate')) {
    function _horde_hook_postauthenticate($userID, $credential, $realm)
    {
        $ldapServer = 'localhost';
        $ldapPort = '389';
        // Note that credential is sent plain-text in this case, so don't use
        // privileged account here or setup SSL (by using port 636 above).
        // uncomment if not using an anonymous bind
        //$binddn = 'uid=bindn,ou=people,dc=example,dc=com';
        //$bindpw = 'password';
        // search base for LDAP groups
        $searchBase = 'ou=group,dc=example,dc=com';
        $groupAttr = 'cn';
        // Group membership attribute, need to be all lowercase
        $groupMembershipAttr = 'member';
        // Attribute to check for right to use Horde
        $groupName = 'horde_authorized_group_name';
        $ret = false;
        $ds = @ldap_connect($ldapServer, $ldapPort);
        // used to set the LDAP protocol to version 3 (recommended)
        // not necessary if your LDAP server supports version 2
        ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);

        if (@ldap_bind($ds, $binddn, $bindpw)) {
            $searchResult = @ldap_search($ds, $searchBase, $groupAttr . '=' . $groupName, array($groupMembershipAttr), 0, 1, 5);
            if ($information = @ldap_get_entries($ds, $searchResult)) {
                // make pattern case-insensitive
                $pattern = '/^' . $userID . '$/i';
                foreach ($information[0][$groupMembershipAttr] as $group) {
                    if (preg_match($pattern, $group)) {
                        $ret = true;
                        break;
                    }
                }
            }
        }

        ldap_close($ds);
        return $ret;
    }
}

Enabling the postauthenticate hook

In the Horde administrative interface, select the "custom function hooks" tab and check the box for

function _horde_hook_postauthenticate()

-- Derek Dresser - 27 Jan 2006

Link