viewgit/inc/functions.php:22 Function utf8_encode() is deprecated [8192]

Add preliminary support for LDAP authentication

Chris Pollett [2024-06-25 23:Jun:th]
Add preliminary support for LDAP authentication
Filename
src/controllers/AdminController.php
src/models/SigninModel.php
src/models/UserModel.php
src/views/elements/ManageaccountElement.php
diff --git a/src/controllers/AdminController.php b/src/controllers/AdminController.php
index f78420ecb..8982f0841 100755
--- a/src/controllers/AdminController.php
+++ b/src/controllers/AdminController.php
@@ -138,13 +138,12 @@ class AdminController extends Controller implements CrawlConstants
                     tl('admin_controller_need_cookies') . "</h1>');";
                 unset($_SESSION['USER_ID']);
             } else if ($this->checkSignin()) {
-                $_SESSION['USER_NAME'] = $_REQUEST['u'];
+                $username = $this->clean($_REQUEST['u'], "string");
+                $_SESSION['USER_NAME'] = $username;
                 // successful login.
-                $user_id = $this->model("signin")->getUserId(
-                    $this->clean($_REQUEST['u'], "string"));
+                $user_id = $this->model("signin")->getUserId($username);
                 $session = $this->model("user")->getUserSession($user_id);
                 $last_activity = [];
-                $_SESSION['USER_NAME'] = $_REQUEST['u'];
                 if (isset($_SESSION['LAST_ACTIVITY']) &&
                     is_array($_SESSION['LAST_ACTIVITY'])) {
                     $_REQUEST = array_merge($_REQUEST,
@@ -242,10 +241,11 @@ class AdminController extends Controller implements CrawlConstants
     public function checkSignin()
     {
         $result = false;
+        $username = $this->clean($_REQUEST['u'], "string");
+        $password = $this->clean($_REQUEST['p'], "string");
         if (isset($_REQUEST['u']) && isset($_REQUEST['p']) ) {
             $result = $this->model("signin")->checkValidSignin(
-                $this->clean($_REQUEST['u'], "string"),
-                $this->clean($_REQUEST['p'], "string") );
+                $username, $password);
         }
         return $result;
     }
diff --git a/src/models/SigninModel.php b/src/models/SigninModel.php
index 37968441d..21fc5ab47 100755
--- a/src/models/SigninModel.php
+++ b/src/models/SigninModel.php
@@ -30,6 +30,7 @@
  */
 namespace seekquarry\yioop\models;

+use seekquarry\yioop\configs as C;
 use seekquarry\yioop\library as L;

 /**
@@ -44,22 +45,68 @@ class SigninModel extends Model
      * Checks that a username password pair is valid. This function
      * is slow because the underlying crypt to slow
      *
-     * @param string $username the username to check
+     * @param string &$username the username to check - username might
+     *      be changed to a local username if LDAP being used
      * @param string $password the password to check
      * @return bool  where the password is that of the given user
      *     (or at least hashes to the same thing)
      */
-    public function checkValidSignin($username, $password)
+    public function checkValidSignin(&$username, $password)
     {
         $db = $this->db;
-        $row = $this->getUserDetails($username);
-        $start_time = microtime(true);
-        if ($row) {
-            $crypt_password = L\crawlCrypt($password, $row['PASSWORD']);
-            $valid_password = ($crypt_password == $row['PASSWORD']);
-        } else {
-            $crypt_password = L\crawlCrypt($password);
-            $valid_password = false;
+        $use_ldap = false;
+        $have_ldap_mapping = false;
+        $valid_password = false;
+        if (C\nsdefined("USE_LDAP") && C\USE_LDAP) {
+            $have_ldap_mapping = function_exists(C\LDAP_LOCAL_NAME);
+            $use_ldap = true;
+            $num_controllers = count(C\LDAP_CONTROLLERS);
+            $domain_controller = C\LDAP_CONTROLLERS[rand(0,
+                $num_controllers - 1)];
+            $account_suffix = C\LDAP_ACCOUNT_SUFFIX;
+            if ($connection = ldap_connect("ldaps://" . $domain_controller)) {
+                ldap_start_tls($connection);
+                $ldap_name = $_SESSION["LDAP_NAME"][$username] ?? $username;
+                if ($valid_password = ldap_bind($connection,
+                    $ldap_name . $account_suffix, $password) &&
+                    $have_ldap_mapping) {
+                    $email = "";
+                    $email = "";
+                    $display_name = "";
+                    $fields = ["mail", "displayname"];
+                    $filter = "samaccountname=" . $ldap_name;
+                    $filter = "(&(objectCategory=person)({$filter}))";
+                    if ($results = ldap_search($connection,
+                        C\LDAP_BASE_DOMAIN, $filter, $fields)) {
+                        $entries = ldap_get_entries($connection, $results);
+                        $email = $entries[0]['mail'][0] ?? "";
+                        $display_name = $entries[0]['displayname'][0] ?? "";
+                    }
+                    $username = C\LDAP_LOCAL_USER($ldap_name, $email,
+                        $display_name);
+                    if (empty($username)) {
+                        $valid_password = false;
+                    }
+                    if (!empty($username)) {
+                        $_SESSION["LDAP_NAME"] ??=  [];
+                        $_SESSION["LDAP_NAME"][$username] = $ldap_name;
+                        $_REQUEST['u'] = $username;
+                    }
+                }
+            }
+        }
+        if (!$use_ldap || (!$valid_password && $use_ldap &&
+            (!$have_ldap_mapping || ($have_ldap_mapping && !empty($username))
+            ))) {
+            $row = $this->getUserDetails($username);
+            $start_time = microtime(true);
+            if ($row) {
+                $crypt_password = L\crawlCrypt($password, $row['PASSWORD']);
+                $valid_password = ($crypt_password == $row['PASSWORD']);
+            } else {
+                $crypt_password = L\crawlCrypt($password);
+                $valid_password = false;
+            }
         }
         // crude avoid timing attacks if possible
         $micro_delta = L\changeInMicrotime($start_time);
diff --git a/src/models/UserModel.php b/src/models/UserModel.php
index 5861654d3..784da4aa5 100755
--- a/src/models/UserModel.php
+++ b/src/models/UserModel.php
@@ -441,12 +441,12 @@ class UserModel extends Model
      * Deletes a user by username from the list of users that can login to
      * the admin panel
      *
-     * @param string $user_name  the login name of the user to delete
+     * @param string $username  the login name of the user to delete
      */
-    public function deleteUser($user_name)
+    public function deleteUser($username)
     {
         $db = $this->db;
-        $user_id = $this->getUserId($user_name);
+        $user_id = $this->getUserId($username);
         if ($user_id) {
             $sql = "DELETE FROM USER_ROLE WHERE USER_ID=?";
             $result = $db->execute($sql, [$user_id]);
diff --git a/src/views/elements/ManageaccountElement.php b/src/views/elements/ManageaccountElement.php
index fcd7a8f33..113397ebe 100755
--- a/src/views/elements/ManageaccountElement.php
+++ b/src/views/elements/ManageaccountElement.php
@@ -292,7 +292,8 @@ class ManageaccountElement extends Element
                 name="password"  maxlength="<?= C\LONG_NAME_LEN
                 ?>" class="narrow-field" >
             </td></tr><?php
-        } else if (!empty($data['EDIT_PASSWORD'])) { ?>
+        } else if (!empty($data['EDIT_PASSWORD']) &&
+            empty($_SESSION['LDAP_NAME'])) { ?>
             <tr><th class="table-label"><label for="password"><?php
             e(tl('manageaccount_element_password'))?></label></th>
             <td><input type="password" id="password"
@@ -312,7 +313,7 @@ class ManageaccountElement extends Element
                     name="retype_password"  maxlength="<?=
                     C\LONG_NAME_LEN?>" class="narrow-field" >
                 </td></tr><?php
-        } else {
+        } else if (empty($_SESSION['LDAP_NAME'])) {
             $question_sets = [];
             if (C\RECOVERY_MODE == C\EMAIL_AND_QUESTIONS_RECOVERY) {
             $question_sets = [
@@ -356,7 +357,8 @@ class ManageaccountElement extends Element
         <td class="center"><button
             class="button-box" type="submit"><?php
             e(tl('manageaccount_element_save')); ?></button></td></tr><?php
-        if (empty($data['EDIT_PASSWORD']) && empty($data['EDIT_RECOVERY'])) { ?>
+        if (empty($data['EDIT_PASSWORD']) && empty($data['EDIT_RECOVERY'])
+            && empty($_SESSION['LDAP_NAME'])) { ?>
             <tr><td>&nbsp;</td><td></td></tr>
             <tr><td></td><td><a href="<?php
                 e($password_or_no_url);?>"><?php
ViewGit