8000 Merge branch '5.4' into 6.0 · symfony/symfony@ccf4e7b · GitHub
[go: up one dir, main page]

Skip to content

Commit ccf4e7b

Browse files
Merge branch '5.4' into 6.0
* 5.4: [FrameworkBundle] fix leftover [Uid] fix performance and prevent collisions with the real clock_seq Fix RequestContext not updated bug #41715: [FrameworkBundle] Partial backport of PR#41530 [Security] Restore extension point in MessageDigestPasswordEncoder Fix some typos in Greek language [Security] Fix deprecation notice on TokenInterface::getUser() stringable return Remove TLS related options when not using TLS
2 parents d6ec101 + a0728f2 commit ccf4e7b

File tree

16 files changed

+233
-71
lines changed
< 10000 button data-component="IconButton" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-c50BI flex-shrink-0 prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R55dab:-loading-announcement" aria-labelledby=":R3t5dab:" id=":R55dab:">

16 files changed

+233
-71
lines changed

src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/ConnectionTest.php

Lines changed: 21 additions & 0 B41A deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,27 @@ public function testItCanPublishAndWaitForConfirmation()
764764
$connection->publish('body');
765765
}
766766

767+
public function testItCanBeConstructedWithTLSOptionsAndNonTLSDsn()
768+
{
769+
$this->assertEquals(
770+
new Connection([
771+
'host' => 'localhost',
772+
'port' => 5672,
773+
'vhost' => '/',
774+
], [
775+
'name' => self::DEFAULT_EXCHANGE_NAME,
776+
], [
777+
self::DEFAULT_EXCHANGE_NAME => [],
778+
]),
779+
Connection::fromDsn('amqp://', [
780+
'cacert' => 'foobar',
781+
'cert' => 'foobar',
782+
'key' => 'foobar',
783+
'verify' => false,
784+
])
785+
);
786+
}
787+
767788
private function createDelayOrRetryConnection(\AMQPExchange $delayExchange, string $deadLetterExchangeName, string $delayQueueName): Connection
768789
{
769790
$amqpConnection = $this->createMock(\AMQPConnection::class);

src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ public static function fromDsn(string $dsn, array $options = [], AmqpFactory $am
224224
return $queueOptions;
225225
}, $queuesOptions);
226226

227+
if (!$useAmqps) {
228+
unset($amqpOptions['cacert'], $amqpOptions['cert'], $amqpOptions['key'], $amqpOptions['verify']);
229+
}
230+
227231
if ($useAmqps && !self::hasCaCertConfigured($amqpOptions)) {
228232
throw new InvalidArgumentException('No CA certificate has been provided. Set "amqp.cacert" in your php.ini or pass the "cacert" parameter in the DSN to use SSL. Alternatively, you can use amqp:// to use without SSL.');
229233
}

src/Symfony/Component/Messenger/Middleware/RouterContextMiddleware.php

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use Symfony\Component\Messenger\Envelope;
1515
use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp;
1616
use Symfony\Component\Messenger\Stamp\RouterContextStamp;
17-
use Symfony\Component\Routing\RequestContext;
1817
use Symfony\Component\Routing\RequestContextAwareInterface;
1918

2019
/**
@@ -49,24 +48,41 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope
4948
return $stack->next()->handle($envelope, $stack);
5049
}
5150

52-
$currentContext = $this->router->getContext();
51+
$context = $this->router->getContext();
52+
$currentBaseUrl = $context->getBaseUrl();
53+
$currentMethod = $context->getMethod();
54+
$currentHost = $context->getHost();
55+
$currentScheme = $context->getScheme();
56+
$currentHttpPort = $context->getHttpPort();
57+
$currentHttpsPort = $context->getHttpsPort();
58+
$currentPathInfo = $context->getPathInfo();
59+
$currentQueryString = $context->getQueryString();
5360

5461
/* @var RouterContextStamp $contextStamp */
55-
$this->router->setContext(new RequestContext(
56-
$contextStamp->getBaseUrl(),
57-
$contextStamp->getMethod(),
58-
$contextStamp->getHost(),
59-
$contextStamp->getScheme(),
60-
$contextStamp->getHttpPort(),
61-
$contextStamp->getHttpsPort(),
62-
$contextStamp->getPathInfo(),
63-
$contextStamp->getQueryString()
64-
));
62+
$context
63+
->setBaseUrl($contextStamp->getBaseUrl())
64+
->setMethod($contextStamp->getMethod())
65+
->setHost($contextStamp->getHost())
66+
->setScheme($contextStamp->getScheme())
67+
->setHttpPort($contextStamp->getHttpPort())
68+
->setHttpsPort($contextStamp->getHttpsPort())
69+
->setPathInfo($contextStamp->getPathInfo())
70+
->setQueryString($contextStamp->getQueryString())
71+
;
6572

6673
try {
6774
return $stack->next()->handle($envelope, $stack);
6875
} finally {
69-
$this->router->setContext($currentContext);
76+
$context
77+
->setBaseUrl($currentBaseUrl)
78+
->setMethod($currentMethod)
79+
->setHost($currentHost)
80+
->setScheme($currentScheme)
81+
->setHttpPort($currentHttpPort)
82+
->setHttpsPort($currentHttpsPort)
83+
->setPathInfo($currentPathInfo)
84+
->setQueryString($currentQueryString)
85+
;
7086
}
7187
}
7288
}

src/Symfony/Component/Messenger/Tests/Middleware/RouterContextMiddlewareTest.php

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
namespace Symfony\Component\Messenger\Tests\Middleware;
44

55
use Symfony\Component\Messenger\Envelope;
6+
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
67
use Symfony\Component\Messenger\Middleware\RouterContextMiddleware;
8+
use Symfony\Component\Messenger\Middleware\StackInterface;
9+
use Symfony\Component\Messenger\Middleware\StackMiddleware;
710
use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp;
811
use Symfony\Component\Messenger\Stamp\RouterContextStamp;
912
use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase;
@@ -34,30 +37,32 @@ public function testMiddlewareStoreContext()
3437
public function testMiddlewareRestoreContext()
3538
{
3639
$router = $this->createMock(RequestContextAwareInterface::class);
37-
$originalContext = new RequestContext();
40+
$context = new RequestContext('', 'POST', 'github.com');
3841

3942
$router
4043
->expects($this->o 10000 nce())
4144
->method('getContext')
42-
->willReturn($originalContext);
43-
44-
$router
45-
->expects($this->exactly(2))
46-
->method('setContext')
47-
->withConsecutive(
48-
[$this->callback(function ($context) {
49-
$this->assertSame('symfony.com', $context->getHost());
50-
51-
return true;
52-
})],
53-
[$originalContext]
54-
);
45+
->willReturn($context);
5546

5647
$middleware = new RouterContextMiddleware($router);
5748
$envelope = new Envelope(new \stdClass(), [
5849
new ConsumedByWorkerStamp(),
5950
new RouterContextStamp('', 'GET', 'symfony.com', 'https', 80, 443, '/', ''),
6051
]);
61-
$middleware->handle($envelope, $this->getStackMock());
52+
53+
$nextMiddleware = $this->createMock(MiddlewareInterface::class);
54+
$nextMiddleware
55+
->expects($this->once())
56+
->method('handle')
57+
->willReturnCallback(function (Envelope $envelope, StackInterface $stack) use ($context): Envelope {
58+
$this->assertSame('symfony.com', $context->getHost());
59+
60+
return $envelope;
61+
})
62+
;
63+
64+
$middleware->handle($envelope, new StackMiddleware($nextMiddleware));
65+
66+
$this->assertSame('github.com', $context->getHost());
6267
}
6368
}

src/Symfony/Component/Security/Core/Encoder/MessageDigestPasswordEncoder.php

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Core\Encoder;
1313

1414
use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher;
15+
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
1516

1617
trigger_deprecation('symfony/security-core', '5.3', 'The "%s" class is deprecated, use "%s" instead.', MessageDigestPasswordEncoder::class, MessageDigestPasswordHasher::class);
1718

@@ -24,7 +25,10 @@
2425
*/
2526
class MessageDigestPasswordEncoder extends BasePasswordEncoder
2627
{
27-
use LegacyEncoderTrait;
28+
private $algorithm;
29+
private $encodeHashAsBase64;
30+
private $iterations = 1;
31+
private $encodedLength = -1;
2832

2933
/**
3034
* @param string $algorithm The digest algorithm to use
@@ -33,6 +37,51 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
3337
*/
3438
public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 5000)
3539
{
36-
$this->hasher = new MessageDigestPasswordHasher($algorithm, $encodeHashAsBase64, $iterations);
40+
$this->algorithm = $algorithm;
41+
$this->encodeHashAsBase64 = $encodeHashAsBase64;
42+
43+
try {
44+
$this->encodedLength = \strlen($this->encodePassword('', 'salt'));
45+
} catch (\LogicException $e) {
46+
// ignore algorithm not supported
47+
}
48+
49+
$this->iterations = $iterations;
50+
}
51+
52+
/**
53+
* {@inheritdoc}
54+
*/
55+
public function encodePassword(string $raw, ?string $salt)
56+
{
57+
if ($this->isPasswordTooLong($raw)) {
58+
throw new BadCredentialsException('Invalid password.');
59+
}
60+
61+
if (!\in_array($this->algorithm, hash_algos(), true)) {
62+
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
63+
}
64+
65+
$salted = $this->mergePasswordAndSalt($raw, $salt);
66+
$digest = hash($this->algorithm, $salted, true);
67+
68+
// "stretch" hash
69+
for ($i = 1; $i < $this->iterations; ++$i) {
70+
$digest = hash($this->algorithm, $digest.$salted, true);
71+
}
72+
73+
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
74+
}
75+
76+
/**
77+
* {@inheritdoc}
78+
*/
79+
public function isPasswordValid(string $encoded, string $raw, ?string $salt)
80+
{
81+
if (\strlen($encoded) !== $this->encodedLength || false !== strpos($encoded, '$')) {
82+
return false;
83+
}
84+
85+
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
3786
}
3887
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Security\Core\Tests\Encoder\Fixtures;
13+
14+
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
15+
16+
final class MyMessageDigestPasswordEncoder extends MessageDigestPasswordEncoder
17+
{
18+
public function __construct()
19+
{
20+
parent::__construct('sha512', true, 1);
21+
}
22+
23+
protected function mergePasswordAndSalt(string $password, ?string $salt): string
24+
{
25+
return json_encode(['password' => $password, 'salt' => $salt]);
26+
}
27+
28+
protected function demergePasswordAndSalt(string $mergedPasswordSalt): array
29+
{
30+
['password' => $password, 'salt' => $salt] = json_decode($mergedPasswordSalt, true);
31+
32+
return [$password, $salt];
33+
}
34+
}

src/Symfony/Component/Security/Core/Tests/Encoder/MessageDigestPasswordEncoderTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
1616
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
17+
use Symfony\Component\Security\Core\Tests\Encoder\Fixtures\MyMessageDigestPasswordEncoder;
1718

1819
/**
1920
* @group legacy
@@ -60,4 +61,13 @@ public function testCheckPasswordLength()
6061

6162
$this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), 'salt'));
6263
}
64+
65+
public function testCustomEncoder()
66+
{
67+
$encoder = new MyMessageDigestPasswordEncoder();
68+
$encodedPassword = $encoder->encodePassword('p4ssw0rd', 's417');
69+
70+
$this->assertSame(base64_encode(hash('sha512', '{"password":"p4ssw0rd","salt":"s417"}', true)), $encodedPassword);
71+
$this->assertTrue($encoder->isPasswordValid($encodedPassword, 'p4ssw0rd', 's417'));
72+
}
6373
}

src/Symfony/Component/Security/Http/Authentication/AuthenticatorManager.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ private function executeAuthenticator(AuthenticatorInterface $authenticator, Req
230230
private function handleAuthenticationSuccess(TokenInterface $authenticatedToken, PassportInterface $passport, Request $request, AuthenticatorInterface $authenticator): ?Response
231231
{
232232
// @deprecated since 5.3
233-
if (!method_exists($authenticatedToken->getUser(), 'getUserIdentifier')) {
233+
$user = $authenticatedToken->getUser();
234+
if ($user instanceof UserInterface && !method_exists($user, 'getUserIdentifier')) {
234235
trigger_deprecation('symfony/security-core', '5.3', 'Not implementing method "getUserIdentifier(): string" in user class "%s" is deprecated. This method will replace "getUsername()" in Symfony 6.0.', get_debug_type($authenticatedToken->getUser()));
235236
}
236237

src/Symfony/Component/Uid/Factory/UuidFactory.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,7 @@ public function timeBased(Uuid|string|null $node = null): TimeBasedUuidFactory
6363
{
6464
$node ?? $node = $this->timeBasedNode;
6565

66-
if (null === $node) {
67-
$class = $this->timeBasedClass;
68-
$node = $this->timeBasedNode = new $class();
69-
} elseif (!$node instanceof Uuid) {
66+
if (null !== $node && !$node instanceof Uuid) {
7067
$node = Uuid::fromString($node);
7168
}
7269

src/Symfony/Component/Uid/NilUuid.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ class NilUuid extends Uuid
2020

2121
public function __construct()
2222
{
23-
$this->uid = '00000000-0000-0000-0000-000000000000';
23+
$this->uid = parent::NIL;
2424
}
2525
}

src/Symfony/Component/Uid/Tests/Factory/UuidFactoryTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ public function testCreateTimed()
6565
$this->assertSame('c10ab929ae84', $uuid1->getNode());
6666

6767
// Test default node override
68-
$uuid2 = $uuidFactory->timeBased('7c1ede70-3586-48ed-a984-23c8018d9174')->create();
69-
$this->assertInstanceOf(UuidV6::class, $uuid2);
70-
$this->assertSame('23c8018d9174', $uuid2->getNode());
68+
$uuid2Factory = $uuidFactory->timeBased('7c1ede70-3586-48ed-a984-23c8018d9174');
69+
$this->assertSame('1eb5a7ae-17e1-62d0-a984-23c8018d9174', (string) $uuid2Factory->create(new \DateTime('@1611076938.057800')));
70+
$this->assertSame('23c8018d9174', substr($uuid2Factory->create(), 24));
71+
$this->assertNotSame('a984', substr($uuid2Factory->create(), 19, 4));
7172

7273
// Test version override
7374
$uuid3 = (new UuidFactory(6, 1))->timeBased()->create();

src/Symfony/Component/Uid/Ulid.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
*/
2121
class Ulid extends AbstractUid
2222
{
23+
private const NIL = '00000000000000000000000000';
24+
2325
private static $time = '';
2426
private static $rand = [];
2527

@@ -31,6 +33,12 @@ public function __construct(string $ulid = null)
3133
return;
3234
}
3335

36+
if (self::NIL === $ulid) {
37+
$this->uid = $ulid;
38+
39+
return;
40+
}
41+
3442
if (!self::isValid($ulid)) {
3543
throw new \InvalidArgumentException(sprintf('Invalid ULID: "%s".', $ulid));
3644
}
@@ -77,7 +85,10 @@ public static function fromString(string $ulid): parent
7785
base_convert(substr($ulid, 27, 5), 16, 32)
7886
);
7987

80-
return new static(strtr($ulid, 'abcdefghijklmnopqrstuv', 'ABCDEFGHJKMNPQRSTVWXYZ'));
88+
$u = new static(self::NIL);
89+
$u->uid = strtr($ulid, 'abcdefghijklmnopqrstuv', 'ABCDEFGHJKMNPQRSTVWXYZ');
90+
91+
return $u;
8192
}
8293

8394
public function toBinary(): string

0 commit comments

Comments
 (0)
0