Skip to content

Commit

Permalink
Merge pull request #12 from roadiz/feature/passwordless-public-user
Browse files Browse the repository at this point in the history
  • Loading branch information
roadiz-ci committed Sep 18, 2024
1 parent 44384f8 commit c0bf179
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 64 deletions.
3 changes: 0 additions & 3 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,6 @@ services:
Solarium\Core\Client\Client:
factory: ['RZ\Roadiz\CoreBundle\SearchEngine\ClientRegistry', 'getClient']

RZ\Roadiz\CoreBundle\Security\Authentication\JwtAuthenticationSuccessHandler:
decorates: 'lexik_jwt_authentication.handler.authentication_success'

RZ\Roadiz\CoreBundle\Security\Authorization\Chroot\NodeChrootResolver:
alias: RZ\Roadiz\CoreBundle\Security\Authorization\Chroot\NodeChrootChainResolver

Expand Down
41 changes: 41 additions & 0 deletions src/EventSubscriber/JwtAuthenticationSuccessEventSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\EventSubscriber;

use Doctrine\Persistence\ManagerRegistry;
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
use RZ\Roadiz\CoreBundle\Entity\User;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

final readonly class JwtAuthenticationSuccessEventSubscriber implements EventSubscriberInterface
{
public function __construct(
private ManagerRegistry $managerRegistry,
) {
}

/**
* @inheritDoc
*/
public static function getSubscribedEvents(): array
{
return [
'lexik_jwt_authentication.on_authentication_success' => 'onAuthenticationSuccess',
AuthenticationSuccessEvent::class => 'onAuthenticationSuccess',
];
}

public function onAuthenticationSuccess(AuthenticationSuccessEvent $event): void
{
$user = $event->getUser();

if (!($user instanceof User)) {
return;
}

$user->setLastLogin(new \DateTime());
$this->managerRegistry->getManager()->flush();
}
}
34 changes: 0 additions & 34 deletions src/Security/Authentication/JwtAuthenticationSuccessHandler.php

This file was deleted.

68 changes: 68 additions & 0 deletions src/Security/LoginLink/EmailLoginLinkSender.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Security\LoginLink;

use RZ\Roadiz\CoreBundle\Bag\Settings;
use RZ\Roadiz\CoreBundle\Entity\User;
use RZ\Roadiz\CoreBundle\Mailer\EmailManagerFactory;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\LoginLink\LoginLinkDetails;
use Symfony\Contracts\Translation\TranslatorInterface;

final readonly class EmailLoginLinkSender implements LoginLinkSenderInterface
{
public function __construct(
private Settings $settingsBag,
private EmailManagerFactory $emailManagerFactory,
private TranslatorInterface $translator,
private string $htmlTemplate = '@RoadizCore/email/users/login_link_email.html.twig',
private string $txtTemplate = '@RoadizCore/email/users/login_link_email.txt.twig'
) {
}

public function sendLoginLink(UserInterface $user, LoginLinkDetails $loginLinkDetails,): void
{
if ($user instanceof User && !$user->isEnabled()) {
throw new \InvalidArgumentException('User must be enabled to send a login link.');
}

if (!\method_exists($user, 'getEmail')) {
throw new \InvalidArgumentException('User implementation must have getEmail method.');
}

if (null === $user->getEmail()) {
throw new \InvalidArgumentException('User must have an email to send a login link.');
}

$emailManager = $this->emailManagerFactory->create();
$emailContact = $this->settingsBag->get('email_sender', null);
if (!\is_string($emailContact)) {
throw new \InvalidArgumentException('Email sender must be a string.');
}
$siteName = $this->settingsBag->get('site_name', null);
if (!\is_string($siteName)) {
throw new \InvalidArgumentException('Site name must be a string.');
}

$emailManager->setAssignation([
'loginLink' => $loginLinkDetails->getUrl(),
'expiresAt' => $loginLinkDetails->getExpiresAt(),
'user' => $user,
'site' => $siteName,
'mailContact' => $emailContact,
]);
$emailManager->setEmailTemplate($this->htmlTemplate);
$emailManager->setEmailPlainTextTemplate($this->txtTemplate);
$emailManager->setSubject($this->translator->trans(
'login_link.request'
));

$emailManager->setReceiver($user->getEmail());
$emailManager->setSender([$emailContact => $siteName]);

// Send the message
$emailManager->send();
}
}
16 changes: 16 additions & 0 deletions src/Security/LoginLink/LoginLinkSenderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Security\LoginLink;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\LoginLink\LoginLinkDetails;

interface LoginLinkSenderInterface
{
public function sendLoginLink(
UserInterface $user,
LoginLinkDetails $loginLinkDetails,
): void;
}
34 changes: 7 additions & 27 deletions src/Security/User/UserViewer.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use RZ\Roadiz\CoreBundle\Bag\Settings;
use RZ\Roadiz\CoreBundle\Entity\User;
use RZ\Roadiz\CoreBundle\Mailer\EmailManagerFactory;
use RZ\Roadiz\CoreBundle\Security\LoginLink\LoginLinkSenderInterface;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
Expand All @@ -22,7 +23,8 @@ public function __construct(
private readonly UrlGeneratorInterface $urlGenerator,
private readonly TranslatorInterface $translator,
private readonly EmailManagerFactory $emailManagerFactory,
private readonly LoggerInterface $logger
private readonly LoggerInterface $logger,
private readonly LoginLinkSenderInterface $loginLinkSender
) {
}

Expand Down Expand Up @@ -95,38 +97,16 @@ public function sendPasswordResetLink(
}
}

/**
* @deprecated Use LoginLinkSenderInterface::sendLoginLink instead
*/
public function sendLoginLink(
UserInterface $user,
LoginLinkDetails $loginLinkDetails,
string $htmlTemplate = '@RoadizCore/email/users/login_link_email.html.twig',
string $txtTemplate = '@RoadizCore/email/users/login_link_email.txt.twig'
): void {
if (!(($user instanceof User) && $user->isEnabled())) {
throw new \InvalidArgumentException('User must be enabled to send a login link.');
}

$emailManager = $this->emailManagerFactory->create();
$emailContact = $this->getContactEmail();
$siteName = $this->getSiteName();

$emailManager->setAssignation([
'loginLink' => $loginLinkDetails->getUrl(),
'expiresAt' => $loginLinkDetails->getExpiresAt(),
'user' => $user,
'site' => $siteName,
'mailContact' => $emailContact,
]);
$emailManager->setEmailTemplate($htmlTemplate);
$emailManager->setEmailPlainTextTemplate($txtTemplate);
$emailManager->setSubject($this->translator->trans(
'login_link.request'
));

$emailManager->setReceiver($user->getEmail());
$emailManager->setSender([$emailContact => $siteName]);

// Send the message
$emailManager->send();
$this->loginLinkSender->sendLoginLink($user, $loginLinkDetails);
}

/**
Expand Down

0 comments on commit c0bf179

Please sign in to comment.