diff --git a/inc/SP/Account/AccountCrypt.class.php b/inc/SP/Account/AccountCrypt.class.php index f2aad837..520f81e1 100644 --- a/inc/SP/Account/AccountCrypt.class.php +++ b/inc/SP/Account/AccountCrypt.class.php @@ -55,7 +55,7 @@ class AccountCrypt */ public function updateOldPass(&$currentMasterPass) { - set_time_limit(300); + set_time_limit(0); $accountsOk = []; $userId = Session::getUserData()->getUserId(); @@ -87,6 +87,10 @@ class AccountCrypt $AccountDataBase = new AccountData(); foreach ($accountsPass as $account) { + if ($LogMessage->getDetailsCounter() >= 100) { + $Log->writeLog(false, true); + } + $AccountData = clone $AccountDataBase; $AccountData->setAccountId($account->account_id); @@ -187,6 +191,10 @@ class AccountCrypt $AccountDataBase = new AccountData(); foreach ($accountsPass as $account) { + if ($LogMessage->getDetailsCounter() >= 100) { + $Log->writeLog(false, true); + } + $AccountData = clone $AccountDataBase; $AccountData->setAccountId($account->account_id); diff --git a/inc/SP/Account/AccountHistoryCrypt.class.php b/inc/SP/Account/AccountHistoryCrypt.class.php index a69ee830..b1fbd321 100644 --- a/inc/SP/Account/AccountHistoryCrypt.class.php +++ b/inc/SP/Account/AccountHistoryCrypt.class.php @@ -55,7 +55,7 @@ class AccountHistoryCrypt */ public function updateOldPass(&$currentMasterPass) { - set_time_limit(300); + set_time_limit(0); $accountsOk = []; $demoEnabled = Checks::demoIsEnabled(); @@ -92,6 +92,10 @@ class AccountHistoryCrypt $AccountDataBase->hash = Hash::hashKey($currentMasterPass); foreach ($accountsPass as $account) { + if ($LogMessage->getDetailsCounter() >= 100) { + $Log->writeLog(false, true); + } + $AccountData = clone $AccountDataBase; $AccountData->id = $account->acchistory_id; @@ -200,6 +204,10 @@ class AccountHistoryCrypt $AccountDataBase->hash = Hash::hashKey($newMasterPass); foreach ($accountsPass as $account) { + if ($LogMessage->getDetailsCounter() >= 100) { + $Log->writeLog(false, true); + } + $AccountData = clone $AccountDataBase; $AccountData->id = $account->acchistory_id; diff --git a/inc/SP/Api/ApiBase.class.php b/inc/SP/Api/ApiBase.class.php index 474e8732..113de794 100644 --- a/inc/SP/Api/ApiBase.class.php +++ b/inc/SP/Api/ApiBase.class.php @@ -34,6 +34,7 @@ use SP\Core\Exceptions\SPException; use SP\Core\Session; use SP\Core\SessionUtil; use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\Log\Log; use SP\Mgmt\Users\User; use SP\Mgmt\Users\UserPass; @@ -75,7 +76,7 @@ abstract class ApiBase implements ApiInterface */ protected $mPass = ''; /** - * @var UserData + * @var UserLoginData */ protected $UserData; /** @@ -168,6 +169,9 @@ abstract class ApiBase implements ApiInterface * * @throws SPException * @throws \SP\Core\Exceptions\InvalidClassException + * @throws \Defuse\Crypto\Exception\BadFormatException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException */ protected function doAuth() { @@ -187,14 +191,11 @@ abstract class ApiBase implements ApiInterface throw new SPException(SPException::SP_CRITICAL, __('Acceso no permitido', false)); } - $UserPass = UserPass::getItem($this->UserData); - if (!$this->UserData->isUserIsDisabled() - && $UserPass->checkUserUpdateMPass() - && $UserPass->loadUserMPass() + && UserPass::loadUserMPass($this->UserData) === UserPass::MPASS_OK ) { $this->auth = true; - $this->mPass = $UserPass->getClearUserMPass(); + $this->mPass = UserPass::getClearUserMPass(); } else { throw new SPException(SPException::SP_CRITICAL, __('Acceso no permitido', false)); } diff --git a/inc/SP/Auth/Auth.class.php b/inc/SP/Auth/Auth.class.php index a8fc93c8..24a31ea6 100644 --- a/inc/SP/Auth/Auth.class.php +++ b/inc/SP/Auth/Auth.class.php @@ -34,6 +34,7 @@ use SP\Auth\Ldap\LdapStd; use SP\Config\Config; use SP\Core\Exceptions\SPException; use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\Util\Checks; defined('APP_ROOT') || die(); @@ -52,17 +53,17 @@ class Auth */ protected $auths = []; /** - * @var UserData + * @var UserLoginData */ protected $UserData; /** * Auth constructor. * - * @param UserData $UserData + * @param UserLoginData $UserData * @throws \SP\Core\Exceptions\SPException */ - public function __construct(UserData $UserData) + public function __construct(UserLoginData $UserData) { $this->UserData = $UserData; @@ -146,6 +147,8 @@ class Auth * se ejecuta el proceso para actualizar la clave. * * @return DatabaseAuthData + * @throws \phpmailer\phpmailerException + * @throws \SP\Core\Exceptions\SPException */ public function authDatabase() { diff --git a/inc/SP/Auth/AuthInterface.class.php b/inc/SP/Auth/AuthInterface.class.php index 7324486a..ecc6acb9 100644 --- a/inc/SP/Auth/AuthInterface.class.php +++ b/inc/SP/Auth/AuthInterface.class.php @@ -24,7 +24,7 @@ namespace SP\Auth; -use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; /** * Interface AuthInterface @@ -35,8 +35,8 @@ interface AuthInterface /** * Autentificar al usuario * - * @param UserData $UserData Datos del usuario + * @param UserLoginData $UserData Datos del usuario * @return mixed|AuthDataBase */ - public function authenticate(UserData $UserData); + public function authenticate(UserLoginData $UserData); } \ No newline at end of file diff --git a/inc/SP/Auth/Browser/Browser.class.php b/inc/SP/Auth/Browser/Browser.class.php index 995d14d0..2d2d5bc2 100644 --- a/inc/SP/Auth/Browser/Browser.class.php +++ b/inc/SP/Auth/Browser/Browser.class.php @@ -25,7 +25,7 @@ namespace SP\Auth\Browser; use SP\Auth\AuthInterface; -use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; /** * Class Browser @@ -39,13 +39,13 @@ class Browser implements AuthInterface /** * Autentificar al usuario * - * @param UserData $UserData Datos del usuario + * @param UserLoginData $UserData Datos del usuario * @return BrowserAuthData */ - public function authenticate(UserData $UserData) + public function authenticate(UserLoginData $UserData) { $AuthData = new BrowserAuthData(); - $AuthData->setAuthenticated($this->checkServerAuthUser($UserData->getUserLogin())); + $AuthData->setAuthenticated($this->checkServerAuthUser($UserData->getLogin())); return $AuthData; } diff --git a/inc/SP/Auth/Database/Database.class.php b/inc/SP/Auth/Database/Database.class.php index 483e8321..14fb7875 100644 --- a/inc/SP/Auth/Database/Database.class.php +++ b/inc/SP/Auth/Database/Database.class.php @@ -27,9 +27,10 @@ namespace SP\Auth\Database; use SP\Auth\AuthInterface; use SP\Core\Crypt\Hash; use SP\Core\Exceptions\SPException; -use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\DataModel\UserPassData; use SP\Log\Log; +use SP\Mgmt\Users\User; use SP\Mgmt\Users\UserMigrate; use SP\Storage\DB; use SP\Storage\QueryData; @@ -44,19 +45,19 @@ use SP\Storage\QueryData; class Database implements AuthInterface { /** - * @var UserData $UserData + * @var UserLoginData $UserData */ protected $UserData; /** * Autentificar al usuario * - * @param UserData $UserData Datos del usuario + * @param UserLoginData $UserData Datos del usuario * @return DatabaseAuthData * @throws \SP\Core\Exceptions\SPException * @throws \phpmailer\phpmailerException */ - public function authenticate(UserData $UserData) + public function authenticate(UserLoginData $UserData) { $this->UserData = $UserData; @@ -78,37 +79,23 @@ class Database implements AuthInterface */ protected function authUser() { - if (UserMigrate::checkUserIsMigrate($this->UserData->getUserLogin())) { - try { - UserMigrate::migrateUserPass($this->UserData->getUserLogin(), $this->UserData->getUserPass()); - } catch (SPException $e) { - $Log = new Log(); - $LogMessage = $Log->getLogMessage(); - $LogMessage->setAction(__FUNCTION__); - $LogMessage->addDescription($e->getMessage()); - $LogMessage->addDetails(__('Login', false), $this->UserData->getUserLogin()); - $Log->writeLog(); + try { + User::getItem($this->UserData)->getByLogin($this->UserData->getLogin()); + if ($this->UserData->isUserIsMigrate() && !UserMigrate::migrateUserPass($this->UserData)) { return false; } + + return Hash::checkHashKey($this->UserData->getLoginPass(), $this->UserData->getUserPass()); + } catch (SPException $e) { + $Log = new Log(); + $LogMessage = $Log->getLogMessage(); + $LogMessage->setAction(__FUNCTION__); + $LogMessage->addDescription($e->getMessage()); + $LogMessage->addDetails(__('Login', false), $this->UserData->getLogin()); + $Log->writeLog(); + + return false; } - - $query = /** @lang SQL */ - 'SELECT user_pass, user_hashSalt - FROM usrData - WHERE user_login = ? - AND user_isMigrate = 0 LIMIT 1'; - - $Data = new QueryData(); - $Data->setMapClassName(UserPassData::class); - $Data->setQuery($query); - $Data->addParam($this->UserData->getUserLogin()); - - /** @var UserPassData $queryRes */ - $queryRes = DB::getResults($Data); - - return $queryRes !== false - && $Data->getQueryNumRows() === 1 - && Hash::checkHashKey($this->UserData->getUserPass(), $queryRes->getUserPass()); } } \ No newline at end of file diff --git a/inc/SP/Auth/Ldap/LdapBase.class.php b/inc/SP/Auth/Ldap/LdapBase.class.php index ce9bb2bb..143c4178 100644 --- a/inc/SP/Auth/Ldap/LdapBase.class.php +++ b/inc/SP/Auth/Ldap/LdapBase.class.php @@ -28,7 +28,7 @@ use SP\Auth\AuthInterface; use SP\Config\Config; use SP\Core\Exceptions\SPException; use SP\Core\Messages\LogMessage; -use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\Log\Log; /** @@ -405,22 +405,22 @@ abstract class LdapBase implements LdapInterface, AuthInterface /** * Autentificar al usuario * - * @param UserData $UserData Datos del usuario + * @param UserLoginData $UserData Datos del usuario * @return bool */ - public function authenticate(UserData $UserData) + public function authenticate(UserLoginData $UserData) { if (!$this->checkParams()) { return false; } try { - $this->setUserLogin($UserData->getUserLogin()); + $this->setUserLogin($UserData->getLogin()); $this->connect(); $this->bind(); $this->getAttributes(); - $this->bind($this->LdapAuthData->getDn(), $UserData->getUserPass()); + $this->bind($this->LdapAuthData->getDn(), $UserData->getLoginPass()); } catch (SPException $e) { return false; } @@ -511,7 +511,7 @@ abstract class LdapBase implements LdapInterface, AuthInterface } } - if (!empty($res["fullname"])) { + if (!empty($res['fullname'])) { $this->LdapAuthData->setName($res['fullname']); } else { $this->LdapAuthData->setName($res['name'] . ' ' . $res['sn']); diff --git a/inc/SP/Controller/AccountController.class.php b/inc/SP/Controller/AccountController.class.php index 2cb5ab60..5f13a17c 100644 --- a/inc/SP/Controller/AccountController.class.php +++ b/inc/SP/Controller/AccountController.class.php @@ -281,7 +281,7 @@ class AccountController extends ControllerBase implements ActionsInterface if (!Acl::checkUserAccess($this->getAction())) { $this->showError(self::ERR_PAGE_NO_PERMISSION); return false; - } elseif (!UserPass::getItem($this->UserData)->checkUserUpdateMPass()) { + } elseif (!UserPass::checkUserUpdateMPass($this->UserData->getUserId())) { $this->showError(self::ERR_UPDATE_MPASS); return false; } elseif ($this->id > 0) { diff --git a/inc/SP/Controller/ConfigActionController.class.php b/inc/SP/Controller/ConfigActionController.class.php index d61a670a..fb4f30db 100644 --- a/inc/SP/Controller/ConfigActionController.class.php +++ b/inc/SP/Controller/ConfigActionController.class.php @@ -482,7 +482,7 @@ class ConfigActionController implements ItemControllerInterface $confirmPassChange = Request::analyze('confirmPassChange', 0, false, 1); $noAccountPassChange = Request::analyze('chkNoAccountChange', 0, false, 1); - if (!UserPass::getItem(Session::getUserData())->checkUserUpdateMPass()) { + if (!UserPass::checkUserUpdateMPass(Session::getUserData()->getUserId())) { $this->JsonResponse->setDescription(__('Clave maestra actualizada', false)); $this->JsonResponse->addMessage(__('Reinicie la sesión para cambiarla', false)); $this->JsonResponse->setStatus(100); diff --git a/inc/SP/Controller/ItemShowController.class.php b/inc/SP/Controller/ItemShowController.class.php index c14bb8e0..182a6a18 100644 --- a/inc/SP/Controller/ItemShowController.class.php +++ b/inc/SP/Controller/ItemShowController.class.php @@ -508,12 +508,9 @@ class ItemShowController extends ControllerBase implements ActionsInterface, Ite $AccountAcl = new AccountAcl($Account, ActionsInterface::ACTION_ACC_VIEW_PASS); $Acl = $AccountAcl->getAcl(); - $UserPass = new UserPass(new UserPassData()); - $UserPass->getItemData()->setUserId(Session::getUserData()->getUserId()); - if (!$Acl->isShowViewPass()) { throw new ItemException(__('No tiene permisos para acceder a esta cuenta', false)); - } elseif (!$UserPass->checkUserUpdateMPass()) { + } elseif (!UserPass::checkUserUpdateMPass(Session::getUserData()->getUserId())) { throw new ItemException(__('Clave maestra actualizada', false) . '
' . __('Reinicie la sesión para cambiarla', false)); } diff --git a/inc/SP/Controller/LoginController.class.php b/inc/SP/Controller/LoginController.class.php index d2221e43..80c1eb25 100644 --- a/inc/SP/Controller/LoginController.class.php +++ b/inc/SP/Controller/LoginController.class.php @@ -2,8 +2,8 @@ /** * sysPass * - * @author nuxsmin - * @link http://syspass.org + * @author nuxsmin + * @link http://syspass.org * @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. @@ -41,14 +41,13 @@ use SP\Core\Language; use SP\Core\Messages\LogMessage; use SP\Core\Session; use SP\Core\SessionUtil; -use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\DataModel\UserPassRecoverData; use SP\Http\JsonResponse; use SP\Http\Request; use SP\Log\Log; use SP\Mgmt\Groups\Group; use SP\Mgmt\Profiles\Profile; -use SP\Mgmt\Users\User; use SP\Mgmt\Users\UserLdap; use SP\Mgmt\Users\UserPass; use SP\Mgmt\Users\UserPassRecover; @@ -76,7 +75,7 @@ class LoginController */ protected $jsonResponse; /** - * @var UserData + * @var UserLoginData */ protected $UserData; /** @@ -90,7 +89,7 @@ class LoginController public function __construct() { $this->jsonResponse = new JsonResponse(); - $this->UserData = new UserData(); + $this->UserData = new UserLoginData(); $this->LogMessage = new LogMessage(); $this->LogMessage->setAction(__('Inicio sesión', false)); } @@ -112,8 +111,8 @@ class LoginController Json::returnJson($this->jsonResponse); } - $this->UserData->setUserLogin($userLogin); - $this->UserData->setUserPass($userPass); + $this->UserData->setLogin($userLogin); + $this->UserData->setLoginPass($userPass); $Log = new Log($this->LogMessage); @@ -134,9 +133,9 @@ class LoginController throw new AuthException(SPException::SP_INFO, __('Login incorrecto', false), '', self::STATUS_INVALID_LOGIN); } - $this->getUserData($userPass); - $this->checkUserDisabled(); - $this->checkPasswordChange(); + $this->getUserData(); + $this->checkUser(); + $this->loadMasterPass(); $this->setUserSession(); $this->loadUserPreferences(); } catch (SPException $e) { @@ -166,17 +165,14 @@ class LoginController /** * Obtener los datos del usuario * - * @param $userPass * @throws SPException * @throws \SP\Core\Exceptions\InvalidClassException * @throws \SP\Core\Exceptions\AuthException * @throws \InvalidArgumentException */ - protected function getUserData($userPass) + protected function getUserData() { try { - $this->UserData = User::getItem($this->UserData)->getByLogin($this->UserData->getUserLogin()); - $this->UserData->setUserPass($userPass); $this->UserData->setUserPreferences(UserPreferences::getItem()->getById($this->UserData->getUserId())); } catch (SPException $e) { $this->LogMessage->addDescription(__('Error al obtener los datos del usuario de la BBDD', false)); @@ -186,23 +182,141 @@ class LoginController } /** - * omprobar si el usuario está deshabilitado + * Comprobar estado del usuario * * @throws \SP\Core\Exceptions\SPException */ - protected function checkUserDisabled() + protected function checkUser() { // Comprobar si el usuario está deshabilitado if ($this->UserData->isUserIsDisabled()) { $this->LogMessage->addDescription(__('Usuario deshabilitado', false)); - $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getUserLogin()); + $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getLogin()); throw new AuthException(SPException::SP_INFO, __('Usuario deshabilitado', false), '', self::STATUS_USER_DISABLED); + } elseif ($this->UserData->isUserIsChangePass()) { + $hash = Util::generateRandomBytes(); + + $UserPassRecoverData = new UserPassRecoverData(); + $UserPassRecoverData->setUserpassrUserId($this->UserData->getUserId()); + $UserPassRecoverData->setUserpassrHash($hash); + + UserPassRecover::getItem($UserPassRecoverData)->add(); + + $data = ['url' => Init::$WEBURI . '/index.php?a=passreset&h=' . $hash . '&t=' . time() . '&f=1']; + $this->jsonResponse->setData($data); + $this->jsonResponse->setStatus(0); + Json::returnJson($this->jsonResponse); } return false; } + /** + * Cargar la clave maestra o solicitarla + * + * @throws \SP\Core\Exceptions\SPException + * @throws \SP\Core\Exceptions\AuthException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + */ + protected function loadMasterPass() + { + $masterPass = Request::analyzeEncrypted('mpass'); + $oldPass = Request::analyzeEncrypted('oldpass'); + + try { + if ($masterPass) { + if (CryptMasterPass::checkTempMasterPass($masterPass)) { + $this->LogMessage->addDescription(__('Usando clave temporal', false)); + + $masterPass = CryptMasterPass::getTempMasterPass($masterPass); + } + + if (!UserPass::updateUserMPass($masterPass, $this->UserData)) { + $this->LogMessage->addDescription(__('Clave maestra incorrecta', false)); + + throw new AuthException(SPException::SP_INFO, __('Clave maestra incorrecta', false), '', self::STATUS_INVALID_MASTER_PASS); + } else { + CryptSession::saveSessionKey(UserPass::getClearUserMPass()); + + $this->LogMessage->addDescription(__('Clave maestra actualizada', false)); + } + } else if ($oldPass) { + if (!UserPass::updateMasterPassFromOldPass($oldPass, $this->UserData)) { + $this->LogMessage->addDescription(__('Clave maestra incorrecta', false)); + + throw new AuthException(SPException::SP_INFO, __('Clave maestra incorrecta', false), '', self::STATUS_INVALID_MASTER_PASS); + } else { + CryptSession::saveSessionKey(UserPass::getClearUserMPass()); + + $this->LogMessage->addDescription(__('Clave maestra actualizada', false)); + } + } else { + switch (UserPass::loadUserMPass($this->UserData)) { + case UserPass::MPASS_CHECKOLD: + throw new AuthException(SPException::SP_INFO, __('Es necesaria su clave anterior', false), '', self::STATUS_NEED_OLD_PASS); + break; + case UserPass::MPASS_NOTSET: + case UserPass::MPASS_CHANGED: + case UserPass::MPASS_WRONG: + throw new AuthException(SPException::SP_INFO, __('La clave maestra no ha sido guardada o es incorrecta', false), '', self::STATUS_INVALID_MASTER_PASS); + break; + } + } + } catch (CryptoException $e) { + $this->LogMessage->addDescription(__('Error interno', false)); + + throw new AuthException(SPException::SP_INFO, $this->LogMessage->getDescription(), $e->getMessage(), self::STATUS_INTERNAL_ERROR); + } + } + + /** + * Cargar la sesión del usuario + * + * @throws \SP\Core\Exceptions\SPException + * @throws \InvalidArgumentException + * @throws \SP\Core\Exceptions\AuthException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + */ + protected function setUserSession() + { + // Obtenemos la clave maestra del usuario + if (UserPass::getClearUserMPass() !== '') { + // Actualizar el último login del usuario + UserUtil::setUserLastLogin($this->UserData->getUserId()); + + // Cargar las variables de sesión del usuario + SessionUtil::loadUserSession($this->UserData); + + $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getLogin()); + $this->LogMessage->addDetails(__('Perfil', false), Profile::getItem()->getById($this->UserData->getUserProfileId())->getUserprofileName()); + $this->LogMessage->addDetails(__('Grupo', false), Group::getItem()->getById($this->UserData->getUserGroupId())->getUsergroupName()); + } else { + $this->LogMessage->addDescription(__('Error al obtener la clave maestra del usuario', false)); + + throw new AuthException(SPException::SP_ERROR, __('Error interno', false), '', self::STATUS_INTERNAL_ERROR); + } + } + + /** + * Cargar las preferencias del usuario y comprobar si usa 2FA + * + * @throws \SP\Core\Exceptions\SPException + * @throws \SP\Core\Exceptions\InvalidClassException + */ + protected function loadUserPreferences() + { + Language::setLanguage(true); + DiFactory::getTheme()->initTheme(true); + Session::setUserPreferences($this->UserData->getUserPreferences()); + Session::setSessionType(Session::SESSION_INTERACTIVE); + Session::setAuthCompleted(true); + + DiFactory::getEventDispatcher()->notifyEvent('login.preferences', $this); + } + /** * Comprobar si se ha forzado un cambio de clave * @@ -230,116 +344,6 @@ class LoginController return false; } - /** - * Cargar la sesión del usuario - * - * @throws \SP\Core\Exceptions\SPException - * @throws \InvalidArgumentException - * @throws \SP\Core\Exceptions\AuthException - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \SP\Core\Exceptions\QueryException - */ - protected function setUserSession() - { - $UserPass = $this->loadMasterPass(); - - // Obtenemos la clave maestra del usuario - if ($UserPass->getClearUserMPass() !== '') { - // Actualizar el último login del usuario - UserUtil::setUserLastLogin($this->UserData->getUserId()); - - // Cargar las variables de sesión del usuario - SessionUtil::loadUserSession($this->UserData); - - $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getUserLogin()); - $this->LogMessage->addDetails(__('Perfil', false), Profile::getItem()->getById($this->UserData->getUserProfileId())->getUserprofileName()); - $this->LogMessage->addDetails(__('Grupo', false), Group::getItem()->getById($this->UserData->getUserGroupId())->getUsergroupName()); - } else { - $this->LogMessage->addDescription(__('Error al obtener la clave maestra del usuario', false)); - - throw new AuthException(SPException::SP_ERROR, __('Error interno', false), '', self::STATUS_INTERNAL_ERROR); - } - } - - /** - * Cargar la clave maestra o solicitarla - * - * @throws \SP\Core\Exceptions\SPException - * @throws \SP\Core\Exceptions\AuthException - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \SP\Core\Exceptions\QueryException - */ - protected function loadMasterPass() - { - $masterPass = Request::analyzeEncrypted('mpass'); - $oldPass = Request::analyzeEncrypted('oldpass'); - - $UserPass = UserPass::getItem($this->UserData); - - try { - if ($masterPass) { - if (CryptMasterPass::checkTempMasterPass($masterPass)) { - $this->LogMessage->addDescription(__('Usando clave temporal', false)); - - $masterPass = CryptMasterPass::getTempMasterPass($masterPass); - } - - if (!$UserPass->updateUserMPass($masterPass)) { - $this->LogMessage->addDescription(__('Clave maestra incorrecta', false)); - - throw new AuthException(SPException::SP_INFO, __('Clave maestra incorrecta', false), '', self::STATUS_INVALID_MASTER_PASS); - } else { - CryptSession::saveSessionKey($UserPass->getClearUserMPass()); - - $this->LogMessage->addDescription(__('Clave maestra actualizada', false)); - } - } else if ($oldPass) { - if (!$UserPass->updateMasterPass($oldPass)) { - $this->LogMessage->addDescription(__('Clave maestra incorrecta', false)); - - throw new AuthException(SPException::SP_INFO, __('Clave maestra incorrecta', false), '', self::STATUS_INVALID_MASTER_PASS); - } else { - CryptSession::saveSessionKey($UserPass->getClearUserMPass()); - - $this->LogMessage->addDescription(__('Clave maestra actualizada', false)); - } - } else { - $loadMPass = $UserPass->loadUserMPass(); - - // Comprobar si es necesario actualizar la clave maestra - if ($loadMPass === null) { - throw new AuthException(SPException::SP_INFO, __('Es necesaria su clave anterior', false), '', self::STATUS_NEED_OLD_PASS); - // La clave no está establecida o se ha sido cambiada por el administrador - } else if ($loadMPass === false) { - throw new AuthException(SPException::SP_INFO, __('La clave maestra no ha sido guardada o es incorrecta', false), '', self::STATUS_INVALID_MASTER_PASS); - } - } - } catch (CryptoException $e) { - $this->LogMessage->addDescription(__('Error interno', false)); - - throw new AuthException(SPException::SP_INFO, $this->LogMessage->getDescription(), $e->getMessage(), self::STATUS_INTERNAL_ERROR); - } - - return $UserPass; - } - - /** - * Cargar las preferencias del usuario y comprobar si usa 2FA - * - * @throws \SP\Core\Exceptions\SPException - * @throws \SP\Core\Exceptions\InvalidClassException - */ - protected function loadUserPreferences() - { - Language::setLanguage(true); - DiFactory::getTheme()->initTheme(true); - Session::setUserPreferences($this->UserData->getUserPreferences()); - Session::setSessionType(Session::SESSION_INTERACTIVE); - Session::setAuthCompleted(true); - - DiFactory::getEventDispatcher()->notifyEvent('login.preferences', $this); - } - /** * Autentificación LDAP * @@ -353,7 +357,7 @@ class LoginController { if ($LdapAuthData->getStatusCode() > 0) { $this->LogMessage->addDetails(__('Tipo', false), __FUNCTION__); - $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getUserLogin()); + $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getLogin()); if ($LdapAuthData->getStatusCode() === 49) { $this->LogMessage->addDescription(__('Login incorrecto', false)); @@ -382,7 +386,7 @@ class LoginController try { // Verificamos si el usuario existe en la BBDD - if (UserLdap::checkLDAPUserInDB($this->UserData->getUserLogin())) { + if (UserLdap::checkLDAPUserInDB($this->UserData->getLogin())) { // Actualizamos el usuario de LDAP en MySQL UserLdap::getItem($this->UserData)->update(); } else { @@ -411,7 +415,7 @@ class LoginController // Autentificamos con la BBDD if ($AuthData->getAuthenticated() === 0) { $this->LogMessage->addDescription(__('Login incorrecto', false)); - $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getUserLogin()); + $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getLogin()); throw new AuthException(SPException::SP_INFO, $this->LogMessage->getDescription(), '', self::STATUS_INVALID_LOGIN); } elseif ($AuthData->getAuthenticated() === 1) { @@ -434,7 +438,7 @@ class LoginController if ($AuthData->getAuthenticated() === 0) { $this->LogMessage->addDescription(__('Login incorrecto', false)); $this->LogMessage->addDetails(__('Tipo', false), __FUNCTION__); - $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getUserLogin()); + $this->LogMessage->addDetails(__('Usuario', false), $this->UserData->getLogin()); $this->LogMessage->addDetails(__('Autentificación', false), sprintf('%s (%s)', AuthUtil::getServerAuthType(), $AuthData->getName())); throw new AuthException(SPException::SP_INFO, $this->LogMessage->getDescription(), '', self::STATUS_INVALID_LOGIN); diff --git a/inc/SP/Core/Installer.class.php b/inc/SP/Core/Installer.class.php index 20c28b5e..5012d1ed 100644 --- a/inc/SP/Core/Installer.class.php +++ b/inc/SP/Core/Installer.class.php @@ -36,7 +36,7 @@ use SP\Core\Exceptions\SPException; use SP\DataModel\GroupData; use SP\DataModel\InstallData; use SP\DataModel\ProfileData; -use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\Mgmt\Groups\Group; use SP\Mgmt\Profiles\Profile; use SP\Mgmt\Users\User; @@ -462,11 +462,13 @@ class Installer Profile::getItem($ProfileData)->add(); // Datos del usuario - $UserData = new UserData(); + $UserData = new UserLoginData(); $UserData->setUserGroupId($GroupData->getUsergroupId()); $UserData->setUserProfileId($ProfileData->getUserprofileId()); $UserData->setUserLogin($this->InstallData->getAdminLogin()); + $UserData->setLogin($this->InstallData->getAdminLogin()); $UserData->setUserPass($this->InstallData->getAdminPass()); + $UserData->setLoginPass($this->InstallData->getAdminPass()); $UserData->setUserName('Admin'); $UserData->setUserIsAdminApp(1); @@ -477,10 +479,9 @@ class Installer ConfigDB::setCacheConfigValue('lastupdatempass', time()); ConfigDB::writeConfig(true); - if (!UserPass::getItem($UserData)->updateUserMPass($this->InstallData->getMasterPassword())) { + if (!UserPass::updateUserMPass($this->InstallData->getMasterPassword(), $UserData)) { throw new SPException(SPException::SP_CRITICAL, - __('Error al actualizar la clave maestra del usuario "admin"', false), - __('Informe al desarrollador', false)); + __('Error al actualizar la clave maestra del usuario "admin"', false)); } } catch (\Exception $e) { $this->rollback(); diff --git a/inc/SP/Core/Messages/LogMessage.class.php b/inc/SP/Core/Messages/LogMessage.class.php index 8cff1ed9..be884ef6 100644 --- a/inc/SP/Core/Messages/LogMessage.class.php +++ b/inc/SP/Core/Messages/LogMessage.class.php @@ -41,6 +41,14 @@ class LogMessage extends MessageBase * @var array Detalles de la acción en formato "detalle : descripción" */ protected $details = []; + /** + * @var int + */ + protected $descriptionCounter = 0; + /** + * @var int + */ + protected $detailsCounter = 0; /** * Devuelve la acción realizada @@ -140,6 +148,8 @@ class LogMessage extends MessageBase $this->details[] = [$this->formatString($key), $this->formatString($value)]; + $this->detailsCounter++; + return $this; } @@ -175,6 +185,7 @@ class LogMessage extends MessageBase public function addDescriptionLine() { $this->description[] = ''; + $this->descriptionCounter++; return $this; } @@ -222,7 +233,7 @@ class LogMessage extends MessageBase * Devolver un detalle formateado * * @param array $detail - * @param bool $translate + * @param bool $translate * @return string */ protected function formatDetail(array $detail, $translate = false) @@ -257,6 +268,18 @@ class LogMessage extends MessageBase public function resetDescription() { $this->description = []; + $this->descriptionCounter = 0; + + return $this; + } + + /** + * Restablecer la variable de detalles + */ + public function resetDetails() + { + $this->details = []; + $this->detailsCounter = 0; return $this; } @@ -271,4 +294,20 @@ class LogMessage extends MessageBase { return nl2br($this->getDetails($translate)); } + + /** + * @return int + */ + public function getDescriptionCounter() + { + return $this->descriptionCounter; + } + + /** + * @return int + */ + public function getDetailsCounter() + { + return $this->detailsCounter; + } } \ No newline at end of file diff --git a/inc/SP/Core/Upgrade/Crypt.class.php b/inc/SP/Core/Upgrade/Crypt.class.php index 9e21ac1f..fd94246c 100644 --- a/inc/SP/Core/Upgrade/Crypt.class.php +++ b/inc/SP/Core/Upgrade/Crypt.class.php @@ -31,6 +31,7 @@ use SP\Account\AccountHistoryCrypt; use SP\Config\ConfigDB; use SP\Core\Crypt\Hash; use SP\Core\Exceptions\SPException; +use SP\Core\Init; use SP\Log\Log; use SP\Mgmt\CustomFields\CustomFieldsUtil; use SP\Storage\DB; @@ -75,6 +76,10 @@ class Crypt return false; } + global $timeStart; + + debugLog(Init::microtime_float() - $timeStart); + return true; } diff --git a/inc/SP/Core/Upgrade/Upgrade.class.php b/inc/SP/Core/Upgrade/Upgrade.class.php index 74f3f199..dff2f5f6 100644 --- a/inc/SP/Core/Upgrade/Upgrade.class.php +++ b/inc/SP/Core/Upgrade/Upgrade.class.php @@ -52,7 +52,7 @@ defined('APP_ROOT') || die(); */ class Upgrade { - private static $dbUpgrade = [110, 1121, 1122, 1123, 11213, 11219, 11220, 12001, 12002, 1316011001, 1316100601, 20017011302, 20017011701, 20017012901, 20117021901]; + private static $dbUpgrade = [110, 1121, 1122, 1123, 11213, 11219, 11220, 12001, 12002, 1316011001, 1316100601, 20017011302, 20017011701, 20017012901]; private static $cfgUpgrade = [1124, 1316020501, 20017011202]; private static $auxUpgrade = [12001, 12002, 20017010901, 20017011202]; private static $appUpgrade = [20117021901]; diff --git a/inc/SP/Core/Upgrade/User.class.php b/inc/SP/Core/Upgrade/User.class.php index f73345f0..8d32b010 100644 --- a/inc/SP/Core/Upgrade/User.class.php +++ b/inc/SP/Core/Upgrade/User.class.php @@ -25,10 +25,9 @@ namespace SP\Core\Upgrade; use Defuse\Crypto\Exception\CryptoException; -use SP\Config\ConfigDB; -use SP\Core\Crypt\Hash; use SP\Core\Exceptions\SPException; use SP\Core\OldCrypt; +use SP\DataModel\UserLoginData; use SP\Mgmt\Users\UserPass; use SP\Storage\DB; use SP\Storage\QueryData; @@ -118,17 +117,16 @@ class User /** * Actualizar la clave maestra * - * @param UserPass $UserPass + * @param UserLoginData $UserData * @return bool */ - public static function upgradeMasterKey(UserPass $UserPass) + public static function upgradeMasterKey(UserLoginData $UserData) { - $UserData = $UserPass->getItemData(); - $key = OldCrypt::generateAesKey($UserData->getUserPass() . $UserData->getUserLogin()); + $key = OldCrypt::generateAesKey($UserData->getLoginPass() . $UserData->getLogin()); $mKey = OldCrypt::getDecrypt($UserData->getUserMPass(), $UserData->getUserMKey(), $key); try { - return $mKey && $UserPass->updateUserMPass($mKey); + return $mKey && UserPass::updateUserMPass($mKey, $UserData); } catch (SPException $e) { } catch (CryptoException $e) { } diff --git a/inc/SP/DataModel/UserLoginData.class.php b/inc/SP/DataModel/UserLoginData.class.php new file mode 100644 index 00000000..1221ac33 --- /dev/null +++ b/inc/SP/DataModel/UserLoginData.class.php @@ -0,0 +1,74 @@ +. + */ + +namespace SP\DataModel; + +/** + * Class UserLoginData + * + * @package SP\DataModel + */ +class UserLoginData extends UserData +{ + /** + * @var string + */ + protected $login; + /** + * @var string + */ + protected $loginPass; + + /** + * @return string + */ + public function getLogin() + { + return $this->login; + } + + /** + * @param string $login + */ + public function setLogin($login) + { + $this->login = $login; + } + + /** + * @return string + */ + public function getLoginPass() + { + return $this->loginPass; + } + + /** + * @param string $loginPass + */ + public function setLoginPass($loginPass) + { + $this->loginPass = $loginPass; + } +} \ No newline at end of file diff --git a/inc/SP/Log/Log.class.php b/inc/SP/Log/Log.class.php index ca54c4c1..5ac69640 100644 --- a/inc/SP/Log/Log.class.php +++ b/inc/SP/Log/Log.class.php @@ -115,13 +115,34 @@ class Log extends ActionLog return $Log; } + /** + * Escribir un nuevo evento en el registro de eventos + * + * @param string $action La acción realizada + * @param string $description La descripción de la acción realizada + * @param string $level + * @return Log + */ + public static function writeNewLog($action, $description = null, $level = Log::INFO) + { + $LogMessage = new LogMessage(); + $LogMessage->setAction($action); + $LogMessage->addDescription($description); + + $Log = new Log($LogMessage, $level); + $Log->writeLog(); + + return $Log; + } + /** * Escribir un nuevo evento en el registro de eventos * * @param bool $resetDescription Restablecer la descripción + * @param bool $resetDetails Restablecer los detalles * @return bool */ - public function writeLog($resetDescription = false) + public function writeLog($resetDescription = false, $resetDetails = false) { if ((defined('IS_INSTALLER') && IS_INSTALLER === 1) || self::$logDbEnabled === 0 @@ -166,6 +187,10 @@ class Log extends ActionLog $this->LogMessage->resetDescription(); } + if ($resetDetails === true) { + $this->LogMessage->resetDetails(); + } + try { DB::getQuery($Data); } catch (SPException $e) { @@ -218,24 +243,4 @@ class Log extends ActionLog return new Log($LogMessage, $level); } - - /** - * Escribir un nuevo evento en el registro de eventos - * - * @param string $action La acción realizada - * @param string $description La descripción de la acción realizada - * @param string $level - * @return Log - */ - public static function writeNewLog($action, $description = null, $level = Log::INFO) - { - $LogMessage = new LogMessage(); - $LogMessage->setAction($action); - $LogMessage->addDescription($description); - - $Log = new Log($LogMessage, $level); - $Log->writeLog(); - - return $Log; - } } \ No newline at end of file diff --git a/inc/SP/Mgmt/Users/User.class.php b/inc/SP/Mgmt/Users/User.class.php index 9cb6c40a..75cacd5a 100644 --- a/inc/SP/Mgmt/Users/User.class.php +++ b/inc/SP/Mgmt/Users/User.class.php @@ -305,6 +305,10 @@ class User extends UserBase implements ItemInterface, ItemSelectInterface user_lastUpdate, user_lastUpdateMPass, user_preferences, + user_pass, + user_hashSalt, + user_mPass, + user_mKey, BIN(user_isAdminApp) AS user_isAdminApp, BIN(user_isAdminAcc) AS user_isAdminAcc, BIN(user_isLdap) AS user_isLdap, @@ -357,6 +361,10 @@ class User extends UserBase implements ItemInterface, ItemSelectInterface user_lastUpdate, user_lastUpdateMPass, user_preferences, + user_pass, + user_hashSalt, + user_mPass, + user_mKey, BIN(user_isAdminApp) AS user_isAdminApp, BIN(user_isAdminAcc) AS user_isAdminAcc, BIN(user_isLdap) AS user_isLdap, @@ -369,7 +377,13 @@ class User extends UserBase implements ItemInterface, ItemSelectInterface WHERE user_login = ? LIMIT 1'; $Data = new QueryData(); - $Data->setMapClassName($this->getDataModel()); + + if (is_object($this->itemData)) { + $Data->setMapClass($this->itemData); + } else { + $Data->setMapClassName($this->getDataModel()); + } + $Data->setQuery($query); $Data->addParam($login); diff --git a/inc/SP/Mgmt/Users/UserMigrate.class.php b/inc/SP/Mgmt/Users/UserMigrate.class.php index 43ae196d..8e4193fa 100644 --- a/inc/SP/Mgmt/Users/UserMigrate.class.php +++ b/inc/SP/Mgmt/Users/UserMigrate.class.php @@ -29,6 +29,8 @@ defined('APP_ROOT') || die(); use SP\Core\Crypt\Hash; use SP\Core\Exceptions\SPException; use SP\DataModel\GroupUsersData; +use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\Log\Email; use SP\Log\Log; use SP\Mgmt\Groups\GroupUsers; @@ -65,48 +67,51 @@ class UserMigrate /** * Actualizar la clave de un usuario desde phpPMS. * - * @param string $userLogin con el login del usuario - * @param string $userPass con la clave del usuario + * @param UserLoginData $UserData + * @return bool + * @throws \SP\Core\Exceptions\SPException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Core\Exceptions\ConstraintException * * Esta función actualiza la clave de un usuario que ha sido migrado desde phpPMS - * @throws \SP\Core\Exceptions\SPException - * @throws \phpmailer\phpmailerException - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \SP\Core\Exceptions\QueryException */ - public static function migrateUserPass($userLogin, $userPass) + public static function migrateUserPass(UserLoginData $UserData) { - $query = /** @lang SQL */ - 'UPDATE usrData SET + $passOk = ($UserData->getUserPass() === sha1($UserData->getUserHashSalt() . $UserData->getLoginPass()) + || $UserData->getUserPass() === md5($UserData->getLoginPass()) + || hash_equals($UserData->getUserPass(), crypt($UserData->getLoginPass(), $UserData->getUserHashSalt())) + || Hash::checkHashKey($UserData->getLoginPass(), $UserData->getUserPass())); + + if ($passOk) { + $query = /** @lang SQL */ + 'UPDATE usrData SET user_pass = ?, user_hashSalt = \'\', user_lastUpdate = NOW(), user_isMigrate = 0 - WHERE user_login = ? - AND user_isMigrate = 1 - AND (user_pass = SHA1(CONCAT(user_hashSalt,?)) - OR user_pass = MD5(?) - OR user_pass = ENCRYPT(?, user_hashSalt)) LIMIT 1'; + WHERE user_login = ? LIMIT 1'; - $Data = new QueryData(); - $Data->setQuery($query); - $Data->addParam(Hash::hashKey($userPass)); - $Data->addParam($userLogin); - $Data->addParam($userPass); - $Data->addParam($userPass); - $Data->addParam($userPass); - $Data->setOnErrorMessage(__('Error al migrar cuenta de usuario', false)); + $Data = new QueryData(); + $Data->setQuery($query); + $Data->addParam(Hash::hashKey($UserData->getLoginPass())); + $Data->addParam($UserData->getLogin()); + $Data->setOnErrorMessage(__('Error al migrar cuenta de usuario', false)); - DB::getQuery($Data); + DB::getQuery($Data); - $Log = new Log(); - $Log->getLogMessage() - ->setAction(__FUNCTION__) - ->addDescription(__('Usuario actualizado', false)) - ->addDetails(__('Login', false), $userLogin); - $Log->writeLog(); + $Log = new Log(); + $Log->getLogMessage() + ->setAction(__FUNCTION__) + ->addDescription(__('Usuario actualizado', false)) + ->addDetails(__('Login', false), $UserData->getLogin()); + $Log->writeLog(); - Email::sendEmail($Log->getLogMessage()); + Email::sendEmail($Log->getLogMessage()); + + return true; + } + + return false; } /** diff --git a/inc/SP/Mgmt/Users/UserPass.class.php b/inc/SP/Mgmt/Users/UserPass.class.php index b242bb97..a5ffac69 100644 --- a/inc/SP/Mgmt/Users/UserPass.class.php +++ b/inc/SP/Mgmt/Users/UserPass.class.php @@ -33,7 +33,9 @@ use SP\Core\Crypt\Crypt; use SP\Core\Crypt\Hash; use SP\Core\Exceptions\QueryException; use SP\Core\Exceptions\SPException; -use SP\Core\Upgrade\User; +use SP\Core\Upgrade\User as UpgradeUser; +use SP\DataModel\UserData; +use SP\DataModel\UserLoginData; use SP\DataModel\UserPassData; use SP\Log\Email; use SP\Log\Log; @@ -48,10 +50,21 @@ use SP\Core\Crypt\Session as CryptSession; */ class UserPass extends UserBase { + // La clave maestra incorrecta + const MPASS_WRONG = 0; + // La clave maestra correcta + const MPASS_OK = 1; + // La clave maestra no está guardada + const MPASS_NOTSET = 2; + // La clave maestra ha cambiado + const MPASS_CHANGED = 3; + // Comprobar la clave maestra con la calve del usuario anterior + const MPASS_CHECKOLD = 4; + /** * @var string */ - protected $clearUserMPass = ''; + private static $clearUserMPass = ''; /** * Category constructor. @@ -93,9 +106,10 @@ class UserPass extends UserBase /** * Comprobar si el usuario tiene actualizada la clave maestra actual. * + * @param int $userId ID de usuario * @return bool */ - public function checkUserUpdateMPass() + public static function checkUserUpdateMPass($userId) { $configMPassTime = ConfigDB::getValue('lastupdatempass'); @@ -109,7 +123,7 @@ class UserPass extends UserBase $Data = new QueryData(); $Data->setMapClassName(UserPassData::class); $Data->setQuery($query); - $Data->addParam($this->itemData->getUserId()); + $Data->addParam($userId); /** @var UserPassData $queryRes */ $queryRes = DB::getResults($Data); @@ -117,6 +131,152 @@ class UserPass extends UserBase return ($queryRes !== false && $queryRes->getUserLastUpdateMPass() >= $configMPassTime); } + /** + * Actualizar la clave maestra con la clave anterior del usuario + * + * @param string $oldUserPass + * @param UserLoginData $UserData + * @return bool + * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException + * @throws \Defuse\Crypto\Exception\BadFormatException + * @throws \SP\Core\Exceptions\SPException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + */ + public static function updateMasterPassFromOldPass($oldUserPass, UserLoginData $UserData) + { + if (self::loadUserMPass($UserData, $oldUserPass) === UserPass::MPASS_OK) { + return self::updateUserMPass(self::$clearUserMPass, $UserData); + } + + return UserPass::MPASS_WRONG; + } + + /** + * Comprueba la clave maestra del usuario. + * + * @param UserLoginData $UserData + * @param string $key Clave de cifrado + * @return bool + * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException + * @throws \Defuse\Crypto\Exception\BadFormatException + * @throws \SP\Core\Exceptions\SPException + * @throws \Defuse\Crypto\Exception\CryptoException + */ + public static function loadUserMPass(UserLoginData $UserData, $key = null) + { + $configHashMPass = ConfigDB::getValue('masterPwd'); + + if (empty($configHashMPass) + || empty($UserData->getUserMPass()) + || empty($UserData->getUserMKey()) + ) { + return self::MPASS_NOTSET; + } elseif ($UserData->getUserLastUpdateMPass() < ConfigDB::getValue('lastupdatempass')) { + return self::MPASS_CHANGED; + } elseif ($UserData->isUserIsMigrate() === 1) { + return UpgradeUser::upgradeMasterKey($UserData) ? self::MPASS_OK : self::MPASS_WRONG; + } else { + $securedKey = Crypt::unlockSecuredKey($UserData->getUserMKey(), self::getKey($UserData, $key)); + $userMPass = Crypt::decrypt($UserData->getUserMPass(), $securedKey, self::getKey($UserData, $key)); + + // Comprobamos el hash de la clave del usuario con la guardada + if (Hash::checkHashKey($userMPass, $configHashMPass)) { + self::$clearUserMPass = $userMPass; + + CryptSession::saveSessionKey($userMPass); + + return self::MPASS_OK; + } + } + + return self::MPASS_CHECKOLD; + } + + /** + * Obtener una clave de cifrado basada en la clave del usuario y un salt. + * + * @param UserLoginData $UserData + * @param string $key Clave de cifrado + * @return string con la clave de cifrado + */ + private static function getKey(UserLoginData $UserData, $key = null) + { + $pass = $key === null ? $UserData->getLoginPass() : $key; + + return $pass . $UserData->getLogin() . Config::getConfig()->getPasswordSalt(); + } + + /** + * Actualizar la clave maestra del usuario en la BBDD. + * + * @param string $userMPass con la clave maestra + * @param UserData|UserLoginData $UserData $UserData + * @return bool + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\SPException + * @throws QueryException + */ + public static function updateUserMPass($userMPass, UserLoginData $UserData) + { + $configHashMPass = ConfigDB::getValue('masterPwd'); + + if ($configHashMPass === false) { + return self::MPASS_NOTSET; + } elseif (null === $configHashMPass) { + $configHashMPass = Hash::hashKey($userMPass); + ConfigDB::setValue('masterPwd', $configHashMPass); + } + + if (Hash::checkHashKey($userMPass, $configHashMPass) + || \SP\Core\Upgrade\Crypt::migrateHash($userMPass) + ) { + $securedKey = Crypt::makeSecuredKey(self::getKey($UserData)); + $cryptMPass = Crypt::encrypt($userMPass, $securedKey, self::getKey($UserData)); + + if (!empty($cryptMPass)) { + if (strlen($securedKey) > 1000 || strlen($cryptMPass) > 1000) { + throw new QueryException(SPException::SP_ERROR, __('Error interno', false), '', LoginController::STATUS_INTERNAL_ERROR); + } + + $query = /** @lang SQL */ + 'UPDATE usrData SET + user_mPass = ?, + user_mKey = ?, + user_lastUpdateMPass = UNIX_TIMESTAMP(), + user_isMigrate = 0 + WHERE user_id = ? LIMIT 1'; + + $Data = new QueryData(); + $Data->setQuery($query); + $Data->addParam($cryptMPass); + $Data->addParam($securedKey); + $Data->addParam($UserData->getUserId()); + + self::$clearUserMPass = $userMPass; + + $UserData->setUserMPass($cryptMPass); + $UserData->setUserMKey($securedKey); + + DB::getQuery($Data); + + return self::MPASS_OK; + } + } + + return self::MPASS_WRONG; + } + + /** + * @return string + */ + public static function getClearUserMPass() + { + return self::$clearUserMPass; + } + /** * Modificar la clave de un usuario. * @@ -159,179 +319,4 @@ class UserPass extends UserBase return $this; } - - /** - * Comprueba la clave maestra del usuario. - * - * @return bool - * @throws \Defuse\Crypto\Exception\CryptoException - * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException - * @throws \Defuse\Crypto\Exception\BadFormatException - * @throws \SP\Core\Exceptions\SPException - */ - public function loadUserMPass() - { - $userMPass = $this->getUserMPass(); - $configHashMPass = ConfigDB::getValue('masterPwd'); - - if ($userMPass === false || empty($configHashMPass)) { - return false; - - // Comprobamos el hash de la clave del usuario con la guardada - } elseif (Hash::checkHashKey($userMPass, $configHashMPass)) { - $this->clearUserMPass = $userMPass; - - CryptSession::saveSessionKey($userMPass); - - return true; - } - - return null; - } - - /** - * Desencriptar la clave maestra del usuario para la sesión. - * - * @param string $key Clave de cifrado - * @return false|string Devuelve bool se hay error o string si se devuelve la clave - * @throws \Defuse\Crypto\Exception\CryptoException - */ - public function getUserMPass($key = null) - { - $query = /** @lang SQL */ - 'SELECT user_mPass, - user_mKey, - user_lastUpdateMPass, - BIN(user_isMigrate) AS user_isMigrate - FROM usrData WHERE user_id = ? LIMIT 1'; - - $Data = new QueryData(); - $Data->setQuery($query); - $Data->addParam($this->itemData->getUserId()); - - $queryRes = DB::getResults($Data); - - if ($queryRes === false - || empty($queryRes->user_mPass) - || empty($queryRes->user_mKey) - || $queryRes->user_lastUpdateMPass < ConfigDB::getValue('lastupdatempass') - ) { - return false; - } elseif ((int)$queryRes->user_isMigrate === 1) { - $this->itemData->setUserMPass($queryRes->user_mPass); - $this->itemData->setUserMKey($queryRes->user_mKey); - - return User::upgradeMasterKey($this); - } - - $this->itemData->setUserMPass($queryRes->user_mPass); - $this->itemData->setUserMKey($queryRes->user_mKey); - - $securedKey = Crypt::unlockSecuredKey($queryRes->user_mKey, $this->getKey($key)); - - return Crypt::decrypt($queryRes->user_mPass, $securedKey, $this->getKey($key)); - } - - /** - * Obtener una clave de cifrado basada en la clave del usuario y un salt. - * - * @param string $key Clave de cifrado - * @return string con la clave de cifrado - * @throws \Defuse\Crypto\Exception\CryptoException - */ - private function getKey($key = null) - { - $pass = $key === null ? $this->itemData->getUserPass() : $key; - - return $pass . $this->itemData->getUserLogin() . Config::getConfig()->getPasswordSalt(); - } - - /** - * @return string - */ - public function getClearUserMPass() - { - return $this->clearUserMPass; - } - - /** - * Actualizar la clave maestra con la clave anterior del usuario - * - * @param $oldUserPass - * @return bool - * @throws \SP\Core\Exceptions\QueryException - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \Defuse\Crypto\Exception\CryptoException - * @throws \SP\Core\Exceptions\SPException - */ - public function updateMasterPass($oldUserPass) - { - $masterPass = $this->getUserMPass($oldUserPass); - - if ($masterPass) { - return $this->updateUserMPass($masterPass); - } - - return false; - } - - /** - * Actualizar la clave maestra del usuario en la BBDD. - * - * @param string $masterPwd con la clave maestra - * @return bool - * @throws \SP\Core\Exceptions\QueryException - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \Defuse\Crypto\Exception\CryptoException - * @throws \SP\Core\Exceptions\SPException - */ - public function updateUserMPass($masterPwd) - { - $configHashMPass = ConfigDB::getValue('masterPwd'); - - if ($configHashMPass === false) { - return false; - } elseif (null === $configHashMPass) { - $configHashMPass = Hash::hashKey($masterPwd); - ConfigDB::setValue('masterPwd', $configHashMPass); - } - - if (Hash::checkHashKey($masterPwd, $configHashMPass) - || \SP\Core\Upgrade\Crypt::migrateHash($masterPwd) - ) { - $securedKey = Crypt::makeSecuredKey($this->getKey()); - $cryptMPass = Crypt::encrypt($masterPwd, $securedKey, $this->getKey()); - - if (!empty($cryptMPass)) { - if (strlen($securedKey) > 1000 || strlen($cryptMPass) > 1000) { - throw new QueryException(SPException::SP_ERROR, __('Error interno', false), '', LoginController::STATUS_INTERNAL_ERROR); - } - - $query = /** @lang SQL */ - 'UPDATE usrData SET - user_mPass = ?, - user_mKey = ?, - user_lastUpdateMPass = UNIX_TIMESTAMP(), - user_isMigrate = 0 - WHERE user_id = ? LIMIT 1'; - - $Data = new QueryData(); - $Data->setQuery($query); - $Data->addParam($cryptMPass); - $Data->addParam($securedKey); - $Data->addParam($this->itemData->getUserId()); - - $this->clearUserMPass = $masterPwd; - - $this->itemData->setUserMPass($cryptMPass); - $this->itemData->setUserMKey($securedKey); - - DB::getQuery($Data); - - return true; - } - } - - return false; - } } \ No newline at end of file diff --git a/js/app-triggers.min.js b/js/app-triggers.min.js index 8c8afc31..edfb3390 100644 --- a/js/app-triggers.min.js +++ b/js/app-triggers.min.js @@ -1,5 +1,5 @@ var $jscomp={scope:{},findInternal:function(b,d,e){b instanceof String&&(b=String(b));for(var a=b.length,c=0;c