Skip to content

Commit

Permalink
feat(Security): Allow setting password context for validation and gen…
Browse files Browse the repository at this point in the history
…eration

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>
  • Loading branch information
susnux and nickvergessen committed Aug 21, 2024
1 parent b36ced8 commit 3c51924
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 6 deletions.
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@
'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',
Expand Down
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
34 changes: 32 additions & 2 deletions lib/public/Security/Events/GenerateSecurePasswordEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,55 @@
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 {
return $this->password;
}

/**
* 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;
}
}
23 changes: 19 additions & 4 deletions lib/public/Security/Events/ValidatePasswordPolicyEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,41 @@
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;
}
}
29 changes: 29 additions & 0 deletions lib/public/Security/PasswordContext.php
Original file line number Diff line number Diff line change
@@ -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: string {
/**
* Password used for an user account
* @since 31.0.0
*/
case ACCOUNT = 'account';

/**
* Password used for (public) shares
* @since 31.0.0
*/
case SHARING = 'sharing';
}
33 changes: 33 additions & 0 deletions tests/lib/Security/Events/GenerateSecurePasswordEventTest.php
Original file line number Diff line number Diff line change
@@ -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());
}
}
28 changes: 28 additions & 0 deletions tests/lib/Security/Events/ValidatePasswordPolicyEventTest.php
Original file line number Diff line number Diff line change
@@ -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());
}
}

0 comments on commit 3c51924

Please sign in to comment.