summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoeland Jago Douma <rullzer@users.noreply.github.com>2019-11-27 11:11:17 +0100
committerGitHub <noreply@github.com>2019-11-27 11:11:17 +0100
commit0532f8116da1ed92b973c8842c4d18f084255820 (patch)
treef259a529e238cb66cf3d89a25d2203a2065f5e7e
parentd2f9deba51d6c3944344fb8e0b8731a049923dba (diff)
parent1a886b1472cad1fb04e8073d2749514e2d97a506 (diff)
downloadnextcloud-server-0532f8116da1ed92b973c8842c4d18f084255820.tar.gz
nextcloud-server-0532f8116da1ed92b973c8842c4d18f084255820.zip
Merge pull request #18019 from nextcloud/enhancement/password-policy-events
Add typed events for password_policy
-rw-r--r--lib/composer/composer/autoload_classmap.php2
-rw-r--r--lib/composer/composer/autoload_static.php2
-rw-r--r--lib/private/Share20/Manager.php4
-rw-r--r--lib/private/User/Database.php15
-rw-r--r--lib/public/Security/Events/GenerateSecurePasswordEvent.php50
-rw-r--r--lib/public/Security/Events/ValidatePasswordPolicyEvent.php51
-rw-r--r--tests/lib/Share20/ManagerTest.php55
-rw-r--r--tests/lib/User/DatabaseTest.php32
8 files changed, 163 insertions, 48 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index f2c5eae91e0..3d73c7b690d 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -386,6 +386,8 @@ return array(
'OCP\\Search\\Provider' => $baseDir . '/lib/public/Search/Provider.php',
'OCP\\Search\\Result' => $baseDir . '/lib/public/Search/Result.php',
'OCP\\Security\\CSP\\AddContentSecurityPolicyEvent' => $baseDir . '/lib/public/Security/CSP/AddContentSecurityPolicyEvent.php',
+ 'OCP\\Security\\Events\\GenerateSecurePasswordEvent' => $baseDir . '/lib/public/Security/Events/GenerateSecurePasswordEvent.php',
+ 'OCP\\Security\\Events\\ValidatePasswordPolicyEvent' => $baseDir . '/lib/public/Security/Events/ValidatePasswordPolicyEvent.php',
'OCP\\Security\\FeaturePolicy\\AddFeaturePolicyEvent' => $baseDir . '/lib/public/Security/FeaturePolicy/AddFeaturePolicyEvent.php',
'OCP\\Security\\IContentSecurityPolicyManager' => $baseDir . '/lib/public/Security/IContentSecurityPolicyManager.php',
'OCP\\Security\\ICredentialsManager' => $baseDir . '/lib/public/Security/ICredentialsManager.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index d806718a0ab..e00acfbfdb5 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -415,6 +415,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Search\\Provider' => __DIR__ . '/../../..' . '/lib/public/Search/Provider.php',
'OCP\\Search\\Result' => __DIR__ . '/../../..' . '/lib/public/Search/Result.php',
'OCP\\Security\\CSP\\AddContentSecurityPolicyEvent' => __DIR__ . '/../../..' . '/lib/public/Security/CSP/AddContentSecurityPolicyEvent.php',
+ 'OCP\\Security\\Events\\GenerateSecurePasswordEvent' => __DIR__ . '/../../..' . '/lib/public/Security/Events/GenerateSecurePasswordEvent.php',
+ 'OCP\\Security\\Events\\ValidatePasswordPolicyEvent' => __DIR__ . '/../../..' . '/lib/public/Security/Events/ValidatePasswordPolicyEvent.php',
'OCP\\Security\\FeaturePolicy\\AddFeaturePolicyEvent' => __DIR__ . '/../../..' . '/lib/public/Security/FeaturePolicy/AddFeaturePolicyEvent.php',
'OCP\\Security\\IContentSecurityPolicyManager' => __DIR__ . '/../../..' . '/lib/public/Security/IContentSecurityPolicyManager.php',
'OCP\\Security\\ICredentialsManager' => __DIR__ . '/../../..' . '/lib/public/Security/ICredentialsManager.php',
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index d9809fd128a..210dc7772c0 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -55,6 +55,7 @@ use OCP\IUser;
use OCP\IUserManager;
use OCP\L10N\IFactory;
use OCP\Mail\IMailer;
+use OCP\Security\Events\ValidatePasswordPolicyEvent;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
use OCP\Share;
@@ -191,8 +192,7 @@ class Manager implements IManager {
// Let others verify the password
try {
- $event = new GenericEvent($password);
- $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
+ $this->eventDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
} catch (HintException $e) {
throw new \Exception($e->getHint());
}
diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php
index 23dbe8c2334..a4c35deb2b8 100644
--- a/lib/private/User/Database.php
+++ b/lib/private/User/Database.php
@@ -58,7 +58,9 @@ declare(strict_types=1);
namespace OC\User;
use OC\Cache\CappedMemoryCache;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
+use OCP\Security\Events\ValidatePasswordPolicyEvent;
use OCP\User\Backend\ABackend;
use OCP\User\Backend\ICheckPasswordBackend;
use OCP\User\Backend\ICountUsersBackend;
@@ -68,7 +70,6 @@ use OCP\User\Backend\IGetHomeBackend;
use OCP\User\Backend\IGetRealUIDBackend;
use OCP\User\Backend\ISetDisplayNameBackend;
use OCP\User\Backend\ISetPasswordBackend;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
/**
@@ -86,7 +87,7 @@ class Database extends ABackend
/** @var CappedMemoryCache */
private $cache;
- /** @var EventDispatcherInterface */
+ /** @var IEventDispatcher */
private $eventDispatcher;
/** @var IDBConnection */
@@ -98,13 +99,13 @@ class Database extends ABackend
/**
* \OC\User\Database constructor.
*
- * @param EventDispatcherInterface $eventDispatcher
+ * @param IEventDispatcher $eventDispatcher
* @param string $table
*/
public function __construct($eventDispatcher = null, $table = 'users') {
$this->cache = new CappedMemoryCache();
$this->table = $table;
- $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->getEventDispatcher();
+ $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->query(IEventDispatcher::class);
}
/**
@@ -130,8 +131,7 @@ class Database extends ABackend
$this->fixDI();
if (!$this->userExists($uid)) {
- $event = new GenericEvent($password);
- $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
+ $this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
$qb = $this->dbConn->getQueryBuilder();
$qb->insert($this->table)
@@ -199,8 +199,7 @@ class Database extends ABackend
$this->fixDI();
if ($this->userExists($uid)) {
- $event = new GenericEvent($password);
- $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
+ $this->eventDispatcher->dispatchTyped(new ValidatePasswordPolicyEvent($password));
$hasher = \OC::$server->getHasher();
$hashedPassword = $hasher->hash($password);
diff --git a/lib/public/Security/Events/GenerateSecurePasswordEvent.php b/lib/public/Security/Events/GenerateSecurePasswordEvent.php
new file mode 100644
index 00000000000..a55c8daafbd
--- /dev/null
+++ b/lib/public/Security/Events/GenerateSecurePasswordEvent.php
@@ -0,0 +1,50 @@
+<?php declare(strict_types=1);
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Security\Events;
+
+use OCP\EventDispatcher\Event;
+
+/**
+ * @since 18.0.0
+ */
+class GenerateSecurePasswordEvent extends Event {
+
+ /** @var null|string */
+ private $password;
+
+ /**
+ * @since 18.0.0
+ */
+ public function getPassword(): ?string {
+ return $this->password;
+ }
+
+ /**
+ * @since 18.0.0
+ */
+ public function setPassword(string $password): void {
+ $this->password = $password;
+ }
+
+}
diff --git a/lib/public/Security/Events/ValidatePasswordPolicyEvent.php b/lib/public/Security/Events/ValidatePasswordPolicyEvent.php
new file mode 100644
index 00000000000..11378526cc7
--- /dev/null
+++ b/lib/public/Security/Events/ValidatePasswordPolicyEvent.php
@@ -0,0 +1,51 @@
+<?php declare(strict_types=1);
+
+/**
+ * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCP\Security\Events;
+
+use OCP\EventDispatcher\Event;
+
+/**
+ * @since 18.0.0
+ */
+class ValidatePasswordPolicyEvent extends Event {
+
+ /** @var string */
+ private $password;
+
+ /**
+ * @since 18.0.0
+ */
+ public function __construct(string $password) {
+ parent::__construct();
+ $this->password = $password;
+ }
+
+ /**
+ * @since 18.0.0
+ */
+ public function getPassword(): string {
+ return $this->password;
+ }
+
+}
diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php
index 26008c2a3de..3e34a64acf3 100644
--- a/tests/lib/Share20/ManagerTest.php
+++ b/tests/lib/Share20/ManagerTest.php
@@ -27,6 +27,7 @@ use OC\Share20\DefaultShareProvider;
use OC\Share20\Exception;
use OC\Share20\Manager;
use OC\Share20\Share;
+use OCP\EventDispatcher\Event;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
@@ -42,16 +43,18 @@ use OCP\ILogger;
use OCP\IServerContainer;
use OCP\IURLGenerator;
use OCP\IUser;
-
use OCP\IUserManager;
use OCP\L10N\IFactory;
use OCP\Mail\IMailer;
+use OCP\Security\Events\ValidatePasswordPolicyEvent;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
+use PHPUnit\Framework\MockObject\MockBuilder;
+use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
@@ -65,37 +68,37 @@ class ManagerTest extends \Test\TestCase {
/** @var Manager */
protected $manager;
- /** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var ILogger|MockObject */
protected $logger;
- /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IConfig|MockObject */
protected $config;
- /** @var ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var ISecureRandom|MockObject */
protected $secureRandom;
- /** @var IHasher|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IHasher|MockObject */
protected $hasher;
- /** @var IShareProvider|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IShareProvider|MockObject */
protected $defaultProvider;
- /** @var IMountManager|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IMountManager|MockObject */
protected $mountManager;
- /** @var IGroupManager|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IGroupManager|MockObject */
protected $groupManager;
- /** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IL10N|MockObject */
protected $l;
- /** @var IFactory|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IFactory|MockObject */
protected $l10nFactory;
/** @var DummyFactory */
protected $factory;
- /** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IUserManager|MockObject */
protected $userManager;
- /** @var IRootFolder | \PHPUnit_Framework_MockObject_MockObject */
+ /** @var IRootFolder | MockObject */
protected $rootFolder;
- /** @var EventDispatcherInterface | \PHPUnit_Framework_MockObject_MockObject */
+ /** @var EventDispatcherInterface | MockObject */
protected $eventDispatcher;
- /** @var IMailer|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IMailer|MockObject */
protected $mailer;
- /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IURLGenerator|MockObject */
protected $urlGenerator;
- /** @var \OC_Defaults|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var \OC_Defaults|MockObject */
protected $defaults;
public function setUp() {
@@ -146,7 +149,7 @@ class ManagerTest extends \Test\TestCase {
}
/**
- * @return \PHPUnit_Framework_MockObject_MockBuilder
+ * @return MockBuilder
*/
private function createManagerMock() {
return $this->getMockBuilder('\OC\Share20\Manager')
@@ -496,11 +499,12 @@ class ManagerTest extends \Test\TestCase {
]));
$this->eventDispatcher->expects($this->once())->method('dispatch')
- ->willReturnCallback(function($eventName, GenericEvent $event) {
- $this->assertSame('OCP\PasswordPolicy::validate', $eventName);
- $this->assertSame('password', $event->getSubject());
+ ->willReturnCallback(function(Event $event) {
+ $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
+ /** @var ValidatePasswordPolicyEvent $event */
+ $this->assertSame('password', $event->getPassword());
}
- );
+ );
$result = self::invokePrivate($this->manager, 'verifyPassword', ['password']);
$this->assertNull($result);
@@ -516,12 +520,13 @@ class ManagerTest extends \Test\TestCase {
]));
$this->eventDispatcher->expects($this->once())->method('dispatch')
- ->willReturnCallback(function($eventName, GenericEvent $event) {
- $this->assertSame('OCP\PasswordPolicy::validate', $eventName);
- $this->assertSame('password', $event->getSubject());
+ ->willReturnCallback(function(Event $event) {
+ $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
+ /** @var ValidatePasswordPolicyEvent $event */
+ $this->assertSame('password', $event->getPassword());
throw new HintException('message', 'password not accepted');
}
- );
+ );
self::invokePrivate($this->manager, 'verifyPassword', ['password']);
}
diff --git a/tests/lib/User/DatabaseTest.php b/tests/lib/User/DatabaseTest.php
index feba7a6926d..8e52be50c75 100644
--- a/tests/lib/User/DatabaseTest.php
+++ b/tests/lib/User/DatabaseTest.php
@@ -21,10 +21,14 @@
*/
namespace Test\User;
+
use OC\HintException;
use OC\User\User;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Security\Events\ValidatePasswordPolicyEvent;
+use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\GenericEvent;
/**
* Class DatabaseTest
@@ -34,7 +38,7 @@ use Symfony\Component\EventDispatcher\GenericEvent;
class DatabaseTest extends Backend {
/** @var array */
private $users;
- /** @var EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var IEventDispatcher|MockObject */
private $eventDispatcher;
public function getUser() {
@@ -46,7 +50,7 @@ class DatabaseTest extends Backend {
protected function setUp() {
parent::setUp();
- $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
+ $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
$this->backend=new \OC\User\Database($this->eventDispatcher);
}
@@ -65,11 +69,12 @@ class DatabaseTest extends Backend {
$user = $this->getUser();
$this->backend->createUser($user, 'pass1');
- $this->eventDispatcher->expects($this->once())->method('dispatch')
+ $this->eventDispatcher->expects($this->once())->method('dispatchTyped')
->willReturnCallback(
- function ($eventName, GenericEvent $event) {
- $this->assertSame('OCP\PasswordPolicy::validate', $eventName);
- $this->assertSame('newpass', $event->getSubject());
+ function (Event $event) {
+ $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
+ /** @var ValidatePasswordPolicyEvent $event */
+ $this->assertSame('newpass', $event->getPassword());
}
);
@@ -85,11 +90,12 @@ class DatabaseTest extends Backend {
$user = $this->getUser();
$this->backend->createUser($user, 'pass1');
- $this->eventDispatcher->expects($this->once())->method('dispatch')
+ $this->eventDispatcher->expects($this->once())->method('dispatchTyped')
->willReturnCallback(
- function ($eventName, GenericEvent $event) {
- $this->assertSame('OCP\PasswordPolicy::validate', $eventName);
- $this->assertSame('newpass', $event->getSubject());
+ function (Event $event) {
+ $this->assertInstanceOf(ValidatePasswordPolicyEvent::class, $event);
+ /** @var ValidatePasswordPolicyEvent $event */
+ $this->assertSame('newpass', $event->getPassword());
throw new HintException('password change failed', 'password change failed');
}
);
@@ -124,8 +130,8 @@ class DatabaseTest extends Backend {
$user2 = $this->getUser();
$this->backend->createUser($user2, 'pass1');
- $user1Obj = new User($user1, $this->backend, $this->eventDispatcher);
- $user2Obj = new User($user2, $this->backend, $this->eventDispatcher);
+ $user1Obj = new User($user1, $this->backend, $this->createMock(EventDispatcherInterface::class));
+ $user2Obj = new User($user2, $this->backend, $this->createMock(EventDispatcherInterface::class));
$emailAddr1 = "$user1@nextcloud.com";
$emailAddr2 = "$user2@nextcloud.com";