diff --git a/ajax/ajax_doLogin.php b/ajax/ajax_doLogin.php index 346d1098..58b4b1df 100644 --- a/ajax/ajax_doLogin.php +++ b/ajax/ajax_doLogin.php @@ -36,18 +36,18 @@ $userLogin = SP_Common::parseParams('p', 'user'); $userPass = SP_Common::parseParams('p', 'pass'); $masterPass = SP_Common::parseParams('p', 'mpass'); -if (!$userLogin OR !$userPass) { +if (!$userLogin || !$userPass) { SP_Common::printJSON(_('Usuario/Clave no introducidos')); } +$resLdap = SP_Auth::authUserLDAP($userLogin,$userPass); + $objUser = new SP_Users; -$objUser->userLogin = SP_Auth::$userLogin = $userLogin; -$objUser->userPass = SP_Auth::$userPass = $userPass; +$objUser->userLogin = $userLogin; +$objUser->userPass = $userPass; $objUser->userName = SP_Auth::$userName; $objUser->userEmail = SP_Auth::$userEmail; -$resLdap = SP_Auth::authUserLDAP(); - // Autentificamos por LDAP if ($resLdap == 1) { $message['action'] = _('Inicio sesión (LDAP)'); @@ -71,6 +71,7 @@ if ($resLdap == 1) { } } } else if ($resLdap == 49) { + $message['action'] = _('Inicio sesión (LDAP)'); $message['text'][] = _('Login incorrecto'); $message['text'][] = _('Usuario') . ": " . $userLogin; $message['text'][] = _('IP') . ": " . $_SERVER['REMOTE_ADDR']; @@ -81,7 +82,7 @@ if ($resLdap == 1) { $message['action'] = _('Inicio sesión (MySQL)'); // Autentificamos con la BBDD - if (!SP_Auth::authUserMySQL()) { + if (!SP_Auth::authUserMySQL($userLogin,$userPass)) { $message['text'][] = _('Login incorrecto'); $message['text'][] = _('Usuario') . ": " . $userLogin; $message['text'][] = _('IP') . ": " . $_SERVER['REMOTE_ADDR']; @@ -92,7 +93,7 @@ if ($resLdap == 1) { } // Comprobar si el usuario está deshabilitado -if (SP_Auth::checkUserIsDisabled()) { +if (SP_Auth::checkUserIsDisabled($userLogin)) { $message['text'][] = _('Usuario deshabilitado'); $message['text'][] = _('Usuario') . ": " . $userLogin; $message['text'][] = _('IP') . ": " . $_SERVER['REMOTE_ADDR']; @@ -139,9 +140,7 @@ if ($objUser->getUserMPass()) { } } - if ( isset($params) ){ - $urlParams = '?'.implode('&', $params); - } + $urlParams = isset($params) ? '?'.implode('&', $params) : ''; SP_Common::printJSON('index.php'.$urlParams, 0); } diff --git a/inc/auth.class.php b/inc/auth.class.php index 55b52b74..e7c08d39 100644 --- a/inc/auth.class.php +++ b/inc/auth.class.php @@ -30,134 +30,101 @@ defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo' */ class SP_Auth { - static $userLogin; - static $userPass; static $userName; static $userEmail; /** * @brief Autentificación de usuarios con LDAP + * @param string $userLogin con el login del usuario + * @param string $userPass con la clave del usuario * @return bool */ - public static function authUserLDAP() { - if (SP_Config::getValue('ldapenabled', 0) === 0 || !SP_Util::ldapIsAvailable()) { - return FALSE; - } - - $searchBase = SP_Config::getValue('ldapbase'); - $ldapserver = SP_Config::getValue('ldapserver'); - $ldapgroup = SP_Config::getValue('ldapgroup'); - $bindDN = SP_Config::getValue('ldapbinduser'); - $bindPass = SP_Config::getValue('ldapbindpass'); - - if (!$searchBase || !$ldapserver || !$ldapgroup || !$bindDN || !$bindPass) { + public static function authUserLDAP($userLogin, $userPass) { + if (!SP_Util::ldapIsAvailable() + || !SP_Config::getValue('ldapenabled', FALSE) + || !SP_LDAP::checkLDAPParams()) { return FALSE; } $ldapAccess = FALSE; $message['action'] = __FUNCTION__; - // Conexión al servidor LDAP - if (!$ldapConn = @ldap_connect($ldapserver)) { - $message['text'][] = _('No es posible conectar con el servidor de LDAP') . " '" . $ldapserver . "'"; - $message['text'][] = 'LDAP ERROR: ' . ldap_error($ldapConn) . '(' . ldap_errno($ldapConn) . ')'; + // Conectamos al servidor realizamos la conexión con el usuario proxy + try { + SP_LDAP::connect(); + SP_LDAP::bind(); + SP_LDAP::getUserDN($userLogin); + } catch (Exception $e) { + return FALSE; + } + + $userDN = SP_LDAP::$ldapSearchData[0]['dn']; + // Mapeo de los atributos + $attribsMap = array( + 'groupmembership' => 'group', + 'memberof' => 'group', + 'displayname' => 'name', + 'fullname' => 'name', + 'mail' => 'mail', + 'lockouttime' => 'expire'); + + // Realizamos la conexión con el usuario real y obtenemos los atributos + try{ + SP_LDAP::bind($userDN, $userPass); + SP_LDAP::unbind(); + $attribs = SP_LDAP::getLDAPAttr($attribsMap); + } catch (Exception $e) { + return ldap_errno(SP_LDAP::getConn()); + } + // Comprobamos si la cuenta está bloqueada o expirada + if ( isset($attribs['expire']) && $attribs['expire'] > 0){ + return FALSE; + } + + if ( !isset($attribs['group']) ){ + $message['text'][] = _('El usuario no tiene grupos asociados'); SP_Common::wrLogInfo($message); return FALSE; } + + if (is_array($attribs['group'])){ + foreach ($attribs['group'] as $group) { + if (is_int($group)) { + continue; + } - @ldap_set_option($ldapConn, LDAP_OPT_NETWORK_TIMEOUT, 10); // Set timeout - @ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3); // Set LDAP version - - if (!@ldap_bind($ldapConn, $bindDN, $bindPass)) { - $message['text'][] = _('Error al conectar (bind)'); - $message['text'][] = 'LDAP ERROR: ' . ldap_error($ldapConn) . '(' . ldap_errno($ldapConn) . ')'; - - SP_Common::wrLogInfo($message); - return FALSE; - } - - $filter = '(&(|(samaccountname=' . self::$userLogin . ')(cn=' . self::$userLogin . '))(|(objectClass=inetOrgPerson)(objectClass=person)))'; - $filterAttr = array("dn", "displayname", "samaccountname", "mail", "memberof", "lockouttime", "fullname", "groupmembership", "mail"); - - $searchRes = @ldap_search($ldapConn, $searchBase, $filter, $filterAttr); - - if (!$searchRes) { - $message['text'][] = _('Error al buscar el DN del usuario'); - $message['text'][] = 'LDAP ERROR: ' . ldap_error($ldapConn) . '(' . ldap_errno($ldapConn) . ')'; - - SP_Common::wrLogInfo($message); - return FALSE; - } - - if (@ldap_count_entries($ldapConn, $searchRes) === 1) { - $searchUser = @ldap_get_entries($ldapConn, $searchRes); - - if (!$searchUser) { - $message['text'][] = _('Error al localizar el usuario en LDAP'); - $message['text'][] = 'LDAP ERROR: ' . ldap_error($ldapConn) . '(' . ldap_errno($ldapConn) . ')'; - - SP_Common::wrLogInfo($message); - return FALSE; - } - - $userDN = $searchUser[0]["dn"]; - } - - if (@ldap_bind($ldapConn, $userDN, self::$userPass)) { - @ldap_unbind($ldapConn); - - foreach ($searchUser as $entryValue) { - if (is_array($entryValue)) { - foreach ($entryValue as $entryAttr => $attrValue) { - if (is_array($attrValue)) { - if ($entryAttr == "groupmembership" || $entryAttr == "memberof") { - foreach ($attrValue as $group) { - if (is_int($group)) { - continue; - } - - preg_match('/^cn=([\w\s-]+),.*/i', $group, $groupName); - - // Comprobamos que el usuario está en el grupo indicado - if ($groupName[1] == $ldapgroup || $group == $ldapgroup) { - $ldapAccess = TRUE; - break; - } - } - } elseif ($entryAttr == "displayname" | $entryAttr == "fullname") { - self::$userName = $attrValue[0]; - } elseif ($entryAttr == "mail") { - self::$userEmail = $attrValue[0]; - } elseif ($entryAttr == "lockouttime") { - if ($attrValue[0] > 0) - return FALSE; - } - } - } + // Comprobamos que el usuario está en el grupo indicado + if ( self::checkLDAPGroup($group) ) { + $ldapAccess = TRUE; + break; } } - } else { - $message['text'][] = _('Error al conectar con el usuario'); - $message['text'][] = 'LDAP ERROR: ' . ldap_error($ldapConn) . '(' . ldap_errno($ldapConn) . ')'; - - SP_Common::wrLogInfo($message); - return ldap_errno($ldapConn); + } else{ + // Comprobamos que el usuario está en el grupo indicado + if ( self::checkLDAPGroup($attribs['group']) ) { + $ldapAccess = TRUE; + } } - + + self::$userName = $attribs['name']; + self::$userEmail = $attribs['mail']; + return $ldapAccess; } /** * @brief Autentificación de usuarios con MySQL + * @param string $userLogin con el login del usuario + * @param string $userPass con la clave del usuario * @return bool * * Esta función comprueba la clave del usuario. Si el usuario necesita ser migrado desde phpPMS, * se ejecuta el proceso para actualizar la clave. */ - public static function authUserMySQL() { - if (SP_Users::checkUserIsMigrate(self::$userLogin)) { - if (!SP_Users::migrateUser(self::$userLogin, self::$userPass)) { + public static function authUserMySQL($userLogin, $userPass) { + if (SP_Users::checkUserIsMigrate($userLogin)) { + if (!SP_Users::migrateUser($userLogin, $userPass)) { return FALSE; } } @@ -165,9 +132,9 @@ class SP_Auth { $query = "SELECT user_login," . "user_pass " . "FROM usrData " - . "WHERE user_login = '" . DB::escape(self::$userLogin) . "' " + . "WHERE user_login = '" . DB::escape($userLogin) . "' " . "AND user_isMigrate = 0 " - . "AND user_pass = SHA1(CONCAT(user_hashSalt,'" . DB::escape(self::$userPass) . "')) LIMIT 1"; + . "AND user_pass = SHA1(CONCAT(user_hashSalt,'" . DB::escape($userPass) . "')) LIMIT 1"; if (DB::doQuery($query, __FUNCTION__) === FALSE) { return FALSE; @@ -182,12 +149,13 @@ class SP_Auth { /** * @brief Comprobar si un usuario está deshabilitado + * @param string $userLogin con el login del usuario * @return bool */ - public static function checkUserIsDisabled() { + public static function checkUserIsDisabled($userLogin) { $query = "SELECT user_isDisabled " . "FROM usrData " - . "WHERE user_login = '" . DB::escape(self::$userLogin) . "' LIMIT 1"; + . "WHERE user_login = '" . DB::escape($userLogin) . "' LIMIT 1"; $queryRes = DB::getResults($query, __FUNCTION__); if ($queryRes === FALSE) { @@ -200,4 +168,21 @@ class SP_Auth { return TRUE; } + + /** + * @brief Comprobar si el grupo de LDAP está habilitado + * @param string $group con el nombre del grupo + * @return bool + */ + private static function checkLDAPGroup($group){ + $ldapgroup = SP_Config::getValue('ldapgroup'); + + preg_match('/^cn=([\w\s-]+),.*/i', $group, $groupName); + + if ($groupName[1] == $ldapgroup || $group == $ldapgroup) { + return TRUE; + } + + return FALSE; + } } diff --git a/inc/ldap.class.php b/inc/ldap.class.php new file mode 100644 index 00000000..52a5f609 --- /dev/null +++ b/inc/ldap.class.php @@ -0,0 +1,206 @@ +. + * + */ +defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo')); + +/** + * Esta clase es la encargada de realizar la autentificación de usuarios de sysPass. + */ +class SP_LDAP { + private static $ldapConn; + private static $ldapServer; + private static $searchBase; + private static $bindDN; + private static $bindPass; + private static $ldapGroup; + + public static $ldapSearchData; + + /** + * @brief Obtener el recurso de conexión a LDAP + * @return resource + */ + public static function getConn(){ + if (is_resource(self::$ldapConn)){ + return self::$ldapConn; + } + } + + /** + * @brief Comprobar la conexión al servidor de LDAP + * @return bool + */ + public static function checkLDAPConn(){ + + } + + /** + * @brief Comprobar si los parámetros necesario de LDAP están establecidos + * @return bool + */ + public static function checkLDAPParams(){ + self::$searchBase = SP_Config::getValue('ldapbase'); + self::$ldapServer = SP_Config::getValue('ldapserver'); + self::$bindDN = SP_Config::getValue('ldapbinduser'); + self::$bindPass = SP_Config::getValue('ldapbindpass'); + self::$ldapGroup = SP_Config::getValue('ldapgroup'); + + if (!self::$searchBase || !self::$ldapServer || !self::$ldapGroup || !self::$bindDN || !self::$bindPass) { + $message['action'] = __FUNCTION__; + $message['text'][] = _('Los parámetros de LDAP no están configurados'); + + SP_Common::wrLogInfo($message); + + return FALSE; + } + + return TRUE; + } + + /** + * @brief Realizar la conexión al servidor de LDAP + * @param string $server con la dirección del servidor + * @return bool + */ + public static function connect(){ + $message['action'] = __FUNCTION__; + + // Conexión al servidor LDAP + if (!self::$ldapConn = @ldap_connect(self::$ldapServer)) { + $message['text'][] = _('No es posible conectar con el servidor de LDAP') . " '" . self::$ldapServer . "'"; + $message['text'][] = 'LDAP ERROR: ' . ldap_error(self::$ldapConn) . '(' . ldap_errno(self::$ldapConn) . ')'; + + SP_Common::wrLogInfo($message); + + throw new Exception(_('No es posible conectar con el servidor de LDAP')); + } + + @ldap_set_option(self::$ldapConn, LDAP_OPT_NETWORK_TIMEOUT, 10); // Set timeout + @ldap_set_option(self::$ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3); // Set LDAP version + + return TRUE; + } + + /** + * @brief Realizar la autentificación con el servidor de LDAP + * @param string $dn con el DN del usuario + * @param string $pass con la clave del usuario + * @return bool + */ + public static function bind($userDN = '', $userPass = ''){ + $message['action'] = __FUNCTION__; + + $dn = ( $userDN ) ? $userDN : self::$bindDN; + $pass = ( $userPass ) ? $userPass : self::$bindPass; + + if (!@ldap_bind(self::$ldapConn, $dn, $pass)) { + $message['text'][] = _('Error al conectar (BIND)'); + $message['text'][] = 'LDAP ERROR: ' . ldap_error(self::$ldapConn) . '(' . ldap_errno(self::$ldapConn) . ')'; + $message['text'][] = 'LDAP DN: ' . $dn; + + SP_Common::wrLogInfo($message); + + throw new Exception(_('Error al conectar (BIND)')); + } + + return TRUE; + } + + /** + * @brief Obtener el RDN del usuario que realiza el login + * @param string $userLogin con el login del usuario + * @return none + */ + public static function getUserDN($userLogin){ + $message['action'] = __FUNCTION__; + + $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(self::$ldapConn, self::$searchBase, $filter, $filterAttr); + + if (!$searchRes) { + $message['text'][] = _('Error al buscar el DN del usuario'); + $message['text'][] = 'LDAP ERROR: ' . ldap_error(self::$ldapConn) . '(' . ldap_errno(self::$ldapConn) . ')'; + $message['text'][] = 'LDAP FILTER: ' . $filter; + + SP_Common::wrLogInfo($message); + + throw new Exception(_('Error al buscar el DN del usuario')); + } + + if (@ldap_count_entries(self::$ldapConn, $searchRes) === 1) { + self::$ldapSearchData = @ldap_get_entries(self::$ldapConn, $searchRes); + + if (!self::$ldapSearchData) { + $message['text'][] = _('Error al localizar el usuario en LDAP'); + $message['text'][] = 'LDAP ERROR: ' . ldap_error(self::$ldapConn) . '(' . ldap_errno(self::$ldapConn) . ')'; + + SP_Common::wrLogInfo($message); + + throw new Exception(_('Error al localizar el usuario en LDAP')); + } + + //return $searchUser[0]["dn"]; + } else { + $message['text'][] = _('Error al buscar el DN del usuario'); + $message['text'][] = 'LDAP FILTER: ' . $filter; + + SP_Common::wrLogInfo($message); + + throw new Exception(_('Error al buscar el DN del usuario')); + } + } + + /** + * @brief Realizar la desconexión del servidor de LDAP + * @return none + */ + public static function unbind(){ + @ldap_unbind(self::$ldapConn); + } + + public static function getLDAPAttr($attribs){ + $res = array(); + + foreach (self::$ldapSearchData as $entryValue) { + if (is_array($entryValue)) { + foreach ($entryValue as $entryAttr => $attrValue) { + if (is_array($attrValue)) { + if (array_key_exists($entryAttr, $attribs)){ + if ( $attrValue['count'] > 1 ){ + $res[$attribs[$entryAttr]] = $attrValue; + } else{ + $res[$attribs[$entryAttr]] = $attrValue[0]; + } + } + } + } + } + } + + return $res; + } +} \ No newline at end of file diff --git a/inc/locales/en_US/LC_MESSAGES/messages.mo b/inc/locales/en_US/LC_MESSAGES/messages.mo index a5ae6ece..62f08220 100644 Binary files a/inc/locales/en_US/LC_MESSAGES/messages.mo and b/inc/locales/en_US/LC_MESSAGES/messages.mo differ diff --git a/inc/users.class.php b/inc/users.class.php index 5c384ab1..268ef454 100644 --- a/inc/users.class.php +++ b/inc/users.class.php @@ -482,7 +482,7 @@ class SP_Users { public function newUserLDAP() { $passdata = SP_Users::makeUserPass($this->userPass); - $query = "INSERT INTO usrData SET" + $query = "INSERT INTO usrData SET " . "user_name = '" . DB::escape($this->userName) . "'," . "user_groupId = 0," . "user_login = '" . DB::escape($this->userLogin) . "'," @@ -614,6 +614,8 @@ class SP_Users { $query = "UPDATE usrData SET " . "user_pass = '" . $passdata['pass'] . "'," . "user_hashSalt = '" . $passdata['salt'] . "'," + . "user_name = '" . DB::escape($this->userName) . "'," + . "user_email = '" . DB::escape($this->userEmail) . "'," . "user_lastUpdate = NOW() " . "WHERE user_id = " . $this->getUserIdByLogin($this->userLogin) . " LIMIT 1";