-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Inital password reset commit * Revert composer.json * Add headers * Apply php-cs-fixer changes * Consistency check * Try to reformat login mail text * Align at column 24 * move text to const * Apply php-cs-fixer changes * Do not return json response, just return response --------- Co-authored-by: mattamon <[email protected]>
- Loading branch information
Showing
15 changed files
with
628 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
src/Authorization/Attributes/Request/ResetPasswordRequestBody.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
/** | ||
* Pimcore | ||
* | ||
* This source file is available under two different licenses: | ||
* - GNU General Public License version 3 (GPLv3) | ||
* - Pimcore Commercial License (PCL) | ||
* Full copyright and license information is available in | ||
* LICENSE.md which is distributed with this source code. | ||
* | ||
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) | ||
* @license http://www.pimcore.org/license GPLv3 and PCL | ||
*/ | ||
|
||
namespace Pimcore\Bundle\StudioBackendBundle\Authorization\Attributes\Request; | ||
|
||
use Attribute; | ||
use OpenApi\Attributes\JsonContent; | ||
use OpenApi\Attributes\RequestBody; | ||
use Pimcore\Bundle\StudioBackendBundle\Authorization\Schema\ResetPassword; | ||
|
||
#[Attribute(Attribute::TARGET_METHOD)] | ||
final class ResetPasswordRequestBody extends RequestBody | ||
{ | ||
public function __construct() | ||
{ | ||
parent::__construct( | ||
required: true, | ||
content: new JsonContent(ref: ResetPassword::class) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
/** | ||
* Pimcore | ||
* | ||
* This source file is available under two different licenses: | ||
* - GNU General Public License version 3 (GPLv3) | ||
* - Pimcore Commercial License (PCL) | ||
* Full copyright and license information is available in | ||
* LICENSE.md which is distributed with this source code. | ||
* | ||
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) | ||
* @license http://www.pimcore.org/license GPLv3 and PCL | ||
*/ | ||
|
||
namespace Pimcore\Bundle\StudioBackendBundle\Authorization\Controller; | ||
|
||
use OpenApi\Attributes\Post; | ||
use Pimcore\Bundle\StudioBackendBundle\Authorization\Attributes\Request\ResetPasswordRequestBody; | ||
use Pimcore\Bundle\StudioBackendBundle\Authorization\Schema\ResetPassword; | ||
use Pimcore\Bundle\StudioBackendBundle\Authorization\Service\UserServiceInterface; | ||
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController; | ||
use Pimcore\Bundle\StudioBackendBundle\Exception\DomainConfigurationException; | ||
use Pimcore\Bundle\StudioBackendBundle\Exception\RateLimitException; | ||
use Pimcore\Bundle\StudioBackendBundle\Exception\SendMailException; | ||
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\DefaultResponses; | ||
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attributes\Response\SuccessResponse; | ||
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags; | ||
use Pimcore\Bundle\StudioBackendBundle\Util\Constants\HttpResponseCodes; | ||
use Symfony\Component\HttpFoundation\Response; | ||
use Symfony\Component\HttpKernel\Attribute\MapRequestPayload; | ||
use Symfony\Component\Routing\Attribute\Route; | ||
use Symfony\Component\Serializer\SerializerInterface; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
final class ResetPasswordController extends AbstractApiController | ||
{ | ||
public function __construct( | ||
SerializerInterface $serializer, | ||
private readonly UserServiceInterface $userService | ||
) { | ||
parent::__construct($serializer); | ||
} | ||
|
||
/** | ||
* @throws RateLimitException|DomainConfigurationException|SendMailException | ||
*/ | ||
#[Route('/reset-password', name: 'pimcore_studio_api_reset_password', methods: ['POST'])] | ||
#[Post( | ||
path: self::API_PATH . '/reset-password', | ||
operationId: 'rest-password', | ||
summary: 'Sending username to reset password', | ||
tags: [Tags::Authorization->name] | ||
)] | ||
#[ResetPasswordRequestBody] | ||
#[SuccessResponse] | ||
#[DefaultResponses([ | ||
HttpResponseCodes::TOO_MANY_REQUESTS | ||
])] | ||
public function resetPassword(#[MapRequestPayload] ResetPassword $resetPassword): Response | ||
{ | ||
$this->userService->resetPassword($resetPassword); | ||
return new Response(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
/** | ||
* Pimcore | ||
* | ||
* This source file is available under two different licenses: | ||
* - GNU General Public License version 3 (GPLv3) | ||
* - Pimcore Commercial License (PCL) | ||
* Full copyright and license information is available in | ||
* LICENSE.md which is distributed with this source code. | ||
* | ||
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) | ||
* @license http://www.pimcore.org/license GPLv3 and PCL | ||
*/ | ||
|
||
namespace Pimcore\Bundle\StudioBackendBundle\Authorization\Event; | ||
|
||
use Pimcore\Model\User; | ||
use Symfony\Contracts\EventDispatcher\Event; | ||
|
||
final class LostPasswordEvent extends Event | ||
{ | ||
public const EVENT_NAME = 'pimcore.admin.login.lostpassword'; | ||
|
||
protected bool $sendMail = true; | ||
|
||
public function __construct(private User $user, private string $loginUrl) | ||
{ | ||
} | ||
|
||
public function getUser(): User | ||
{ | ||
return $this->user; | ||
} | ||
|
||
public function getLoginUrl(): string | ||
{ | ||
return $this->loginUrl; | ||
} | ||
|
||
/** | ||
* Determines if lost password mail should be sent | ||
*/ | ||
public function getSendMail(): bool | ||
{ | ||
return $this->sendMail; | ||
} | ||
|
||
/** | ||
* Sets flag whether to send lost password mail or not | ||
*/ | ||
public function setSendMail(bool $sendMail): LostPasswordEvent | ||
{ | ||
$this->sendMail = $sendMail; | ||
|
||
return $this; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
/** | ||
* Pimcore | ||
* | ||
* This source file is available under two different licenses: | ||
* - GNU General Public License version 3 (GPLv3) | ||
* - Pimcore Commercial License (PCL) | ||
* Full copyright and license information is available in | ||
* LICENSE.md which is distributed with this source code. | ||
* | ||
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) | ||
* @license http://www.pimcore.org/license GPLv3 and PCL | ||
*/ | ||
|
||
namespace Pimcore\Bundle\StudioBackendBundle\Authorization\RateLimiter; | ||
|
||
use Pimcore\Bundle\StudioBackendBundle\Exception\RateLimitException; | ||
use Pimcore\Bundle\StudioBackendBundle\Util\Traits\RequestTrait; | ||
use Symfony\Component\HttpFoundation\RequestStack; | ||
use Symfony\Component\RateLimiter\Exception\RateLimitExceededException; | ||
use Symfony\Component\RateLimiter\RateLimiterFactory; | ||
|
||
final readonly class RateLimiter implements RateLimiterInterface | ||
{ | ||
use RequestTrait; | ||
public function __construct( | ||
private RateLimiterFactory $resetPasswordLimiter, | ||
private RequestStack $requestStack, | ||
) | ||
{ | ||
} | ||
|
||
/** | ||
* @throws RateLimitException | ||
*/ | ||
public function check(): void | ||
{ | ||
$request = $this->getCurrentRequest($this->requestStack); | ||
|
||
$limiter = $this->resetPasswordLimiter->create($request->getClientIp()); | ||
|
||
try { | ||
$limiter->consume()->ensureAccepted(); | ||
} catch (RateLimitExceededException) { | ||
throw new RateLimitException(); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
/** | ||
* Pimcore | ||
* | ||
* This source file is available under two different licenses: | ||
* - GNU General Public License version 3 (GPLv3) | ||
* - Pimcore Commercial License (PCL) | ||
* Full copyright and license information is available in | ||
* LICENSE.md which is distributed with this source code. | ||
* | ||
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) | ||
* @license http://www.pimcore.org/license GPLv3 and PCL | ||
*/ | ||
|
||
namespace Pimcore\Bundle\StudioBackendBundle\Authorization\RateLimiter; | ||
|
||
use Pimcore\Bundle\StudioBackendBundle\Exception\RateLimitException; | ||
|
||
interface RateLimiterInterface | ||
{ | ||
/** | ||
* @throws RateLimitException | ||
*/ | ||
public function check(): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
/** | ||
* Pimcore | ||
* | ||
* This source file is available under two different licenses: | ||
* - GNU General Public License version 3 (GPLv3) | ||
* - Pimcore Commercial License (PCL) | ||
* Full copyright and license information is available in | ||
* LICENSE.md which is distributed with this source code. | ||
* | ||
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) | ||
* @license http://www.pimcore.org/license GPLv3 and PCL | ||
*/ | ||
|
||
namespace Pimcore\Bundle\StudioBackendBundle\Authorization\Schema; | ||
|
||
use OpenApi\Attributes\Property; | ||
use OpenApi\Attributes\Schema; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
#[Schema( | ||
title: 'ResetPassword', | ||
description: 'Username', | ||
type: 'object' | ||
)] | ||
final readonly class ResetPassword | ||
{ | ||
public function __construct( | ||
#[Property(description: 'Username', type: 'string', example: 'shaquille.oatmeal')] | ||
private string $username | ||
) { | ||
} | ||
|
||
public function getUsername(): string | ||
{ | ||
return $this->username; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
/** | ||
* Pimcore | ||
* | ||
* This source file is available under two different licenses: | ||
* - GNU General Public License version 3 (GPLv3) | ||
* - Pimcore Commercial License (PCL) | ||
* Full copyright and license information is available in | ||
* LICENSE.md which is distributed with this source code. | ||
* | ||
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) | ||
* @license http://www.pimcore.org/license GPLv3 and PCL | ||
*/ | ||
|
||
namespace Pimcore\Bundle\StudioBackendBundle\Authorization\Service; | ||
|
||
use Exception; | ||
use Pimcore\Bundle\StaticResolverBundle\Lib\ToolResolverInterface; | ||
use Pimcore\Bundle\StudioBackendBundle\Authorization\Event\LostPasswordEvent; | ||
use Pimcore\Bundle\StudioBackendBundle\Exception\DomainConfigurationException; | ||
use Pimcore\Bundle\StudioBackendBundle\Exception\SendMailException; | ||
use Pimcore\Bundle\StudioBackendBundle\Setting\Provider\SettingsProviderInterface; | ||
use Pimcore\Model\User; | ||
use Pimcore\Model\UserInterface; | ||
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | ||
use Symfony\Component\Routing\RouterInterface; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
final readonly class MailService implements MailServiceInterface | ||
{ | ||
private const RESET_MAIL_TEXT = "Login to pimcore and change your password using the following link. | ||
This temporary login link will expire in 24 hours: \r\n\r\n %s"; | ||
private string $domain; | ||
|
||
public function __construct( | ||
private SettingsProviderInterface $systemSettingsProvider, | ||
private RouterInterface $router, | ||
private EventDispatcherInterface $eventDispatcher, | ||
private ToolResolverInterface $toolResolver, | ||
) | ||
{ | ||
$settings = $this->systemSettingsProvider->getSettings(); | ||
$this->domain = $settings['main_domain']; | ||
} | ||
|
||
/** | ||
* @throws DomainConfigurationException|SendMailException | ||
*/ | ||
public function sendResetPasswordMail(UserInterface $user, string $token): void | ||
{ | ||
if (!$this->domain) { | ||
throw new DomainConfigurationException(); | ||
} | ||
|
||
$context = $this->router->getContext(); | ||
$context->setHost($this->domain); | ||
|
||
$loginUrl = $this->router->generate( | ||
'pimcore_admin_login', | ||
[ | ||
'token' => $token, | ||
'reset' => 'true', | ||
], | ||
UrlGeneratorInterface::ABSOLUTE_URL | ||
); | ||
|
||
/** @var User $user */ | ||
$event = new LostPasswordEvent($user, $loginUrl); | ||
$this->eventDispatcher->dispatch($event, LostPasswordEvent::EVENT_NAME); | ||
|
||
// only send mail if it wasn't prevented in event | ||
if ($event->getSendMail()) { | ||
try { | ||
$mail = $this->toolResolver->getMail([$user->getEmail()], 'Pimcore lost password service'); | ||
$mail->setIgnoreDebugMode(true); | ||
$mail->text(sprintf(self::RESET_MAIL_TEXT, $loginUrl)); | ||
$mail->send(); | ||
} catch (Exception $exception) { | ||
throw new SendMailException($exception->getMessage()); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.