Revision: 1996
          http://mrbs.svn.sourceforge.net/mrbs/?rev=1996&view=rev
Author:   jberanek
Date:     2011-09-22 14:41:57 +0000 (Thu, 22 Sep 2011)
Log Message:
-----------
Revamped the LDAP authentication scheme somewhat. You can now
specify most of the configuration parameters as arrays, so that
you can have multiple servers or multiple base DNs that are configured
in different ways.

Additionally, you can now determine whether a user is an
administrator by defining LDAP configuration parameters:
$ldap_group_member_attrib and $ldap_admin_group_dn. See
systemdefaults.inc.php for details.

Modified Paths:
--------------
    mrbs/trunk/AUTHENTICATION
    mrbs/trunk/web/auth_ldap.inc
    mrbs/trunk/web/functions.inc
    mrbs/trunk/web/systemdefaults.inc.php

Modified: mrbs/trunk/AUTHENTICATION
===================================================================
--- mrbs/trunk/AUTHENTICATION   2011-09-22 09:56:45 UTC (rev 1995)
+++ mrbs/trunk/AUTHENTICATION   2011-09-22 14:41:57 UTC (rev 1996)
@@ -690,9 +690,10 @@
 the supplied password and a distinguished name, which is formed from the
 base distinguished name, the user attribute and the user name. 
 
-This method supports multiple $ldap_base_dn entries and $ldap_user_attrib
-values.  The authentication is attempted with each base dn in turn until it
-succeeds or it fails to authenticate the user.
+This method supports multiple values for most of the configuration
+parameters, including $ldap_base_dn entries and $ldap_user_attrib
+values.  The authentication is attempted with each set of configuration
+parameters in turn until it succeeds or it fails to authenticate the user.
 
 Multiple base distinguished names with the same user attribute for each
 base dn:

Modified: mrbs/trunk/web/auth_ldap.inc
===================================================================
--- mrbs/trunk/web/auth_ldap.inc        2011-09-22 09:56:45 UTC (rev 1995)
+++ mrbs/trunk/web/auth_ldap.inc        2011-09-22 14:41:57 UTC (rev 1996)
@@ -8,6 +8,7 @@
   $auth['session']='http';
 }
 
+
 /* authLdapAction($callback, $user, &$object)
  * 
  * Connects/binds to all configured LDAP servers/base DNs and
@@ -34,6 +35,10 @@
   global $ldap_dn_search_attrib;
   global $ldap_dn_search_dn;
   global $ldap_dn_search_password;
+  global $ldap_filter;
+  global $ldap_group_member_attrib;
+  global $ldap_admin_group_dn;
+  global $ldap_email_attrib;
 
   if (!function_exists("ldap_connect"))
   {
@@ -41,83 +46,109 @@
         "Please check your MRBS and web server configuration.</b></p><hr>\n");
   }
 
-  $all_ldap_base_dn     = array();
-  $all_ldap_user_attrib = array();
+  // Transfer the values from the config variables into a local
+  // associative array, turning them all into arrays
+  
+  $config_items = array(
+                        'ldap_host',
+                        'ldap_port',
+                        'ldap_base_dn',
+                        'ldap_user_attrib',
+                        'ldap_dn_search_attrib',
+                        'ldap_dn_search_dn',
+                        'ldap_dn_search_password',
+                        'ldap_filter',
+                        'ldap_group_member_attrib',
+                        'ldap_admin_group_dn',
+                        'ldap_v3',
+                        'ldap_tls',
+                        'ldap_email_attrib'
+                       );
 
-  // Check that if there is an array of hosts and an array of ports
-  // then the number of each must be the same or the authenication
-  // is forced to fail.
-  if (is_array( $ldap_base_dn ) && is_array( $ldap_user_attrib ) &&
-      count($ldap_user_attrib) != count($ldap_base_dn) )
-  {
-    return 0;
-  }
+  $all_ldap_opts = array();
 
-  // Transfer the based dn(s) to an new value to ensure that
-  // an array is always used.
-  // If a single value is passed then turn it into an array
-  if (is_array( $ldap_base_dn ) )
+  
+  foreach ($config_items as $item)
   {
-    $all_ldap_base_dn = $ldap_base_dn;
+    if (!isset($$item))
+    {
+      continue;
+    }
+    if (is_array($$item))
+    {
+      $all_ldap_opts[$item] = $$item;
+    }
+    // The case where the config item _isn't_ an array is handled
+    // further down
   }
-  else
-  {
-    $all_ldap_base_dn = array($ldap_base_dn);
-  }
 
-  // Transfer the array of user attributes to a new value.
-  // Create an array of the user attributes to match the number of
-  // base dn's if a single user attribute has been passed.
-  if (is_array( $ldap_user_attrib ) )
+  $count = null;
+  foreach ($all_ldap_opts as $key => $value)
   {
-    $all_ldap_user_attrib = $ldap_user_attrib;
-  }
-  else
-  {
-    while ( each($all_ldap_base_dn ) )
+    if (isset($count))
     {
-      $all_ldap_user_attrib[] = $ldap_user_attrib;
+      if (count($value) != $count)
+      {
+        authLdapDebug("Count of LDAP array config variables doesn't match, 
aborting!");
+        fatal_error(TRUE,
+                    "MRBS configuration error: Count of LDAP array config 
variables doesn't match, aborting!",
+                    false);
+        return 0;
+      }
     }
+    $count = count($value);
   }
 
-  // establish ldap connection
-  // the '@' suppresses errors
-  if (isset($ldap_port))
+  // Turn any non-array config items into arrays in $all_ldap_opts
+  foreach ($config_items as $item)
   {
-    $ldap = @ldap_connect($ldap_host, $ldap_port);
+    if (!isset($$item))
+    {
+      continue;
+    }
+    if (!is_array($$item))
+    {
+      $all_ldap_opts[$item] = array_fill(0, $count, $$item);
+    }
   }
-  else
-  {
-    $ldap = @ldap_connect($ldap_host);
-  }
 
-  // Check that connection was established
-  if ($ldap)
+  foreach ($all_ldap_opts['ldap_host'] as $idx => $host)
   {
-    authLdapDebug("authLdapAction: Got LDAP connection");
-
-    if ($ldap_v3)
+    // establish ldap connection
+    // the '@' suppresses errors
+    if (isset($all_ldap_opts['ldap_port'][$idx]))
     {
-      ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
+      $ldap = @ldap_connect($host, $all_ldap_opts['ldap_port'][$idx]);
     }
-    if ($ldap_tls)
+    else
     {
-      ldap_start_tls($ldap);
+      $ldap = @ldap_connect($host);
     }
 
-    // now process all base dn's until authentication is achieved
-    // or fail
-    foreach ( $all_ldap_base_dn as $idx => $base_dn)
+    // Check that connection was established
+    if ($ldap)
     {
-      authLdapDebug("authLdapAction: start of foreach $base_dn");
-      if (isset($ldap_dn_search_attrib))
+      authLdapDebug("authLdapAction: Got LDAP connection");
+
+      if (isset($all_ldap_opts['ldap_v3'][$idx]) &&
+          $all_ldap_opts['ldap_v3'][$idx])
       {
-        if (isset($ldap_dn_search_dn) &&
-            isset($ldap_dn_search_password))
+        ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
+      }
+      if (isset($all_ldap_opts['ldap_tls'][$idx]) &&
+          $all_ldap_opts['ldap_tls'][$idx])
+      {
+        ldap_start_tls($ldap);
+      }
+
+      if (isset($all_ldap_opts['ldap_dn_search_attrib'][$idx]))
+      {
+        if (isset($all_ldap_opts['ldap_dn_search_dn'][$idx]) &&
+            isset($all_ldap_opts['ldap_dn_search_password'][$idx]))
         {
           // Bind with DN and password
-          $res = @ldap_bind($ldap, $ldap_dn_search_dn,
-                            $ldap_dn_search_password);
+          $res = @ldap_bind($ldap, $all_ldap_opts['ldap_dn_search_dn'][$idx],
+                            $all_ldap_opts['ldap_dn_search_password'][$idx]);
         }
         else
         {
@@ -129,47 +160,57 @@
         if ($res)
         {
           $res = @ldap_search($ldap,
-                              $base_dn,
-                              "(". $ldap_dn_search_attrib ."=$user)");
+                              $all_ldap_opts['ldap_base_dn'][$idx],
+                              "(". 
$all_ldap_opts['ldap_dn_search_attrib'][$idx] ."=$user)");
 
           if (@ldap_count_entries($ldap, $res) == 1)
           {
-            authLdapDebug("authLdapAction: Found one entry using ".
-                          "$ldap_dn_search_attrib");
+            authLdapDebug("authLdapAction: Found one entry using '".
+                          $all_ldap_opts['ldap_dn_search_attrib'][$idx]."'");
             $entries = ldap_get_entries($ldap, $res);
             $dn = $entries[0]["dn"];
             $user_search = "distinguishedName=" . $dn;
           }
           else
           {
-            authLdapDebug("authLdapAction: Didn't find entry using ".
-                          "$ldap_dn_search_attrib");
+            authLdapDebug("authLdapAction: Didn't find entry using '".
+                          $all_ldap_opts['ldap_dn_search_attrib'][$idx]."'");
           }
-          authLdapDebug("authLdapAction: base_dn $base_dn user $user ".
-                        "dn $dn");
+          authLdapDebug("authLdapAction: base_dn '".
+                        $all_ldap_opts['ldap_base_dn'][$idx].
+                        "' user $user dn $dn");
         }
       }
       else
       {
         // construct dn for user
-        $user_search = $all_ldap_user_attrib[$idx] . "=" . $user;
-        $dn = $user_search . "," . $base_dn;
+        $user_search = $all_ldap_opts['ldap_user_attrib'][$idx] . "=" . $user;
+        $dn = $user_search . "," . $all_ldap_opts['ldap_base_dn'][$idx];
 
-        authLdapDebug("authLdapAction: Constructed dn $dn and ".
-                      "user_search $user_search using ".
-                      "\$ldap_user_attrib");
+        authLdapDebug("authLdapAction: Constructed dn '$dn' and ".
+                      "user_search '$user_search' using '".
+                      $all_ldap_opts['ldap_user_attrib'][$idx]."'");
       }
 
-      $res = $callback($ldap, $base_dn, $dn, $user_search, $user, $object);
+      foreach ($config_items as $item)
+      {
+        if (isset($all_ldap_opts[$item][$idx]))
+        {
+          $object['config'][$item] = $all_ldap_opts[$item][$idx];
+        }
+      }
+
+      $res = $callback($ldap, $all_ldap_opts['ldap_base_dn'][$idx], $dn,
+                       $user_search, $user, $object);
       if ($res)
       {
         return $res;
       }
 
-    } // foreach
+    } // if ($ldap)
 
     @ldap_unbind($ldap);
-  } // if ($ldap)
+  } // foreach
 }
 
 
@@ -216,23 +257,24 @@
 function authLdapGetEmailCallback(&$ldap, $base_dn, $dn, $user_search,
                                   $user, &$object)
 {
-  global $ldap_email_attrib;
+  $email_attrib = $object['config']['ldap_email_attrib'];
 
-  authLdapDebug("authLdapGetEmailCallback: base_dn $base_dn dn $dn ".
-                "user_search $user_search user $user");
+  authLdapDebug("authLdapGetEmailCallback: base_dn '$base_dn' dn '$dn' ".
+                "user_search '$user_search' user '$user'");
 
   if ($ldap && $base_dn && $dn && $user_search)
   {
-  $res = @ldap_read($ldap,
-                        $dn,
-                        "(objectclass=*)",
-                        array($ldap_email_attrib)
-                       );
+    $res = @ldap_read(
+                      $ldap,
+                      $dn,
+                      "(objectclass=*)",
+                      array(strtolower($email_attrib))
+                     );
     if (@ldap_count_entries($ldap, $res) > 0)
     {
       authLdapDebug("authLdapGetEmailCallback: search successful");
       $entries = ldap_get_entries($ldap, $res);
-      $object['email'] = $entries[0][$ldap_email_attrib][0];
+      $object['email'] = $entries[0][strtolower($email_attrib)][0];
 
       authLdapDebug("authLdapGetEmailCallback: email is '".
                     $object['email']."'");
@@ -243,6 +285,7 @@
   return 0;
 }
 
+
 /* authValidateUser($user, $pass)
  * 
  * Checks if the specified username/password pair are valid
@@ -291,19 +334,20 @@
 function authValidateUserCallback(&$ldap, $base_dn, $dn, $user_search,
                                   $user, &$object)
 {
-  global $ldap_filter;
+  authLdapDebug("authValidateUserCallback: base_dn '$base_dn' ".
+                "dn '$dn' user '$user'");
 
-  authLdapDebug("authValidateUserCallback: base_dn $base_dn dn $dn user 
$user");
-
   $pass = $object['pass'];
 
   // try an authenticated bind
   // use this to confirm that the user/password pair
   if ($dn && @ldap_bind($ldap, $dn, $pass))
   {
+    $filter = $object['config']['ldap_filter'];
+
     // however if there is a filter check that the
     // user is part of the group defined by the filter
-    if (! $ldap_filter)
+    if (! $filter)
     {
       authLdapDebug("authValidateUserCallback: Successful authenticated ".
                     "bind with no \$ldap_filter");
@@ -312,11 +356,11 @@
     else
     {
       authLdapDebug("authValidateUserCallback: Successful authenticated ".
-                    "bind checking $ldap_filter");
+                    "bind checking '$filter'");
 
       $res = @ldap_read($ldap,
                         $dn,
-                        "($ldap_filter)",
+                        "($filter)",
                         array()
                        );
       if (@ldap_count_entries($ldap, $res) > 0)
@@ -329,7 +373,7 @@
   }
   else
   {
-    authLdapDebug("authValidateUserCallback: Bind to $dn failed");
+    authLdapDebug("authValidateUserCallback: Bind to '$dn' failed");
   }
 
   if ($ldap_unbind_between_attempts)
@@ -341,6 +385,58 @@
   return 0;
 }
 
+
+/* authLdapCheckAdminGroupCallback(&$ldap, $base_dn, $dn, $user_search,
+                            $user, &$object)
+ * 
+ * Checks if the specified username is in an admin group
+ *
+ * &$ldap       - Reference to the LDAP object
+ * $base_dn     - The base DN
+ * $dn          - The user's DN
+ * $user_search - The LDAP filter to find the user
+ * $user        - The user name
+ * &$object     - Reference to the generic object
+ * 
+ * Returns:
+ *   0        - Not in the admin group
+ *   non-zero - In the admin group
+ */
+function authLdapCheckAdminGroupCallback(&$ldap, $base_dn, $dn, $user_search,
+                                         $user, &$object)
+{
+  $admin_group_dn = $object['config']['ldap_admin_group_dn'];
+  $group_member_attrib = $object['config']['ldap_group_member_attrib'];
+
+  authLdapDebug("authLdapCheckAdminGroupCallback: base_dn '$base_dn' ".
+                "dn '$dn' user_search '$user_search' user '$user'");
+
+  if ($ldap && $base_dn && $dn && $user_search)
+  {
+  $res = @ldap_read(
+                    $ldap,
+                    $dn,
+                    "(objectclass=*)",
+                    array(strtolower($group_member_attrib))
+                   );
+    if (@ldap_count_entries($ldap, $res) > 0)
+    {
+      authLdapDebug("authCheckAdminGroupCallback: search successful".
+                    " $group_member_attrib");
+      $entries = ldap_get_entries($ldap, $res);
+      foreach ($entries[0][strtolower($group_member_attrib)] as $group)
+      {
+        if (strcasecmp($group, $admin_group_dn) == 0)
+        {
+          return 1;
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+
 /* authGetUserLevel($user)
  *
  * Determines the users access level
@@ -353,17 +449,32 @@
 function authGetUserLevel($user)
 {
   global $auth;
+  global $ldap_admin_group_dn;
+
   $admins = $auth['admin'];
   // User not logged in, user level '0'
   if (!isset($user))
   {
     return 0;
   }
+  
+  if ($ldap_admin_group_dn)
+  {
+    $res = authLdapAction("authLdapCheckAdminGroupCallback", $user, $object);
+    if ($res)
+    {
+      return 2;
+    }
+    else
+    {
+      return 1;
+    }
+  }
     
-  // Check if the user is can modify
-  for ($i = 0; $admins[$i]; $i++)
+  // Check if the user is an admin
+  foreach ($admins as $admin)
   {
-    if (strcasecmp($user, $admins[$i]) == 0)
+    if (strcasecmp($user, $admin) == 0)
     {
       return 2;
     }
@@ -373,6 +484,7 @@
   return 1;
 }
 
+
 /* authLdapDebug($message)
  *
  * Output LDAP debugging, if the configuration variable

Modified: mrbs/trunk/web/functions.inc
===================================================================
--- mrbs/trunk/web/functions.inc        2011-09-22 09:56:45 UTC (rev 1995)
+++ mrbs/trunk/web/functions.inc        2011-09-22 14:41:57 UTC (rev 1996)
@@ -567,7 +567,7 @@
 // errors which "should never happen", not those caused by bad inputs.
 // If $need_header!=0 output the top of the page too, else assume the
 // caller did that. Alway outputs the bottom of the page and exits.
-function fatal_error($need_header, $message)
+function fatal_error($need_header, $message, $show_form_data = true)
 {
   global $simple_trailer, $weekstarts, $view_week_number, $strftime_format;
   
@@ -576,12 +576,22 @@
     print_header(0, 0, 0, 0, "");
   }
   error_log("MRBS: ".$message);
-  if (!empty($_GET))
-    error_log("MRBS GET: ".print_r($_GET, true));
-  if (!empty($_POST))
-    error_log("MRBS POST: ".print_r($_POST, true));
+
+  if ($show_form_data)
+  {
+    if (!empty($_GET))
+    {
+      error_log("MRBS GET: ".print_r($_GET, true));
+    }
+    if (!empty($_POST))
+    {
+      error_log("MRBS POST: ".print_r($_POST, true));
+    }
+  }
   if (!empty($_SESSION))
+  {
     error_log("MRBS SESSION: ".print_r($_SESSION, true));
+  }
   echo "<p>$message</p>";
   require_once "trailer.inc";
   exit;

Modified: mrbs/trunk/web/systemdefaults.inc.php
===================================================================
--- mrbs/trunk/web/systemdefaults.inc.php       2011-09-22 09:56:45 UTC (rev 
1995)
+++ mrbs/trunk/web/systemdefaults.inc.php       2011-09-22 14:41:57 UTC (rev 
1996)
@@ -602,43 +602,77 @@
 $auth['db_ext']['password_format'] = 'md5';
 
 // 'auth_ldap' configuration settings
-// Where is the LDAP server
+
+// Many of the LDAP parameters can be specified as arrays, in order to
+// specify multiple LDAP directories to search within. Each item below
+// will specify whether the item can be specified as an array. If any
+// parameter is specified as an array, then EVERY array configuration
+// parameter must have the same number of elements. You can specify a
+// parameter as an array as in the following example:
+//
+// $ldap_host = array('localhost', 'otherhost.example.com');
+
+// Where is the LDAP server.
+// This can be an array.
 //$ldap_host = "localhost";
-// If you have a non-standard LDAP port, you can define it here
+
+// If you have a non-standard LDAP port, you can define it here.
+// This can be an array.
 //$ldap_port = 389;
-// If you do not want to use LDAP v3, change the following to false
+
+// If you do not want to use LDAP v3, change the following to false.
+// This can be an array.
 $ldap_v3 = true;
-// If you want to use TLS, change the following to true
+
+// If you want to use TLS, change the following to true.
+// This can be an array.
 $ldap_tls = false;
-// LDAP base distinguish name
-// See AUTHENTICATION for details of how check against multiple base dn's
+
+// LDAP base distinguish name.
+// This can be an array.
 //$ldap_base_dn = "ou=organizationalunit,dc=my-domain,dc=com";
+
 // Attribute within the base dn that contains the username
+// This can be an array.
 //$ldap_user_attrib = "uid";
+
 // If you need to search the directory to find the user's DN to bind
 // with, set the following to the attribute that holds the user's
 // "username". In Microsoft AD directories this is "sAMAccountName"
+// This can be an array.
 //$ldap_dn_search_attrib = "sAMAccountName";
+
 // If you need to bind as a particular user to do the search described
 // above, specify the DN and password in the variables below
+// These two parameters can be arrays.
 // $ldap_dn_search_dn = "cn=Search User,ou=Users,dc=some,dc=company";
 // $ldap_dn_search_password = "some-password";
 
 // 'auth_ldap' extra configuration for ldap configuration of who can use
 // the system
-// If it's set, the $ldap_filter will be combined with the value of
-// $ldap_user_attrib like this:
-//   (&($ldap_user_attrib=username)($ldap_filter))
-// After binding to check the password, this check is used to see that
-// they are a valid user of mrbs.
-//$ldap_filter = "mrbsuser=y";
+// If it's set, the $ldap_filter will be used to determine whether a
+// user will be granted access to MRBS
+// This can be an array.
+// An example for Microsoft AD:
+//$ldap_filter = "memberof=cn=whater,ou=whatver,dc=example,dc=com";
 
 // Set to TRUE to tell MRBS to look up a user's email address in LDAP.
 // Utilises $ldap_email_attrib below
 $ldap_get_user_email = FALSE;
 // The LDAP attribute which holds a user's email address
+// This can be an array.
 $ldap_email_attrib = 'mail';
 
+// The DN of the LDAP group that MRBS admins must be in. If this is defined
+// then the $auth["admin"] is not used.
+// This can be an array.
+// $ldap_admin_group_dn = 'cn=admins,ou=whoever,dc=example,dc=com';
+
+// The LDAP attribute that holds group membership details. Used with
+// $ldap_admin_group_dn, above.
+// This can be an array.
+$ldap_group_member_attrib = 'memberof';
+  
 // Set to TRUE if you want MRBS to call ldap_unbind() between successive
 // attempts to bind. Unbinding while still connected upsets some
 // LDAP servers

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense.
http://p.sf.net/sfu/splunk-d2dcopy1
_______________________________________________
Mrbs-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mrbs-commits

Reply via email to