Search code examples
phpformsauthenticationactive-directory

LDAP Authentication via PHP - Access Groups


We currently have a basic login page (login.php) for our site and a separate script (auth.php) which includes the function that authenticates a user against the domain via LDAP. Once logged in all users have the same level of access, we are wanting to change that.

Currently when a user logs in we grab all the groups where they are member. We then iterate through the groups to see if they have access to the system via one of our AD groups. If they do they are able to progress into the site.

Because we don't want everyone who has authenticated to the site to have access to all content, we want to change this. We want to setup page level access levels once a user is authenticated. And because a user may be assigned to multiple access groups we want to only give them the lowest level of access.

We are going to use the session variable to set the access level and then use something like the following for the page level access.

if ($_SESSION['access'] != 3)
    {
    // user is logged in but not a ops team member, let's stop him
    die("Access Denied");
    }

Below is the current auth.php script.

login.php:

include("auth.php");

auth.php

<?php
session_start(); // Initialize session
function authenticate($user, $password)
    {
    $ldap_host = "example.com"; // Active Directory server
    $ldap_dn = "DC=example,DC=com"; // Active Directory DN
    $ldap_manager_group = "Group_1"; // Active Directory manager group
    $ldap_ops_group = "Group_2"; // Active Directory ops group
    $ldap_eng_group = "Group_3"; // Active Directory eng group
    $ldap_eng2_group = "Group_4"; // Active Directory other eng group
    $ldap_usr_dom = "@example.com"; // Domain, for purposes of constructing $user
    $ldap = ldap_connect($ldap_host); // connect to active directory

    if ($bind = @ldap_bind($ldap, $user . $ldap_usr_dom, $password)) // verify user and password
        {
        // valid
        // check presence in groups
        $filter = "(sAMAccountName=" . $user . ")";
        $attr = array(
            "memberof",
            "cn",
            "givenname",
            "sn"
        );
        $result = ldap_search($ldap, $ldap_dn, $filter, $attr) or exit("Unable to search LDAP server");
        $entries = ldap_get_entries($ldap, $result);
        $givenname = $entries[0]['givenname'][0];
        $surname = $entries[0]['sn'][0];
        ldap_unbind($ldap);

        foreach($entries[0]['memberof'] as $grps) // check groups
            {
            if (strpos($grps, $ldap_manager_group)) // is manager, break loop
                {
                $access = 4;
                $group = $ldap_manager_group;
                break;
                }

            if (strpos($grps, $ldap_ops_group)) $access = 3; // is ops team
            $group = $ldap_ops_group;

            if (strpos($grps, $ldap_eng_group)) $access = 2; // is eng team
            $group = $ldap_eng_group;

            if (strpos($grps, $ldap_eng2_group)) $access = 1; // is eng2 team
            $group = $ldap_eng2_group;
            }

        if ($access != 0)
            {
            // establish session variables
            $_SESSION['user'] = $user;
            $_SESSION['access'] = $access;
            $_SESSION['access_group'] = $group;
            $_SESSION['givenname'] = $givenname;
            $_SESSION['sn'] = $surname;
            return true;
            }
          else
            {
            return false; // user has no rights
            }
        }
      else
        {
        return false; // invalid name or password
        }
    }
?>

We are thinking about creating new access groups for each access level, like below:

  • $access = 1 # Access to reporting (group = site_reporting)
  • $access = 2 # Access to reporting + content3 (group = site_ops)
  • $access = 3 # Access to reporting + content1 (group = site_content1)
  • $access = 4 # Access to reporting + content2 (group = site_content2)
  • $access = 9 # Admin (group = site_admin)

But are confused how we would search all the LDAP memberships for all of our access groups and assign the lowest access value.

We were thinking something like this would work but it won't match the output of the array from LDAP.

$grps = array(
    $entries[0]['memberof']
);

if (in_array('site_reporting', $grps))
    {
    $access = 1;
    }
elseif (in_array('site_ops', $grps))
    {
    $access = 2;
    }
elseif (in_array('site_content1', $grps))
    {
    $access = 3;
    }
elseif (in_array('site_content2', $grps))
    {
    $access = 4;
    }
elseif (in_array('site_admin', $grps))
    {
    $access = 9;
    }

Any help would be appreciated! Thanks!


Solution

  • I assume the reason it will not match is because you are trying to match only on the AD group name, however your query is bringing back the AD schema (CN,OU,DC,etc).

    One suggestion is to use a foreach loop and use explode to split out only the group name and the results to a new array. Then use that array as your haystack in the if\else statements.