Subversion Repositories php_utils

Rev

Rev 77 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * VtsLDAPUtils - Simple LDAP helper functions
  5.  * Copyright 2021 - 2023 Daniel Marschall, ViaThinkSoft
  6.  * Revision: 2023-11-30
  7.  *
  8.  * Licensed under the Apache License, Version 2.0 (the "License");
  9.  * you may not use this file except in compliance with the License.
  10.  * You may obtain a copy of the License at
  11.  *
  12.  *     http://www.apache.org/licenses/LICENSE-2.0
  13.  *
  14.  * Unless required by applicable law or agreed to in writing, software
  15.  * distributed under the License is distributed on an "AS IS" BASIS,
  16.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17.  * See the License for the specific language governing permissions and
  18.  * limitations under the License.
  19.  */
  20.  
  21. class VtsLDAPUtils {
  22.  
  23.         protected $conn = null;
  24.  
  25.         private static function _L(string $str, ...$sprintfArgs): string {
  26.                 if (function_exists('_L')) {
  27.                         return _L($str, $sprintfArgs);
  28.                 } else if (function_exists('my_vsprintf')) {
  29.                         return my_vsprintf($str, $sprintfArgs);
  30.                 } else {
  31.                         $n = 1;
  32.                         foreach ($sprintfArgs as $val) {
  33.                                 $str = str_replace("%$n", $val, $str);
  34.                                 $n++;
  35.                         }
  36.                         $str = str_replace("%%", "%", $str);
  37.                         return $str;
  38.                 }
  39.         }
  40.  
  41.         public static function getString($ldap_userinfo, $attributeName) {
  42.                 $ary = self::getArray($ldap_userinfo, $attributeName);
  43.                 return implode("\n", $ary);
  44.         }
  45.  
  46.         public static function getArray($ldap_userinfo, $attributeName) {
  47.                 $ary = array();
  48.                 if (isset($ldap_userinfo[$attributeName])) {
  49.                         $cnt = $ldap_userinfo[$attributeName]['count'];
  50.                         for ($i=0; $i<$cnt; $i++) {
  51.                                 $ary[] = $ldap_userinfo[$attributeName][$i];
  52.                         }
  53.                 }
  54.                 return $ary;
  55.         }
  56.  
  57.         public function isMemberOfRec($userDN, $groupDN) {
  58.  
  59.                 if (isset($userDN['dn'])) $userDN = $userDN['dn'];
  60.                 if (isset($groupDN['dn'])) $groupDN = $groupDN['dn'];
  61.  
  62.                 if (!$this->conn) throw new Exception('LDAP not connected');
  63.                 $res = ldap_read($this->conn, $groupDN, "(objectClass=*)");
  64.                 if (!$res) return false;
  65.                 $entries = ldap_get_entries($this->conn, $res);
  66.                 if (!isset($entries[0])) return false;
  67.                 if (!isset($entries[0]['member'])) return false;
  68.                 if (!isset($entries[0]['member']['count'])) return false;
  69.                 $cntMember = $entries[0]['member']['count'];
  70.                 for ($iMember=0; $iMember<$cntMember; $iMember++) {
  71.                         $groupOrUser = $entries[0]['member'][$iMember];
  72.                         if (strtolower($groupOrUser) == strtolower($userDN)) return true;
  73.                         if ($this->isMemberOfRec($userDN, $groupOrUser)) return true;
  74.                 }
  75.                 return false;
  76.         }
  77.  
  78.         public function __destruct() {
  79.                 $this->disconnect();
  80.         }
  81.  
  82.         public function disconnect() {
  83.                 if ($this->conn) {
  84.                         //ldap_unbind($this->conn); // commented out because ldap_unbind() kills the link descriptor
  85.                         ldap_close($this->conn);
  86.                         $this->conn = null;
  87.                 }
  88.         }
  89.  
  90.         public function connect($cfg_ldap_server, $cfg_ldap_port=389) {
  91.                 $this->disconnect();
  92.  
  93.                 // Connect to the server
  94.                 if (strpos($cfg_ldap_server, '://') !== false) {
  95.                         // e.g. ldap://hostname:port or ldaps://hostname:port
  96.                         $uri = $cfg_ldap_server;
  97.                 } else {
  98.                         $secure = ($cfg_ldap_port == 636) || ($cfg_ldap_port == 3268) || ($cfg_ldap_port == 3269);
  99.                         $schema = $secure ? 'ldaps' : 'ldap';
  100.                         $uri =  $schema . '://' . $cfg_ldap_server . ':' . $cfg_ldap_port;
  101.                 }
  102.                 if (!($ldapconn = @ldap_connect($uri))) throw new Exception(self::_L('Cannot connect to LDAP server'));
  103.  
  104.                 ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
  105.                 ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
  106.  
  107.                 $this->conn = $ldapconn;
  108.         }
  109.  
  110.         public function login($username, $password) {
  111.                 return @ldap_bind($this->conn, $username, $password);
  112.         }
  113.  
  114.         public function getUserInfo($userPrincipalName, $cfg_ldap_base_dn) {
  115.                 $cfg_ldap_user_filter = "(&(objectClass=user)(objectCategory=person)(userPrincipalName=".ldap_escape($userPrincipalName, '', LDAP_ESCAPE_FILTER)."))";
  116.  
  117.                 if (!($result = @ldap_search($this->conn,$cfg_ldap_base_dn, $cfg_ldap_user_filter))) throw new Exception(self::_L('Error in search query: %1', ldap_error($this->conn)));
  118.                 $data = ldap_get_entries($this->conn, $result);
  119.                 $ldap_userinfo = array();
  120.  
  121.                 if ($data['count'] == 0) return false; /* @phpstan-ignore-line */
  122.                 $ldap_userinfo = $data[0];
  123.  
  124.                 // empty($ldap_userinfo) can happen if the user did not log-in using their correct userPrincipalName (e.g. "username@domainname" instead of "username@domainname.local")
  125.                 return empty($ldap_userinfo) ? false : $ldap_userinfo;
  126.         }
  127.  
  128. }
  129.