]> source.dussan.org Git - nextcloud-server.git/commitdiff
feat(Security): Allow setting password context for validation and generation
authorFerdinand Thiessen <opensource@fthiessen.de>
Wed, 21 Aug 2024 18:23:27 +0000 (20:23 +0200)
committerFerdinand Thiessen <opensource@fthiessen.de>
Thu, 22 Aug 2024 17:16:50 +0000 (19:16 +0200)
Co-authored-by: Ferdinand Thiessen <opensource@fthiessen.de>
Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com>
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
lib/composer/composer/autoload_classmap.php
lib/composer/composer/autoload_static.php
lib/public/Security/Events/GenerateSecurePasswordEvent.php
lib/public/Security/Events/ValidatePasswordPolicyEvent.php
lib/public/Security/PasswordContext.php [new file with mode: 0644]
tests/lib/Security/Events/GenerateSecurePasswordEventTest.php [new file with mode: 0644]
tests/lib/Security/Events/ValidatePasswordPolicyEventTest.php [new file with mode: 0644]

index 1a3a86fd2077619ac29412a479cd2821e5a7094d..eed05ce73d6c5c284a49503f32d2a5aee589c667 100644 (file)
@@ -678,6 +678,7 @@ return array(
     'OCP\\Security\\Ip\\IFactory' => $baseDir . '/lib/public/Security/Ip/IFactory.php',
     'OCP\\Security\\Ip\\IRange' => $baseDir . '/lib/public/Security/Ip/IRange.php',
     'OCP\\Security\\Ip\\IRemoteAddress' => $baseDir . '/lib/public/Security/Ip/IRemoteAddress.php',
+    'OCP\\Security\\PasswordContext' => $baseDir . '/lib/public/Security/PasswordContext.php',
     'OCP\\Security\\RateLimiting\\ILimiter' => $baseDir . '/lib/public/Security/RateLimiting/ILimiter.php',
     'OCP\\Security\\RateLimiting\\IRateLimitExceededException' => $baseDir . '/lib/public/Security/RateLimiting/IRateLimitExceededException.php',
     'OCP\\Security\\VerificationToken\\IVerificationToken' => $baseDir . '/lib/public/Security/VerificationToken/IVerificationToken.php',
index c636ba769f93599d2492cb23a292f25da4678006..ac293dd7b36f395de035bc39418328d1541fe506 100644 (file)
@@ -711,6 +711,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'OCP\\Security\\Ip\\IFactory' => __DIR__ . '/../../..' . '/lib/public/Security/Ip/IFactory.php',
         'OCP\\Security\\Ip\\IRange' => __DIR__ . '/../../..' . '/lib/public/Security/Ip/IRange.php',
         'OCP\\Security\\Ip\\IRemoteAddress' => __DIR__ . '/../../..' . '/lib/public/Security/Ip/IRemoteAddress.php',
+        'OCP\\Security\\PasswordContext' => __DIR__ . '/../../..' . '/lib/public/Security/PasswordContext.php',
         'OCP\\Security\\RateLimiting\\ILimiter' => __DIR__ . '/../../..' . '/lib/public/Security/RateLimiting/ILimiter.php',
         'OCP\\Security\\RateLimiting\\IRateLimitExceededException' => __DIR__ . '/../../..' . '/lib/public/Security/RateLimiting/IRateLimitExceededException.php',
         'OCP\\Security\\VerificationToken\\IVerificationToken' => __DIR__ . '/../../..' . '/lib/public/Security/VerificationToken/IVerificationToken.php',
index 8adddd529b0cb635ac5f72358d2d7a7935ae3015..419e7b40ee4c3900d3413a6ef3ade4a6d96a10ff 100644 (file)
@@ -9,15 +9,34 @@ declare(strict_types=1);
 namespace OCP\Security\Events;
 
 use OCP\EventDispatcher\Event;
+use OCP\Security\PasswordContext;
 
 /**
+ * Event to request a secure password to be generated
  * @since 18.0.0
  */
 class GenerateSecurePasswordEvent extends Event {
-       /** @var null|string */
-       private $password;
+       private ?string $password;
 
        /**
+        * Request a secure password to be generated.
+        *
+        * By default passwords are generated for the user account context,
+        * this can be adjusted by passing another `PasswordContext`.
+        * @since 31.0.0
+        */
+       public function __construct(
+               private PasswordContext $context = PasswordContext::ACCOUNT,
+       ) {
+               parent::__construct();
+               $this->password = null;
+       }
+
+       /**
+        * Get the generated password.
+        *
+        * If a password generator is registered and successfully generated a password
+        * that password can get read back. Otherwise `null` is returned.
         * @since 18.0.0
         */
        public function getPassword(): ?string {
@@ -25,9 +44,20 @@ class GenerateSecurePasswordEvent extends Event {
        }
 
        /**
+        * Set the generated password.
+        *
+        * This is used by password generators to set the generated password.
         * @since 18.0.0
         */
        public function setPassword(string $password): void {
                $this->password = $password;
        }
+
+       /**
+        * Get the context this password should generated for.
+        * @since 31.0.0
+        */
+       public function getContext(): PasswordContext {
+               return $this->context;
+       }
 }
index 0aa8b516f708a0b77dacfecfcfe394157f8a38fd..d7ac9442392f770ed546c0e0b0c583fb42aa6435 100644 (file)
@@ -9,26 +9,41 @@ declare(strict_types=1);
 namespace OCP\Security\Events;
 
 use OCP\EventDispatcher\Event;
+use OCP\Security\PasswordContext;
 
 /**
+ * This event can be emitted to request a validation of a password.
+ *
+ * If a password policy app is installed and the password
+ * is invalid, an `\OCP\HintException` will be thrown.
  * @since 18.0.0
  */
 class ValidatePasswordPolicyEvent extends Event {
-       /** @var string */
-       private $password;
 
        /**
         * @since 18.0.0
+        * @since 31.0.0 - $context parameter added
         */
-       public function __construct(string $password) {
+       public function __construct(
+               private string $password,
+               private PasswordContext $context = PasswordContext::ACCOUNT,
+       ) {
                parent::__construct();
-               $this->password = $password;
        }
 
        /**
+        * Get the password that should be validated.
         * @since 18.0.0
         */
        public function getPassword(): string {
                return $this->password;
        }
+
+       /**
+        * Get the context this password should validated for.
+        * @since 31.0.0
+        */
+       public function getContext(): PasswordContext {
+               return $this->context;
+       }
 }
diff --git a/lib/public/Security/PasswordContext.php b/lib/public/Security/PasswordContext.php
new file mode 100644 (file)
index 0000000..909070c
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Security;
+
+/**
+ * Define the context in which a password is used.
+ * This allows setting a context for password validation and password generation.
+ *
+ * @package OCP\Security
+ * @since 31.0.0
+ */
+enum PasswordContext {
+       /**
+        * Password used for an user account
+        * @since 31.0.0
+        */
+       case ACCOUNT;
+
+       /**
+        * Password used for (public) shares
+        * @since 31.0.0
+        */
+       case SHARING;
+}
diff --git a/tests/lib/Security/Events/GenerateSecurePasswordEventTest.php b/tests/lib/Security/Events/GenerateSecurePasswordEventTest.php
new file mode 100644 (file)
index 0000000..29002a9
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\Security\Events;
+
+use OCP\Security\Events\GenerateSecurePasswordEvent;
+use OCP\Security\PasswordContext;
+
+class GenerateSecurePasswordEventTest extends \Test\TestCase {
+
+       public function testDefaultProperties() {
+               $event = new GenerateSecurePasswordEvent();
+               $this->assertNull($event->getPassword());
+               $this->assertEquals(PasswordContext::ACCOUNT, $event->getContext());
+       }
+
+       public function testSettingPassword() {
+               $event = new GenerateSecurePasswordEvent();
+               $event->setPassword('example');
+               $this->assertEquals('example', $event->getPassword());
+       }
+
+       public function testSettingContext() {
+               $event = new GenerateSecurePasswordEvent(PasswordContext::SHARING);
+               $this->assertEquals(PasswordContext::SHARING, $event->getContext());
+       }
+}
diff --git a/tests/lib/Security/Events/ValidatePasswordPolicyEventTest.php b/tests/lib/Security/Events/ValidatePasswordPolicyEventTest.php
new file mode 100644 (file)
index 0000000..8a7bc3b
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\Security\Events;
+
+use OCP\Security\Events\ValidatePasswordPolicyEvent;
+use OCP\Security\PasswordContext;
+
+class ValidatePasswordPolicyEventTest extends \Test\TestCase {
+
+       public function testDefaultProperties() {
+               $password = 'example';
+               $event = new ValidatePasswordPolicyEvent($password);
+               $this->assertEquals($password, $event->getPassword());
+               $this->assertEquals(PasswordContext::ACCOUNT, $event->getContext());
+       }
+
+       public function testSettingContext() {
+               $event = new ValidatePasswordPolicyEvent('example', PasswordContext::SHARING);
+               $this->assertEquals(PasswordContext::SHARING, $event->getContext());
+       }
+}