Skip to content

Commit 343aca5

Browse files
mbrodalafabpot
authored andcommitted
[Security] [LoginLink] Set custom lifetime for login link
1 parent 8308df8 commit 343aca5

File tree

4 files changed

+39
-3
lines changed

4 files changed

+39
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ CHANGELOG
77
* Add maximum username length enforcement of 4096 characters in `UserBadge`
88
* Add `#[IsGranted()]`
99
* Deprecate empty username or password when using when using `JsonLoginAuthenticator`
10+
* Set custom lifetime for login link
11+
* Add `$lifetime` parameter to `LoginLinkHandlerInterface::createLoginLink()`
1012

1113
6.0
1214
---

LoginLink/LoginLinkHandler.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ public function __construct(UrlGeneratorInterface $urlGenerator, UserProviderInt
4444
], $options);
4545
}
4646

47-
public function createLoginLink(UserInterface $user, Request $request = null): LoginLinkDetails
47+
public function createLoginLink(UserInterface $user, Request $request = null, int $lifetime = null): LoginLinkDetails
4848
{
49-
$expires = time() + $this->options['lifetime'];
49+
$expires = time() + ($lifetime ?: $this->options['lifetime']);
5050
$expiresAt = new \DateTimeImmutable('@'.$expires);
5151

5252
$parameters = [

LoginLink/LoginLinkHandlerInterface.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ interface LoginLinkHandlerInterface
2323
{
2424
/**
2525
* Generate a link that can be used to authenticate as the given user.
26+
*
27+
* @param int $lifetime
2628
*/
27-
public function createLoginLink(UserInterface $user, Request $request = null): LoginLinkDetails;
29+
public function createLoginLink(UserInterface $user, Request $request = null /*, int $lifetime = null */): LoginLinkDetails;
2830

2931
/**
3032
* Validates if this request contains a login link and returns the associated User.

Tests/LoginLink/LoginLinkHandlerTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,38 @@ public function provideCreateLoginLinkData()
112112
];
113113
}
114114

115+
public function testCreateLoginLinkWithLifetime()
116+
{
117+
$extraProperties = ['emailProperty' => '[email protected]', 'passwordProperty' => 'pwhash'];
118+
119+
$this->router->expects($this->once())
120+
->method('generate')
121+
->with(
122+
'app_check_login_link_route',
123+
$this->callback(function ($parameters) use ($extraProperties) {
124+
return 'weaverryan' == $parameters['user']
125+
&& isset($parameters['expires'])
126+
// allow a small expiration offset to avoid time-sensitivity
127+
&& abs(time() + 1000 - $parameters['expires']) <= 1
128+
&& isset($parameters['hash'])
129+
// make sure hash is what we expect
130+
&& $parameters['hash'] === $this->createSignatureHash('weaverryan', $parameters['expires'], array_values($extraProperties));
131+
}),
132+
UrlGeneratorInterface::ABSOLUTE_URL
133+
)
134+
->willReturn('https://example.com/login/verify?user=weaverryan&hash=abchash&expires=1654244256');
135+
136+
$user = new TestLoginLinkHandlerUser('weaverryan', '[email protected]', 'pwhash');
137+
$lifetime = 1000;
138+
139+
$loginLink = $this->createLinker([], array_keys($extraProperties))->createLoginLink(
140+
user: $user,
141+
lifetime: $lifetime,
142+
);
143+
144+
$this->assertSame('https://example.com/login/verify?user=weaverryan&hash=abchash&expires=1654244256', $loginLink->getUrl());
145+
}
146+
115147
public function testConsumeLoginLink()
116148
{
117149
$expires = time() + 500;

0 commit comments

Comments
 (0)