diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index 80d1a020..0a526c8d 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -82,6 +82,14 @@ security:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
+ login_link:
+ check_route: login_link_check
+ signature_properties: [ 'id', 'email' ]
+ # lifetime in seconds
+ lifetime: 300
+ # only allow the link to be used 3 times
+ max_uses: 3
+ success_handler: RZ\Roadiz\CoreBundle\Security\Authentication\BackofficeAuthenticationSuccessHandler
login_throttling:
max_attempts: 3
logout:
diff --git a/lib/RoadizCoreBundle/config/packages/security.yaml b/lib/RoadizCoreBundle/config/packages/security.yaml
index 8324dc43..b314b29a 100644
--- a/lib/RoadizCoreBundle/config/packages/security.yaml
+++ b/lib/RoadizCoreBundle/config/packages/security.yaml
@@ -75,6 +75,16 @@ security:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
+ # Enable login-link feature
+ # https://symfony.com/doc/current/security/login_link.html
+ login_link:
+ check_route: login_link_check
+ signature_properties: [ 'id', 'email' ]
+ # lifetime in seconds
+ lifetime: 300
+ # only allow the link to be used 3 times
+ max_uses: 3
+ success_handler: RZ\Roadiz\CoreBundle\Security\Authentication\BackofficeAuthenticationSuccessHandler
login_throttling:
max_attempts: 3
logout:
diff --git a/lib/RoadizCoreBundle/src/Security/Authentication/BackofficeAuthenticationSuccessHandler.php b/lib/RoadizCoreBundle/src/Security/Authentication/BackofficeAuthenticationSuccessHandler.php
new file mode 100644
index 00000000..01844589
--- /dev/null
+++ b/lib/RoadizCoreBundle/src/Security/Authentication/BackofficeAuthenticationSuccessHandler.php
@@ -0,0 +1,38 @@
+getUser();
+
+ if ($user instanceof User) {
+ $user->setLastLogin(new \DateTime('now'));
+ $manager = $this->managerRegistry->getManagerForClass(User::class);
+ $manager?->flush();
+ }
+
+ return new RedirectResponse($this->urlGenerator->generate('adminHomePage'));
+ }
+}
diff --git a/lib/RoadizCoreBundle/src/Security/Authentication/RoadizAuthenticator.php b/lib/RoadizCoreBundle/src/Security/Authentication/RoadizAuthenticator.php
index 4295a651..5d58b3cc 100644
--- a/lib/RoadizCoreBundle/src/Security/Authentication/RoadizAuthenticator.php
+++ b/lib/RoadizCoreBundle/src/Security/Authentication/RoadizAuthenticator.php
@@ -62,9 +62,7 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token,
if ($user instanceof User) {
$user->setLastLogin(new \DateTime('now'));
$manager = $this->managerRegistry->getManagerForClass(User::class);
- if (null !== $manager) {
- $manager->flush();
- }
+ $manager?->flush();
}
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
diff --git a/lib/RoadizCoreBundle/src/Security/User/UserViewer.php b/lib/RoadizCoreBundle/src/Security/User/UserViewer.php
index 673c7f28..ee9cdbd0 100644
--- a/lib/RoadizCoreBundle/src/Security/User/UserViewer.php
+++ b/lib/RoadizCoreBundle/src/Security/User/UserViewer.php
@@ -11,6 +11,8 @@
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Http\LoginLink\LoginLinkDetails;
use Symfony\Contracts\Translation\TranslatorInterface;
final class UserViewer
@@ -93,6 +95,36 @@ public function sendPasswordResetLink(
}
}
+ 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 {
+ $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();
+ }
+
/**
* @return string
*/
diff --git a/lib/RoadizCoreBundle/translations/core/messages.en.xlf b/lib/RoadizCoreBundle/translations/core/messages.en.xlf
index 760ae856..5fc5f68a 100644
--- a/lib/RoadizCoreBundle/translations/core/messages.en.xlf
+++ b/lib/RoadizCoreBundle/translations/core/messages.en.xlf
@@ -167,14 +167,52 @@
attributes.defaultRealm.placeholder
-
+
-- No default realm --
Default text when no realm is attached to an attribute
attributeValue.realm.placeholder
-
+
-- No realm --
Default text when no realm is attached to an attribute-value
+
+
+
+ login_link
+ Login link
+
+
+ login_link_sent
+ A login link was sent
+
+
+ login_link_sent_if_email_exists.check_inbox
+ A login link was sent to your email address if your account is valid. Check your inbox.
+
+
+ request_login_link
+ Request a login link
+
+
+ login_link.request
+ Your login link
+
+
+ you.asked.for.a.login_link.on.site
+ You requested a login link for website: %site%
+
+
+ click_on_following_link_to_login
+ Click on the following link to login automatically.
+
+
+ login_link_will_expire_at.expiresAt
+ This link will expire on %expiresAt%
+
+
+ classic.login_password
+ Password login
+