diff options
author | Thomas Steur <tsteur@users.noreply.github.com> | 2018-11-30 00:31:54 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-30 00:31:54 +0300 |
commit | 414230d05a03dc703ad5c6263d2499c46bdecde7 (patch) | |
tree | 544aa75eaaa7a070f0011320954cbae8ae4d76ca /plugins/UsersManager | |
parent | 1d3388c1cd3dd03743576d670118a65e9cd879cb (diff) |
When changing password or email address, require to type old password (#13683)
Diffstat (limited to 'plugins/UsersManager')
17 files changed, 301 insertions, 51 deletions
diff --git a/plugins/UsersManager/API.php b/plugins/UsersManager/API.php index 78bff1b43f..7862cd7b3a 100644 --- a/plugins/UsersManager/API.php +++ b/plugins/UsersManager/API.php @@ -24,6 +24,7 @@ use Piwik\Piwik; use Piwik\SettingsPiwik; use Piwik\Site; use Piwik\Tracker\Cache; +use Piwik\Url; /** * The UsersManager API lets you Manage Users and their permissions to access specific websites. @@ -41,6 +42,8 @@ class API extends \Piwik\Plugin\API { const OPTION_NAME_PREFERENCE_SEPARATOR = '_'; + public static $UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION = true; + /** * @var Model */ @@ -795,26 +798,31 @@ class API extends \Piwik\Plugin\API * Updates a user in the database. * Only login and password are required (case when we update the password). * - * If the password changes and the user has an old token_auth (legacy MD5 format) associated, - * the token will be regenerated. This could break a user's API calls. + * If password or email changes, it is required to also specify the password of the current user needs to be specified + * to confirm this change. * * @see addUser() for all the parameters */ public function updateUser($userLogin, $password = false, $email = false, $alias = false, - $_isPasswordHashed = false) + $_isPasswordHashed = false, $passwordConfirmation = false) { + $requirePasswordConfirmation = self::$UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION; + self::$UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION = true; + Piwik::checkUserHasSuperUserAccessOrIsTheUser($userLogin); $this->checkUserIsNotAnonymous($userLogin); $this->checkUserExists($userLogin); $userInfo = $this->model->getUser($userLogin); $token_auth = $userInfo['token_auth']; + $changeShouldRequirePasswordConfirmation = false; $passwordHasBeenUpdated = false; if (empty($password)) { $password = false; } else { + $changeShouldRequirePasswordConfirmation = true; $password = Common::unsanitizeInputValue($password); if (!$_isPasswordHashed) { @@ -842,6 +850,18 @@ class API extends \Piwik\Plugin\API if ($email != $userInfo['email']) { $this->checkEmail($email); + $changeShouldRequirePasswordConfirmation = true; + } + + if ($changeShouldRequirePasswordConfirmation && $requirePasswordConfirmation) { + if (empty($passwordConfirmation)) { + throw new Exception(Piwik::translate('UsersManager_ConfirmWithPassword')); + } + + $loginCurrentUser = Piwik::getCurrentUserLogin(); + if (!$this->verifyPasswordCorrect($loginCurrentUser, $passwordConfirmation)) { + throw new Exception(Piwik::translate('UsersManager_CurrentPasswordNotCorrect')); + } } $alias = $this->getCleanAlias($alias, $userLogin); @@ -860,6 +880,18 @@ class API extends \Piwik\Plugin\API Piwik::postEvent('UsersManager.updateUser.end', array($userLogin, $passwordHasBeenUpdated, $email, $password, $alias)); } + private function verifyPasswordCorrect($userLogin, $password) + { + /** @var \Piwik\Auth $authAdapter */ + $authAdapter = StaticContainer::get('Piwik\Auth'); + $authAdapter->setLogin($userLogin); + $authAdapter->setPasswordHash(null);// ensure authentication happens on password + $authAdapter->setPassword($password); + $authAdapter->setTokenAuth(null);// ensure authentication happens on password + $authResult = $authAdapter->authenticate(); + return $authResult->wasAuthenticationSuccessful(); + } + /** * Delete one or more users and all its access, given its login. * @@ -1264,7 +1296,8 @@ class API extends \Piwik\Plugin\API } if ($this->password->needsRehash($user['password'])) { - $this->updateUser($userLogin, $this->password->hash($md5Password)); + $userUpdater = new UserUpdater(); + $userUpdater->updateUserWithoutCurrentPassword($userLogin, $this->password->hash($md5Password)); } return $user['token_auth']; diff --git a/plugins/UsersManager/Controller.php b/plugins/UsersManager/Controller.php index ba35641075..c9cfcaecde 100644 --- a/plugins/UsersManager/Controller.php +++ b/plugins/UsersManager/Controller.php @@ -414,40 +414,36 @@ class Controller extends ControllerAdmin private function processPasswordChange($userLogin) { $email = Common::getRequestVar('email'); - $newPassword = false; - $password = Common::getRequestvar('password', false); $passwordBis = Common::getRequestvar('passwordBis', false); - if (!empty($password) - || !empty($passwordBis) - ) { + $passwordCurrent = Common::getRequestvar('passwordConfirmation', false); + + $newPassword = false; + if (!empty($password) || !empty($passwordBis)) { if ($password != $passwordBis) { throw new Exception($this->translator->translate('Login_PasswordsDoNotMatch')); } $newPassword = $password; } - // UI disables password change on invalid host, but check here anyway - if (!Url::isValidHost() - && $newPassword !== false - ) { - throw new Exception("Cannot change password with untrusted hostname!"); + if ($newPassword !== false && !Url::isValidHost()) { + throw new Exception("Cannot change password or email with untrusted hostname!"); } + // UI disables password change on invalid host, but check here anyway Request::processRequest('UsersManager.updateUser', [ 'userLogin' => $userLogin, 'password' => $newPassword, 'email' => $email, + 'passwordConfirmation' => $passwordCurrent ], $default = []); if ($newPassword !== false) { + // logs the user in with the new password $newPassword = Common::unsanitizeInputValue($newPassword); - } - - // logs the user in with the new password - if ($newPassword !== false) { $sessionInitializer = new SessionInitializer(); $auth = StaticContainer::get('Piwik\Auth'); + $auth->setTokenAuth(null); // ensure authenticated through password $auth->setLogin($userLogin); $auth->setPassword($newPassword); $sessionInitializer->initSession($auth); diff --git a/plugins/UsersManager/LastSeenTimeLogger.php b/plugins/UsersManager/LastSeenTimeLogger.php index 491805ed82..8e3adb8296 100644 --- a/plugins/UsersManager/LastSeenTimeLogger.php +++ b/plugins/UsersManager/LastSeenTimeLogger.php @@ -40,7 +40,7 @@ class LastSeenTimeLogger // only log time for non-anonymous visits to the reporting UI if ($module == 'API' || $module == 'Proxy' - || $currentUserLogin == 'anonymous' + || Piwik::isUserIsAnonymous() ) { return; } diff --git a/plugins/UsersManager/UserUpdater.php b/plugins/UsersManager/UserUpdater.php new file mode 100644 index 0000000000..87d748a6dd --- /dev/null +++ b/plugins/UsersManager/UserUpdater.php @@ -0,0 +1,44 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\UsersManager; + +use Piwik\API\Request; + +class UserUpdater +{ + + /** + * Use this method if you have to update the user without having the ability to ask the user for a password confirmation + * @param $userLogin + * @param bool $password + * @param bool $email + * @param bool $alias + * @param bool $_isPasswordHashed + * @throws \Exception + */ + public function updateUserWithoutCurrentPassword($userLogin, $password = false, $email = false, $alias = false, + $_isPasswordHashed = false) + { + API::$UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION = false; + try { + Request::processRequest('UsersManager.updateUser', [ + 'userLogin' => $userLogin, + 'password' => $password, + 'email' => $email, + 'alias' => $alias, + '_isPasswordHashed' => $_isPasswordHashed, + ], $default = []); + API::$UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION = true; + } catch (\Exception $e) { + API::$UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION = true; + throw $e; + } + } + +}
\ No newline at end of file diff --git a/plugins/UsersManager/UsersManager.php b/plugins/UsersManager/UsersManager.php index 1dd7d3b9bb..980528ad04 100644 --- a/plugins/UsersManager/UsersManager.php +++ b/plugins/UsersManager/UsersManager.php @@ -228,6 +228,8 @@ class UsersManager extends \Piwik\Plugin $translationKeys[] = "UsersManager_PrivAdmin"; $translationKeys[] = "UsersManager_PrivView"; $translationKeys[] = "UsersManager_RemoveUserAccess"; + $translationKeys[] = "UsersManager_ConfirmWithPassword"; + $translationKeys[] = "UsersManager_YourCurrentPassword"; $translationKeys[] = "UsersManager_UserHasPermission"; $translationKeys[] = "UsersManager_UserHasNoPermission"; $translationKeys[] = "UsersManager_PrivNone"; @@ -282,10 +284,10 @@ class UsersManager extends \Piwik\Plugin $translationKeys[] = 'UsersManager_Email'; $translationKeys[] = 'UsersManager_LastSeen'; $translationKeys[] = 'UsersManager_SuperUserAccess'; + $translationKeys[] = 'UsersManager_AreYouSureChangeDetails'; + $translationKeys[] = 'UsersManager_AnonymousUserRoleChangeWarning'; $translationKeys[] = 'General_Warning'; $translationKeys[] = 'General_Add'; - $translationKeys[] = 'UsersManager_AreYouSureChangePassword'; $translationKeys[] = 'General_Note'; - $translationKeys[] = 'UsersManager_AnonymousUserRoleChangeWarning'; } } diff --git a/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js b/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js index b6f4b42c6e..31f9f02f7e 100644 --- a/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js +++ b/plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js @@ -7,13 +7,15 @@ (function () { angular.module('piwikApp').controller('PersonalSettingsController', PersonalSettingsController); - PersonalSettingsController.$inject = ['piwikApi', '$window']; + PersonalSettingsController.$inject = ['piwikApi', '$window', 'piwik']; - function PersonalSettingsController(piwikApi, $window) { + function PersonalSettingsController(piwikApi, $window, piwik) { // remember to keep controller very simple. Create a service/factory (model) if needed var self = this; + this.doesRequirePasswordConfirmation = false; + function updateSettings(postParams) { self.loading = true; @@ -28,12 +30,19 @@ id: 'PersonalSettingsSuccess', context: 'success'}); notification.scrollToNotification(); + self.doesRequirePasswordConfirmation = !!self.password; + self.passwordCurrent = ''; self.loading = false; }, function (errorMessage) { self.loading = false; + self.passwordCurrent = ''; }); } + this.requirePasswordConfirmation = function () { + this.doesRequirePasswordConfirmation = true; + }; + this.regenerateTokenAuth = function () { var parameters = { userLogin: piwik.userLogin }; @@ -46,7 +55,6 @@ method: 'UsersManager.regenerateTokenAuth' }, parameters).then(function (success) { $window.location.reload(); - self.loading = false; }, function (errorMessage) { self.loading = false; @@ -54,8 +62,21 @@ }}); }; + this.cancelSave = function () { + this.passwordCurrent = ''; + }; + this.save = function () { + if (this.doesRequirePasswordConfirmation && !this.passwordCurrent) { + angular.element('#confirmChangesWithPassword').openModal({ dismissible: false, ready: function () { + $('.modal.open #currentPassword').focus(); + }}); + return; + } + + angular.element('#confirmChangesWithPassword').closeModal(); + var postParams = { email: this.email, defaultReport: this.defaultReport == 'MultiSites' ? this.defaultReport : this.site.id, @@ -72,6 +93,10 @@ postParams.passwordBis = this.passwordBis; } + if (this.passwordCurrent) { + postParams.passwordConfirmation = this.passwordCurrent; + } + updateSettings(postParams); }; } diff --git a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html index d614aebcd2..89ec94e5db 100644 --- a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html +++ b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html @@ -50,7 +50,6 @@ name="user_password" ng-model="$ctrl.user.password" title="Password" - ng-change="$ctrl.isPasswordChanged = !! $ctrl.user.password;" disabled="$ctrl.isSavingUserInfo || ($ctrl.currentUserRole != 'superuser' && !$ctrl.isAdd)" > </div> @@ -145,10 +144,15 @@ <div class="change-password-modal modal"> <div class="modal-content"> - <h2>{{:: 'UsersManager_AreYouSure'|translate }}</h2> - <p piwik-translate="UsersManager_AreYouSureChangePassword"> - <strong>{{ $ctrl.user.login }}</strong> - </p> + <h2 piwik-translate="UsersManager_AreYouSureChangeDetails"><strong>{{ $ctrl.user.login }}</strong></h2> + <p>{{:: 'UsersManager_ConfirmWithPassword'|translate }}</p> + + <div piwik-field uicontrol="password" name="currentUserPassword" autocomplete="off" + ng-model="$ctrl.passwordConfirmation" + full-width="true" + title="{{ 'UsersManager_YourCurrentPassword'|translate }}" + value=""> + </div> </div> <div class="modal-footer"> <a href="" class="modal-action modal-close btn" ng-click="$ctrl.updateUser()">{{:: 'General_Yes'|translate }}</a> diff --git a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js index e8e9483935..26bcdad072 100644 --- a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js +++ b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js @@ -31,10 +31,10 @@ vm.activeTab = 'basic'; vm.permissionsForIdSite = 1; vm.isSavingUserInfo = false; - vm.isPasswordChanged = false; vm.userHasAccess = true; vm.firstSiteAccess = null; vm.isUserModified = false; + vm.passwordConfirmation = ''; vm.$onInit = $onInit; vm.$onChanges = $onChanges; @@ -77,8 +77,20 @@ $element.find('.superuser-confirm-modal').openModal({ dismissible: false }); } - function confirmPasswordChange() { - $element.find('.change-password-modal').openModal({ dismissible: false }); + function confirmUserChange() { + vm.passwordConfirmation = ''; + function onEnter(event){ + var keycode = (event.keyCode ? event.keyCode : event.which); + if (keycode == '13'){ + $element.find('.change-password-modal').closeModal(); + vm.updateUser(); + } + } + + $element.find('.change-password-modal').openModal({ dismissible: false, ready: function () { + $('.modal.open #currentUserPassword').focus(); + $('.modal.open #currentUserPassword').off('keypress').keypress(onEnter); + }}); } function toggleSuperuserAccess() { @@ -99,10 +111,8 @@ function saveUserInfo() { if (vm.isAdd) { createUser(); - } else if (vm.isPasswordChanged) { - confirmPasswordChange(); } else { - updateUser(); + confirmUserChange(); } } @@ -129,7 +139,7 @@ vm.firstSiteAccess = null; vm.isSavingUserInfo = false; vm.isAdd = false; - vm.isPasswordChanged = false; + vm.isEmailChanged = false; vm.isUserModified = true; showUserSavedNotification(); @@ -142,15 +152,17 @@ method: 'UsersManager.updateUser' }, { userLogin: vm.user.login, - password: vm.isPasswordChanged ? vm.user.password : undefined, + password: vm.user.password ? vm.user.password : undefined, + passwordConfirmation: vm.passwordConfirmation ? vm.passwordConfirmation : undefined, email: vm.user.email, alias: vm.user.alias }).catch(function (e) { vm.isSavingUserInfo = false; + vm.passwordConfirmation = false; throw e; }).then(function () { vm.isSavingUserInfo = false; - vm.isPasswordChanged = false; + vm.passwordConfirmation = false; vm.isUserModified = true; showUserSavedNotification(); diff --git a/plugins/UsersManager/lang/en.json b/plugins/UsersManager/lang/en.json index 438ec55fd8..127d594a86 100644 --- a/plugins/UsersManager/lang/en.json +++ b/plugins/UsersManager/lang/en.json @@ -52,6 +52,9 @@ "GiveViewAccessTitle": "Give an existing user access to view reports for %s", "GiveViewAccessInstructions": "To give an existing user view access for %s enter the username or email address of an existing user", "IfYouWouldLikeToChangeThePasswordTypeANewOne": "If you would like to change the password type a new one. Otherwise leave this blank.", + "YourCurrentPassword": "Your current password", + "CurrentPasswordNotCorrect": "The current password you entered is not correct.", + "ConfirmWithPassword": "Please enter your password to confirm this change.", "InjectedHostCannotChangePwd": "You are currently visiting with an unknown host (%1$s). You cannot change your password until this problem is fixed.", "LastSeen": "Last seen", "MainDescription": "Decide which users have access to your websites. You can also give access to all the websites at once by choosing \"Apply to all websites\" in the website selector.", @@ -135,7 +138,7 @@ "DeleteUserConfirmMultiple": "Are you sure you want to delete the %1$s selected users?", "DeleteUserPermConfirmSingle": "Are you sure you want to change %1$s's role to %2$s for %3$s?", "DeleteUserPermConfirmMultiple": "Are you sure you want to change the %1$s selected users' role to %2$s for %3$s?", - "AreYouSureChangePassword": "Are you sure you want to change the password for %s?", + "AreYouSureChangeDetails": "Are you sure you want to change the user information for %s?", "AnonymousUserRoleChangeWarning": "Giving the %1$s user the %2$s role will make this website's data public and available to everyone, even if they do not have a Matomo login." } } diff --git a/plugins/UsersManager/stylesheets/usersManager.less b/plugins/UsersManager/stylesheets/usersManager.less index 11294a2f84..3def95dce6 100644 --- a/plugins/UsersManager/stylesheets/usersManager.less +++ b/plugins/UsersManager/stylesheets/usersManager.less @@ -90,3 +90,11 @@ min-width: 300px; } } + +#confirmChangesWithPassword { + .modal-no { + float: right; + margin-right: 1em; + margin-top: 1em; + } +}
\ No newline at end of file diff --git a/plugins/UsersManager/templates/userSettings.twig b/plugins/UsersManager/templates/userSettings.twig index 0b6ef9fb78..45f8d7359a 100644 --- a/plugins/UsersManager/templates/userSettings.twig +++ b/plugins/UsersManager/templates/userSettings.twig @@ -22,6 +22,7 @@ <div piwik-field uicontrol="text" name="email" ng-model="personalSettings.email" + ng-change="personalSettings.requirePasswordConfirmation()" maxlength="100" title="{{ 'UsersManager_Email'|translate|e('html_attr') }}" value="{{ userEmail }}"> @@ -75,6 +76,7 @@ <div piwik-field uicontrol="password" name="password" autocomplete="off" ng-model="personalSettings.password" + ng-change="personalSettings.requirePasswordConfirmation()" introduction="{{ 'General_ChangePassword'|translate|e('html_attr') }}" title="{{ 'Login_NewPassword'|translate|e('html_attr') }}" value="" inline-help="{{ 'UsersManager_IfYouWouldLikeToChangeThePasswordTypeANewOne'|translate|e('html_attr') }}"> @@ -82,6 +84,7 @@ <div piwik-field uicontrol="password" name="passwordBis" autocomplete="off" ng-model="personalSettings.passwordBis" + ng-change="personalSettings.requirePasswordConfirmation()" title="{{ 'Login_NewPasswordRepeat'|translate|e('html_attr') }}" value="" inline-help="{{ 'UsersManager_TypeYourPasswordAgain'|translate|e('html_attr') }}"> </div> @@ -97,6 +100,23 @@ <div piwik-save-button onconfirm="personalSettings.save()" saving="personalSettings.loading"></div> + <div class="modal" id="confirmChangesWithPassword"> + <div class="modal-content"> + <h2>{{ 'UsersManager_ConfirmWithPassword'|translate }}</h2> + + <div piwik-field uicontrol="password" name="currentPassword" autocomplete="off" + ng-model="personalSettings.passwordCurrent" + full-width="true" + title="{{ 'UsersManager_YourCurrentPassword'|translate|e('html_attr') }}" + value=""> + </div> + </div> + <div class="modal-footer"> + <a href="javascript:void(0)" class="modal-action btn" ng-click="personalSettings.save()">{{ 'General_Ok'|translate }}</a> + <a href="javascript:void(0)" class="modal-action modal-close modal-no" ng-click="personalSettings.cancelSave()">{{ 'General_Cancel'|translate }}</a> + </div> + </div> + </form> </div> diff --git a/plugins/UsersManager/tests/Integration/APITest.php b/plugins/UsersManager/tests/Integration/APITest.php index 59ba9bad33..2e2040ef79 100644 --- a/plugins/UsersManager/tests/Integration/APITest.php +++ b/plugins/UsersManager/tests/Integration/APITest.php @@ -138,6 +138,8 @@ class APITest extends IntegrationTestCase private $login = 'userLogin'; + private $password = 'password'; + public function setUp() { parent::setUp(); @@ -151,7 +153,7 @@ class APITest extends IntegrationTestCase Fixture::createWebsite('2014-01-01 00:00:00'); Fixture::createWebsite('2014-01-01 00:00:00'); Fixture::createWebsite('2014-01-01 00:00:00'); - $this->api->addUser($this->login, 'password', 'userlogin@password.de'); + $this->api->addUser($this->login, $this->password, 'userlogin@password.de'); } public function test_setUserAccess_ShouldTriggerRemoveSiteAccessEvent_IfAccessToAWebsiteIsRemoved() @@ -291,7 +293,10 @@ class APITest extends IntegrationTestCase public function test_updateUser() { - $this->api->updateUser($this->login, 'newPassword', 'email@example.com', 'newAlias', false); + $identity = FakeAccess::$identity; + FakeAccess::$identity = $this->login; // ensure password will be checked against this user + $this->api->updateUser($this->login, 'newPassword', 'email@example.com', 'newAlias', false, $this->password); + FakeAccess::$identity = $identity; $model = new Model(); $user = $model->getUser($this->login); @@ -309,7 +314,10 @@ class APITest extends IntegrationTestCase $model = new Model(); $userBefore = $model->getUser($this->login); - $this->api->updateUser($this->login, false, 'email@example.com', 'newAlias', false); + $identity = FakeAccess::$identity; + FakeAccess::$identity = $this->login; // ensure password will be checked against this user + $this->api->updateUser($this->login, false, 'email@example.com', 'newAlias', false, $this->password); + FakeAccess::$identity = $identity; $user = $model->getUser($this->login); @@ -323,7 +331,7 @@ class APITest extends IntegrationTestCase */ public function test_updateUser_failsIfPasswordTooLong() { - $this->api->updateUser($this->login, str_pad('foo', UsersManager::PASSWORD_MAX_LENGTH + 1), 'email@example.com', 'newAlias'); + $this->api->updateUser($this->login, str_pad('foo', UsersManager::PASSWORD_MAX_LENGTH + 1), 'email@example.com', 'newAlias', false, $this->password); } public function test_getSitesAccessFromUser_forSuperUser() diff --git a/plugins/UsersManager/tests/Integration/UsersManagerTest.php b/plugins/UsersManager/tests/Integration/UsersManagerTest.php index 961343f2a7..c8c2262137 100644 --- a/plugins/UsersManager/tests/Integration/UsersManagerTest.php +++ b/plugins/UsersManager/tests/Integration/UsersManagerTest.php @@ -39,6 +39,8 @@ class UsersManagerTest extends IntegrationTestCase */ private $model; + private $backupIdentity; + public function setUp() { parent::setUp(); @@ -55,11 +57,18 @@ class UsersManagerTest extends IntegrationTestCase //finally we set the user as a Super User by default FakeAccess::$superUser = true; FakeAccess::$superUserLogin = 'superusertest'; + $this->backupIdentity = FakeAccess::$identity; $this->api = API::getInstance(); $this->model = new Model(); } + public function tearDown() + { + FakeAccess::$identity = $this->backupIdentity; + parent::tearDown(); + } + private function _flatten($sitesAccess) { $result = array(); @@ -932,13 +941,69 @@ class UsersManagerTest extends IntegrationTestCase 'email' => "test@test.com", 'alias' => "alias"); + $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']); - $this->api->updateUser($login, "passowordOK"); + + FakeAccess::$identity = 'login'; + $this->api->updateUser($login, "passowordOK", false, false, false, "geqgeagae"); $this->_checkUserHasNotChanged($user, "passowordOK"); } /** + * @expectedException \Exception + * @expectedExceptionMessage UsersManager_ConfirmWithPassword + */ + public function testUpdateUserFailsNoCurrentPassword() + { + $login = "login"; + $user = array('login' => $login, + 'password' => "geqgeagae", + 'email' => "test@test.com", + 'alias' => "alias"); + + $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']); + + FakeAccess::$identity = 'login'; + $this->api->updateUser($login, "passowordOK", false, false, false, ""); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage UsersManager_CurrentPasswordNotCorrect + */ + public function testUpdateUserFailsWrongCurrentPassword() + { + $login = "login"; + $user = array('login' => $login, + 'password' => "geqgeagae", + 'email' => "test@test.com", + 'alias' => "alias"); + + $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']); + + FakeAccess::$identity = 'login'; + $this->api->updateUser($login, "passowordOK", false, false, false, "geqgeag"); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage UsersManager_CurrentPasswordNotCorrect + */ + public function testUpdateUserFailsWrongCurrentPassword_requiresThePasswordOfCurrentLoggedInUser() + { + $login = "login"; + $user = array('login' => $login, + 'password' => "geqgeagae", + 'email' => "test@test.com", + 'alias' => "alias"); + + $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']); + // currently logged in is a super user and not "login". therefore the password of "login" won't work + $this->api->updateUser($login, "passowordOK", false, false, false, "geqgeag"); + } + + /** * no email => keep old ones */ public function testUpdateUserNoEmail() @@ -950,7 +1015,9 @@ class UsersManagerTest extends IntegrationTestCase 'alias' => "alias"); $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']); - $this->api->updateUser($login, "passowordOK", null, "newalias"); + + FakeAccess::$identity = 'login'; + $this->api->updateUser($login, "passowordOK", null, "newalias", false, "geqgeagae"); $this->_checkUserHasNotChanged($user, "passowordOK", null, "newalias"); } @@ -967,7 +1034,9 @@ class UsersManagerTest extends IntegrationTestCase 'alias' => "alias"); $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']); - $this->api->updateUser($login, "passowordOK", "email@geaga.com"); + + FakeAccess::$identity = 'login'; + $this->api->updateUser($login, "passowordOK", "email@geaga.com", false, false, "geqgeagae"); $this->_checkUserHasNotChanged($user, "passowordOK", "email@geaga.com"); } @@ -1007,7 +1076,9 @@ class UsersManagerTest extends IntegrationTestCase 'alias' => "alias"); $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']); - $this->api->updateUser($login, "passowordOK", "email@geaga.com", "NEW ALIAS"); + + FakeAccess::$identity = 'login'; + $this->api->updateUser($login, "passowordOK", "email@geaga.com", "NEW ALIAS", false, "geqgeagae"); $this->_checkUserHasNotChanged($user, "passowordOK", "email@geaga.com", "NEW ALIAS"); } diff --git a/plugins/UsersManager/tests/UI/UsersManager_spec.js b/plugins/UsersManager/tests/UI/UsersManager_spec.js index 77ada45f80..fce6e321a3 100644 --- a/plugins/UsersManager/tests/UI/UsersManager_spec.js +++ b/plugins/UsersManager/tests/UI/UsersManager_spec.js @@ -362,7 +362,28 @@ describe("UsersManager", function () { expect.screenshot("edit_user_form").to.be.captureSelector('.admin#content', function (page) { page.setViewportSize(1250); - page.click('button.edituser:eq(0)'); + page.click('button.edituser:eq(1)'); + }, done); + }); + + it('should ask for password confirmation when trying to change email', function (done) { + expect.screenshot("edit_user_basic_asks_confirmation").to.be.captureSelector('.modal.open', function (page) { + page.setViewportSize(1250); + + page.evaluate(function () { + $('.userEditForm #user_email').val('testlogin3@example.com').change(); + }); + + page.click('.userEditForm .basic-info-tab [piwik-save-button] .btn'); + }, done); + }); + + it('should show error when wrong password entered', function (done) { + expect.screenshot("edit_user_basic_confirmed_wrong_password").to.be.captureSelector('.admin#content,#notificationContainer', function (page) { + page.setViewportSize(1250); + + page.sendKeys('.modal.open #currentUserPassword', 'test123456'); + page.click('.change-password-modal .modal-close:not(.modal-no)'); }, done); }); diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_asks_confirmation.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_asks_confirmation.png new file mode 100644 index 0000000000..d4c84a5976 --- /dev/null +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_asks_confirmation.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc3f0fcd3ac18b88a19fb3afef08bd8d31f3dd6aef1a1aea2231bb2663a78d9e +size 22237 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_confirmed_wrong_password.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_confirmed_wrong_password.png new file mode 100644 index 0000000000..152212b899 --- /dev/null +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_confirmed_wrong_password.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6acdba605cb48293c18abd9b11730c32b0096378bc6d2ca33d9aefcded633f07 +size 30051 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_form.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_form.png deleted file mode 100644 index cc0d1b9d10..0000000000 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_form.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7dca2ceb788156e59cd81a15474f6db7d76d5d30ea9a64d2b1d01c2f4ed8a4ec -size 22671 |