Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Steur <tsteur@users.noreply.github.com>2018-11-30 00:31:54 +0300
committerGitHub <noreply@github.com>2018-11-30 00:31:54 +0300
commit414230d05a03dc703ad5c6263d2499c46bdecde7 (patch)
tree544aa75eaaa7a070f0011320954cbae8ae4d76ca /plugins/UsersManager
parent1d3388c1cd3dd03743576d670118a65e9cd879cb (diff)
When changing password or email address, require to type old password (#13683)
Diffstat (limited to 'plugins/UsersManager')
-rw-r--r--plugins/UsersManager/API.php41
-rw-r--r--plugins/UsersManager/Controller.php24
-rw-r--r--plugins/UsersManager/LastSeenTimeLogger.php2
-rw-r--r--plugins/UsersManager/UserUpdater.php44
-rw-r--r--plugins/UsersManager/UsersManager.php6
-rw-r--r--plugins/UsersManager/angularjs/personal-settings/personal-settings.controller.js31
-rw-r--r--plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html14
-rw-r--r--plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js30
-rw-r--r--plugins/UsersManager/lang/en.json5
-rw-r--r--plugins/UsersManager/stylesheets/usersManager.less8
-rw-r--r--plugins/UsersManager/templates/userSettings.twig20
-rw-r--r--plugins/UsersManager/tests/Integration/APITest.php16
-rw-r--r--plugins/UsersManager/tests/Integration/UsersManagerTest.php79
-rw-r--r--plugins/UsersManager/tests/UI/UsersManager_spec.js23
-rw-r--r--plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_asks_confirmation.png3
-rw-r--r--plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_basic_confirmed_wrong_password.png3
-rw-r--r--plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_edit_user_form.png3
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