123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\User\Model\ResourceModel;
- use Magento\Authorization\Model\Acl\Role\Group as RoleGroup;
- use Magento\Authorization\Model\Acl\Role\User as RoleUser;
- use Magento\Authorization\Model\UserContextInterface;
- use Magento\Framework\Acl\Data\CacheInterface;
- use Magento\Framework\App\ObjectManager;
- use Magento\User\Model\Backend\Config\ObserverConfig;
- use Magento\User\Model\User as ModelUser;
- /**
- * ACL user resource
- *
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @api
- * @since 100.0.2
- */
- class User extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
- {
- /**
- * Role model
- *
- * @var \Magento\Authorization\Model\RoleFactory
- */
- protected $_roleFactory;
- /**
- * @var \Magento\Framework\Stdlib\DateTime
- */
- protected $dateTime;
- /**
- * @var CacheInterface
- */
- private $aclDataCache;
- /**
- * @var ObserverConfig|null
- */
- private $observerConfig;
- /**
- * Construct
- *
- * @param \Magento\Framework\Model\ResourceModel\Db\Context $context
- * @param \Magento\Authorization\Model\RoleFactory $roleFactory
- * @param \Magento\Framework\Stdlib\DateTime $dateTime
- * @param string $connectionName
- * @param CacheInterface $aclDataCache
- * @param ObserverConfig|null $observerConfig
- */
- public function __construct(
- \Magento\Framework\Model\ResourceModel\Db\Context $context,
- \Magento\Authorization\Model\RoleFactory $roleFactory,
- \Magento\Framework\Stdlib\DateTime $dateTime,
- $connectionName = null,
- CacheInterface $aclDataCache = null,
- ObserverConfig $observerConfig = null
- ) {
- parent::__construct($context, $connectionName);
- $this->_roleFactory = $roleFactory;
- $this->dateTime = $dateTime;
- $this->aclDataCache = $aclDataCache ?: ObjectManager::getInstance()->get(CacheInterface::class);
- $this->observerConfig = $observerConfig ?: ObjectManager::getInstance()->get(ObserverConfig::class);
- }
- /**
- * Define main table
- *
- * @return void
- */
- protected function _construct()
- {
- $this->_init('admin_user', 'user_id');
- }
- /**
- * Initialize unique fields
- *
- * @return $this
- */
- protected function _initUniqueFields()
- {
- $this->_uniqueFields = [
- ['field' => 'email', 'title' => __('Email')],
- ['field' => 'username', 'title' => __('User Name')],
- ];
- return $this;
- }
- /**
- * Authenticate user by $username and $password
- *
- * @param ModelUser $user
- * @return $this
- */
- public function recordLogin(ModelUser $user)
- {
- $connection = $this->getConnection();
- $data = [
- 'logdate' => (new \DateTime())->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT),
- 'lognum' => $user->getLognum() + 1,
- ];
- $condition = ['user_id = ?' => (int)$user->getUserId()];
- $connection->update($this->getMainTable(), $data, $condition);
- return $this;
- }
- /**
- * Load data by specified username
- *
- * @param string $username
- * @return array
- */
- public function loadByUsername($username)
- {
- $connection = $this->getConnection();
- $select = $connection->select()->from($this->getMainTable())->where('username=:username');
- $binds = ['username' => $username];
- return $connection->fetchRow($select, $binds);
- }
- /**
- * Check if user is assigned to any role
- *
- * @param int|ModelUser $user
- * @return null|array
- */
- public function hasAssigned2Role($user)
- {
- if (is_numeric($user)) {
- $userId = $user;
- } elseif ($user instanceof \Magento\Framework\Model\AbstractModel) {
- $userId = $user->getUserId();
- } else {
- return null;
- }
- if ($userId > 0) {
- $connection = $this->getConnection();
- $select = $connection->select();
- $select->from($this->getTable('authorization_role'))
- ->where('parent_id > :parent_id')
- ->where('user_id = :user_id')
- ->where('user_type = :user_type');
- $binds = ['parent_id' => 0, 'user_id' => $userId,
- 'user_type' => UserContextInterface::USER_TYPE_ADMIN
- ];
- return $connection->fetchAll($select, $binds);
- } else {
- return null;
- }
- }
- /**
- * Unserialize user extra data after user save
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return $this
- */
- protected function _afterSave(\Magento\Framework\Model\AbstractModel $user)
- {
- $user->setExtra($this->getSerializer()->unserialize($user->getExtra()));
- if ($user->hasRoleId()) {
- $this->_clearUserRoles($user);
- $this->_createUserRole($user->getRoleId(), $user);
- }
- return $this;
- }
- /**
- * Clear all user-specific roles of provided user
- *
- * @param ModelUser $user
- * @return void
- */
- public function _clearUserRoles(ModelUser $user)
- {
- $conditions = ['user_id = ?' => (int)$user->getId(), 'user_type = ?' => UserContextInterface::USER_TYPE_ADMIN];
- $this->getConnection()->delete($this->getTable('authorization_role'), $conditions);
- }
- /**
- * Create role for provided user of provided type
- *
- * @param int $parentId
- * @param ModelUser $user
- * @return void
- */
- protected function _createUserRole($parentId, ModelUser $user)
- {
- if ($parentId > 0) {
- /** @var \Magento\Authorization\Model\Role $parentRole */
- $parentRole = $this->_roleFactory->create()->load($parentId);
- } else {
- $role = new \Magento\Framework\DataObject();
- $role->setTreeLevel(0);
- }
- if ($parentRole->getId()) {
- $data = new \Magento\Framework\DataObject(
- [
- 'parent_id' => $parentRole->getId(),
- 'tree_level' => $parentRole->getTreeLevel() + 1,
- 'sort_order' => 0,
- 'role_type' => RoleUser::ROLE_TYPE,
- 'user_id' => $user->getId(),
- 'user_type' => UserContextInterface::USER_TYPE_ADMIN,
- 'role_name' => $user->getFirstName(),
- ]
- );
- $insertData = $this->_prepareDataForTable($data, $this->getTable('authorization_role'));
- $this->getConnection()->insert($this->getTable('authorization_role'), $insertData);
- $this->aclDataCache->clean();
- }
- }
- /**
- * Unserialize user extra data after user load
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return $this
- */
- protected function _afterLoad(\Magento\Framework\Model\AbstractModel $user)
- {
- if (is_string($user->getExtra())) {
- $user->setExtra($this->getSerializer()->unserialize($user->getExtra()));
- }
- return parent::_afterLoad($user);
- }
- /**
- * Delete user role record with user
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return bool
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- public function delete(\Magento\Framework\Model\AbstractModel $user)
- {
- $this->_beforeDelete($user);
- $connection = $this->getConnection();
- $uid = $user->getId();
- $connection->beginTransaction();
- try {
- $connection->delete($this->getMainTable(), ['user_id = ?' => $uid]);
- $connection->delete(
- $this->getTable('authorization_role'),
- ['user_id = ?' => $uid, 'user_type = ?' => UserContextInterface::USER_TYPE_ADMIN]
- );
- } catch (\Magento\Framework\Exception\LocalizedException $e) {
- throw $e;
- } catch (\Exception $e) {
- $connection->rollBack();
- return false;
- }
- $connection->commit();
- $this->_afterDelete($user);
- return true;
- }
- /**
- * Get user roles
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return array
- */
- public function getRoles(\Magento\Framework\Model\AbstractModel $user)
- {
- if (!$user->getId()) {
- return [];
- }
- $table = $this->getTable('authorization_role');
- $connection = $this->getConnection();
- $select = $connection->select()->from(
- $table,
- []
- )->joinLeft(
- ['ar' => $table],
- "(ar.role_id = {$table}.parent_id and ar.role_type = '" . RoleGroup::ROLE_TYPE . "')",
- ['role_id']
- )->where(
- "{$table}.user_id = :user_id"
- )->where(
- "{$table}.user_type = :user_type"
- );
- $binds = ['user_id' => (int)$user->getId(),
- 'user_type' => UserContextInterface::USER_TYPE_ADMIN
- ];
- $roles = $connection->fetchCol($select, $binds);
- if ($roles) {
- return $roles;
- }
- return [];
- }
- /**
- * Delete user role
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return $this
- */
- public function deleteFromRole(\Magento\Framework\Model\AbstractModel $user)
- {
- if ($user->getUserId() <= 0) {
- return $this;
- }
- if ($user->getRoleId() <= 0) {
- return $this;
- }
- $dbh = $this->getConnection();
- $condition = [
- 'user_id = ?' => (int)$user->getId(),
- 'parent_id = ?' => (int)$user->getRoleId(),
- 'user_type = ?' => UserContextInterface::USER_TYPE_ADMIN
- ];
- $dbh->delete($this->getTable('authorization_role'), $condition);
- return $this;
- }
- /**
- * Check if role user exists
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return array
- */
- public function roleUserExists(\Magento\Framework\Model\AbstractModel $user)
- {
- if ($user->getUserId() > 0) {
- $roleTable = $this->getTable('authorization_role');
- $dbh = $this->getConnection();
- $binds = [
- 'parent_id' => $user->getRoleId(),
- 'user_id' => $user->getUserId(),
- 'user_type' => UserContextInterface::USER_TYPE_ADMIN
- ];
- $select = $dbh->select()->from($roleTable)
- ->where('parent_id = :parent_id')
- ->where('user_type = :user_type')
- ->where('user_id = :user_id');
- return $dbh->fetchCol($select, $binds);
- } else {
- return [];
- }
- }
- /**
- * Check if user exists
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return array
- */
- public function userExists(\Magento\Framework\Model\AbstractModel $user)
- {
- $connection = $this->getConnection();
- $select = $connection->select();
- $binds = [
- 'username' => $user->getUsername(),
- 'email' => $user->getEmail(),
- 'user_id' => (int)$user->getId(),
- ];
- $select->from(
- $this->getMainTable()
- )->where(
- '(username = :username OR email = :email)'
- )->where(
- 'user_id <> :user_id'
- );
- return $connection->fetchRow($select, $binds);
- }
- /**
- * Whether a user's identity is confirmed
- *
- * @param \Magento\Framework\Model\AbstractModel $user
- * @return bool
- */
- public function isUserUnique(\Magento\Framework\Model\AbstractModel $user)
- {
- return !$this->userExists($user);
- }
- /**
- * Save user extra data
- *
- * @param \Magento\Framework\Model\AbstractModel $object
- * @param string $data
- * @return $this
- */
- public function saveExtra($object, $data)
- {
- if ($object->getId()) {
- $this->getConnection()->update(
- $this->getMainTable(),
- ['extra' => $data],
- ['user_id = ?' => (int)$object->getId()]
- );
- }
- return $this;
- }
- /**
- * Retrieve the total user count bypassing any filters applied to collections
- *
- * @return int
- */
- public function countAll()
- {
- $connection = $this->getConnection();
- $select = $connection->select();
- $select->from($this->getMainTable(), 'COUNT(*)');
- $result = (int)$connection->fetchOne($select);
- return $result;
- }
- /**
- * Add validation rules to be applied before saving an entity
- *
- * @return \Zend_Validate_Interface $validator
- */
- public function getValidationRulesBeforeSave()
- {
- $userIdentity = new \Zend_Validate_Callback([$this, 'isUserUnique']);
- $userIdentity->setMessage(
- __('A user with the same user name or email already exists.'),
- \Zend_Validate_Callback::INVALID_VALUE
- );
- return $userIdentity;
- }
- /**
- * Update role users ACL
- *
- * @param \Magento\Authorization\Model\Role $role
- * @return bool
- */
- public function updateRoleUsersAcl(\Magento\Authorization\Model\Role $role)
- {
- $connection = $this->getConnection();
- $users = $role->getRoleUsers();
- $rowsCount = 0;
- if (sizeof($users) > 0) {
- $bind = ['reload_acl_flag' => 1];
- $where = ['user_id IN(?)' => $users];
- $rowsCount = $connection->update($this->getTable('admin_user'), $bind, $where);
- }
- return $rowsCount > 0;
- }
- /**
- * Unlock specified user record(s)
- *
- * @param int|int[] $userIds
- * @return int number of affected rows
- */
- public function unlock($userIds)
- {
- if (!is_array($userIds)) {
- $userIds = [$userIds];
- }
- return $this->getConnection()->update(
- $this->getMainTable(),
- ['failures_num' => 0, 'first_failure' => null, 'lock_expires' => null],
- $this->getIdFieldName() . ' IN (' . $this->getConnection()->quote($userIds) . ')'
- );
- }
- /**
- * Lock specified user record(s)
- *
- * @param int|int[] $userIds
- * @param int $exceptId
- * @param int $lifetime
- * @return int number of affected rows
- */
- public function lock($userIds, $exceptId, $lifetime)
- {
- if (!is_array($userIds)) {
- $userIds = [$userIds];
- }
- $exceptId = (int)$exceptId;
- return $this->getConnection()->update(
- $this->getMainTable(),
- ['lock_expires' => $this->dateTime->formatDate(time() + $lifetime)],
- "{$this->getIdFieldName()} IN (" . $this->getConnection()->quote(
- $userIds
- ) . ")\n AND {$this->getIdFieldName()} <> {$exceptId}"
- );
- }
- /**
- * Increment failures count along with updating lock expire and first failure dates
- *
- * @param ModelUser $user
- * @param int|bool $setLockExpires
- * @param int|bool $setFirstFailure
- * @return void
- */
- public function updateFailure($user, $setLockExpires = false, $setFirstFailure = false)
- {
- $update = ['failures_num' => new \Zend_Db_Expr('failures_num + 1')];
- if (false !== $setFirstFailure) {
- $update['first_failure'] = $this->dateTime->formatDate($setFirstFailure);
- $update['failures_num'] = 1;
- }
- if (false !== $setLockExpires) {
- $update['lock_expires'] = $this->dateTime->formatDate($setLockExpires);
- }
- $this->getConnection()->update(
- $this->getMainTable(),
- $update,
- $this->getConnection()->quoteInto("{$this->getIdFieldName()} = ?", $user->getId())
- );
- }
- /**
- * Purge and get remaining old password hashes
- *
- * @param ModelUser $user
- * @param int $retainLimit
- * @return array
- */
- public function getOldPasswords($user, $retainLimit = 4)
- {
- $userId = (int)$user->getId();
- $table = $this->getTable('admin_passwords');
- // purge expired passwords, except those which should be retained
- $retainPasswordIds = $this->getConnection()->fetchCol(
- $this->getConnection()
- ->select()
- ->from($table, 'password_id')
- ->where('user_id = :user_id')
- ->order('password_id ' . \Magento\Framework\DB\Select::SQL_DESC)
- ->limit($retainLimit),
- [':user_id' => $userId]
- );
- $where = [
- 'user_id = ?' => $userId,
- 'last_updated <= ?' => time() - $this->observerConfig->getAdminPasswordLifetime()
- ];
- if ($retainPasswordIds) {
- $where['password_id NOT IN (?)'] = $retainPasswordIds;
- }
- $this->getConnection()->delete($table, $where);
- // get all remaining passwords
- return $this->getConnection()->fetchCol(
- $this->getConnection()
- ->select()
- ->from($table, 'password_hash')
- ->where('user_id = :user_id'),
- [':user_id' => $userId]
- );
- }
- /**
- * Remember a password hash for further usage
- *
- * @param ModelUser $user
- * @param string $passwordHash
- * @param int $lifetime deprecated, password expiration date doesn't save anymore,
- * it is calculated in runtime based on password created date and lifetime config value
- * @return void
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- *
- * @see \Magento\User\Model\Backend\Config\ObserverConfig::_isLatestPasswordExpired()
- */
- public function trackPassword($user, $passwordHash, $lifetime = 0)
- {
- $this->getConnection()->insert(
- $this->getTable('admin_passwords'),
- [
- 'user_id' => $user->getId(),
- 'password_hash' => $passwordHash,
- 'last_updated' => time()
- ]
- );
- }
- /**
- * Get latest password for specified user id
- * Possible false positive when password was changed several times with different lifetime configuration
- *
- * @param int $userId
- * @return array
- */
- public function getLatestPassword($userId)
- {
- return $this->getConnection()->fetchRow(
- $this->getConnection()
- ->select()
- ->from($this->getTable('admin_passwords'))
- ->where('user_id = :user_id')
- ->order('password_id ' . \Magento\Framework\DB\Select::SQL_DESC)
- ->limit(1),
- [':user_id' => $userId]
- );
- }
- }
|