diff --git a/ajax/ajax_checkConnection.php b/ajax/ajax_checkConnection.php index 9379f369..3e9991b0 100644 --- a/ajax/ajax_checkConnection.php +++ b/ajax/ajax_checkConnection.php @@ -23,7 +23,7 @@ * */ -use SP\Auth\Ldap; +use SP\Auth\Ldap\Ldap; use SP\Core\Init; use SP\Core\SessionUtil; use SP\Http\Request; diff --git a/ajax/ajax_doLogin.php b/ajax/ajax_doLogin.php index 30d8b170..f147d908 100644 --- a/ajax/ajax_doLogin.php +++ b/ajax/ajax_doLogin.php @@ -24,7 +24,7 @@ */ use SP\Auth\Auth; -use SP\Auth\Ldap; +use SP\Auth\Ldap\Ldap; use SP\Core\CryptMasterPass; use SP\Core\Init; use SP\Core\Language; @@ -36,7 +36,6 @@ use SP\DataModel\UserData; use SP\DataModel\UserPassRecoverData; use SP\Http\JsonResponse; use SP\Http\Request; -use SP\Http\Response; use SP\Log\Log; use SP\Mgmt\Groups\Group; use SP\Mgmt\Profiles\Profile; diff --git a/inc/SP/Auth/Auth.class.php b/inc/SP/Auth/Auth.class.php index 254e2782..d1b6b57c 100644 --- a/inc/SP/Auth/Auth.class.php +++ b/inc/SP/Auth/Auth.class.php @@ -26,6 +26,8 @@ namespace SP\Auth; +use SP\Auth\Ldap\Ldap; +use SP\Auth\Ldap\LdapADS; use SP\Config\Config; use SP\Core\Exceptions\SPException; use SP\DataModel\UserData; diff --git a/inc/SP/Auth/Ldap.class.php b/inc/SP/Auth/Ldap/Ldap.class.php similarity index 99% rename from inc/SP/Auth/Ldap.class.php rename to inc/SP/Auth/Ldap/Ldap.class.php index 75aaa079..56fb28f4 100644 --- a/inc/SP/Auth/Ldap.class.php +++ b/inc/SP/Auth/Ldap/Ldap.class.php @@ -24,7 +24,7 @@ * */ -namespace SP\Auth; +namespace SP\Auth\Ldap; use SP\Config\Config; use SP\Log\Log; diff --git a/inc/SP/Auth/LdapADS.class.php b/inc/SP/Auth/Ldap/LdapADS.class.php similarity index 98% rename from inc/SP/Auth/LdapADS.class.php rename to inc/SP/Auth/Ldap/LdapADS.class.php index 9f90103c..944589f0 100644 --- a/inc/SP/Auth/LdapADS.class.php +++ b/inc/SP/Auth/Ldap/LdapADS.class.php @@ -23,8 +23,9 @@ * */ -namespace SP\Auth; +namespace SP\Auth\Ldap; +use SP\Auth\Ldap\Ldap; use SP\Config\Config; use SP\Log\Log; diff --git a/inc/SP/Auth/Ldap/LdapBase.class.php b/inc/SP/Auth/Ldap/LdapBase.class.php new file mode 100644 index 00000000..e9b96601 --- /dev/null +++ b/inc/SP/Auth/Ldap/LdapBase.class.php @@ -0,0 +1,248 @@ +isLdapAds(); + $this->searchBase = Config::getConfig()->getLdapBase(); +// $this->server = (!self::$isADS) ? Config::getConfig()->getLdapServer() : LdapADS::getADServer(Config::getConfig()->getLdapServer()); + $this->server = $this->pickServer(); + $this->bindDn = Config::getConfig()->getLdapBindUser(); + $this->bindPass = Config::getConfig()->getLdapBindPass(); + $this->group = Config::getConfig()->getLdapGroup(); + + if (!$this->searchBase || !$this->server || !$this->bindDn || !$this->bindPass) { + Log::writeNewLog(__FUNCTION__, _('Los parámetros de LDAP no están configurados')); + + return false; + } + + return true; + } + + /** + * Obtener el RDN del grupo. + * + * @throws \Exception + * @return string con el RDN del grupo + */ + protected function searchGroupDN() + { + $Log = new Log(__FUNCTION__); + $filter = $this->searchGroupDN() ?: $this->group; + $filter = '(cn=' . $filter . ')'; + $filterAttr = ["dn", "cn"]; + + $searchRes = @ldap_search($this->ldapHandler, $this->searchBase, $filter, $filterAttr); + + if (!$searchRes) { + $Log->setLogLevel(Log::ERROR); + $Log->addDescription(_('Error al buscar RDN de grupo')); + $Log->addDetails(_('Grupo'), $filter); + $Log->addDetails('LDAP ERROR', sprintf('%s (%d)', ldap_error($this->ldapHandler), ldap_errno($this->ldapHandler))); + $Log->addDetails('LDAP FILTER', $filter); + $Log->writeLog(); + + throw new \Exception(_('Error al buscar RDN de grupo')); + } + + if (@ldap_count_entries($this->ldapHandler, $searchRes) === 1) { + $ldapSearchData = @ldap_get_entries($this->ldapHandler, $searchRes); + + if (!$ldapSearchData) { + $Log->setLogLevel(Log::ERROR); + $Log->addDescription(_('Error al buscar RDN de grupo')); + $Log->addDetails(_('Grupo'), $filter); + $Log->addDetails('LDAP ERROR', sprintf('%s (%d)', ldap_error($this->ldapHandler), ldap_errno($this->ldapHandler))); + $Log->writeLog(); + + throw new \Exception(_('Error al buscar RDN de grupo')); + } + + return $ldapSearchData[0]["dn"]; + } else { + $Log->setLogLevel(Log::ERROR); + $Log->addDescription(_('Error al buscar RDN de grupo')); + $Log->addDetails(_('Grupo'), $filter); + $Log->addDetails('LDAP FILTER', $filter); + $Log->writeLog(); + + throw new \Exception(_('Error al buscar RDN de grupo')); + } + } + + /** + * Obtener el nombre del grupo a partir del CN + * + * @return bool + */ + protected function getGroupName() + { + if (isset($this->group) && preg_match('/^cn=([\w\s-]+),.*/i', $this->group, $groupName)) { + return $groupName[1]; + } + + return false; + } + + /** + * Escapar carácteres especiales en el RDN de LDAP. + * + * @param string $dn con el RDN del usuario + * @return string + */ + protected function escapeLdapDN($dn) + { + $chars = array('/(,)(?!uid|cn|ou|dc)/i', '/(?)/', '/(<)/', '/(\+)/', '/(#)/', '/\G(\s)/', '/(\s)(?=\s*$)/', '/(\/)/'); + return preg_replace($chars, '\\\$1', $dn); + } + + /** + * Realizar la desconexión del servidor de LDAP. + */ + public function unbind() + { + @ldap_unbind($this->ldapHandler); + } + + /** + * Obtener el filtro para buscar el usuario + * + * @param string $userLogin Login del usuario + * @return mixed + */ + protected abstract function getUserDnFilter($userLogin); + + /** + * Obtener el RDN del usuario que realiza el login. + * + * @param string $userLogin Login del usuario + * @return array + * @throws \Exception + */ + public function getUserDN($userLogin) + { + $Log = new Log(__FUNCTION__); + +// if (self::$isADS === true) { +// $filter = '(&(|(samaccountname=' . $userLogin . ')(cn=' . $userLogin . ')(uid=' . $userLogin . '))(|(objectClass=inetOrgPerson)(objectClass=person)(objectClass=simpleSecurityObject))(objectCategory=person))'; +// } else { +// $filter = '(&(|(samaccountname=' . $userLogin . ')(cn=' . $userLogin . ')(uid=' . $userLogin . '))(|(objectClass=inetOrgPerson)(objectClass=person)(objectClass=simpleSecurityObject)))'; +// } + + $filterAttr = array("dn", "displayname", "samaccountname", "mail", "memberof", "lockouttime", "fullname", "groupmembership", "mail"); + + $searchRes = @ldap_search($this->ldapHandler, $this->searchBase, $this->getUserDnFilter($userLogin), $filterAttr); + + if (!$searchRes) { + $Log->setLogLevel(Log::ERROR); + $Log->addDescription(_('Error al buscar el DN del usuario')); + $Log->addDetails(_('Usuario'), $userLogin); + $Log->addDetails('LDAP ERROR', sprintf('%s (%d)', ldap_error($this->ldapHandler), ldap_errno($this->ldapHandler))); + $Log->addDetails('LDAP FILTER', $this->getUserDnFilter()); + $Log->writeLog(); + + throw new \Exception(_('Error al buscar el DN del usuario')); + } + + if (@ldap_count_entries($this->ldapHandler, $searchRes) === 1) { + $ldapSearchData = @ldap_get_entries($this->ldapHandler, $searchRes); + + if (!$ldapSearchData) { + $Log->setLogLevel(Log::ERROR); + $Log->addDescription(_('Error al localizar el usuario en LDAP')); + $Log->addDetails(_('Usuario'), $userLogin); + $Log->addDetails('LDAP ERROR', sprintf('%s (%d)', ldap_error($this->ldapHandler), ldap_errno($this->ldapHandler))); + $Log->writeLog(); + + throw new \Exception(_('Error al localizar el usuario en LDAP')); + } + } else { + $Log->setLogLevel(Log::ERROR); + $Log->addDescription(_('Error al buscar el DN del usuario')); + $Log->addDetails(_('Usuario'), $userLogin); + $Log->addDetails('LDAP FILTER', $this->getUserDnFilter()); + $Log->writeLog(); + + throw new \Exception(_('Error al buscar el DN del usuario')); + } + + return $ldapSearchData; + } + + /** + * Obtener el servidor de LDAP a utilizar + * + * @return mixed + */ + protected abstract function pickServer(); + + /** + * Realizar una búsqueda de objetos en la ruta indicada. + * + * @throws \Exception + * @return int El número de resultados + */ + protected function searchBase() + { + $Log = new Log(__FUNCTION__); + + $groupDN = (!empty($this->group)) ? $this->searchGroupDN() : '*'; + $filter = '(&(|(memberOf=' . $groupDN . ')(groupMembership=' . $groupDN . '))(|(objectClass=inetOrgPerson)(objectClass=person)(objectClass=simpleSecurityObject)))'; + $filterAttr = ["dn"]; + + $searchRes = @ldap_search($this->ldapHandler, $this->searchBase, $filter, $filterAttr); + + if (!$searchRes) { + $Log->setLogLevel(Log::ERROR); + $Log->addDescription(_('Error al buscar objetos en DN base')); + $Log->addDetails('LDAP ERROR', sprintf('%s (%d)', ldap_error($this->ldapHandler), ldap_errno($this->ldapHandler))); + $Log->addDetails('LDAP FILTER', $filter); + $Log->writeLog(); + + throw new \Exception(_('Error al buscar objetos en DN base')); + } + + return @ldap_count_entries($this->ldapHandler, $searchRes); + } +} \ No newline at end of file diff --git a/inc/SP/Auth/Ldap/LdapInterface.class.php b/inc/SP/Auth/Ldap/LdapInterface.class.php new file mode 100644 index 00000000..3e372dca --- /dev/null +++ b/inc/SP/Auth/Ldap/LdapInterface.class.php @@ -0,0 +1,58 @@ +