feat: identify accounts by a uuid in the oauth2 sub claim
This commit is contained in:
@@ -27,13 +27,14 @@ class UserinfoControllerTest extends TestCase
|
||||
{
|
||||
private const LOGIN_EMAIL = '[email protected]';
|
||||
private const CONTACT_EMAIL = '[email protected]';
|
||||
private const UUID = '018f3c2a-7b4d-4e91-a3c5-6d2f8b1e4a07';
|
||||
|
||||
public function testSubAndEmailAreExportedWithoutAnyOptionalScope(): void
|
||||
{
|
||||
$claims = $this->claims();
|
||||
|
||||
self::assertSame(['sub', 'email'], array_keys($claims));
|
||||
self::assertSame('42', $claims['sub']);
|
||||
self::assertSame(self::UUID, $claims['sub']);
|
||||
self::assertSame(self::LOGIN_EMAIL, $claims['email']);
|
||||
}
|
||||
|
||||
@@ -43,11 +44,27 @@ class UserinfoControllerTest extends TestCase
|
||||
|
||||
// The ids identify the human, the subject identifies the account. A second account of the
|
||||
// same person reports these same two ids and must still be told apart.
|
||||
self::assertSame('42', $claims['sub']);
|
||||
self::assertSame(self::UUID, $claims['sub']);
|
||||
self::assertSame(7, $claims['person_id']);
|
||||
self::assertSame(9, $claims['address_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumers store `sub` and match their own accounts on it, so it must not disclose how many
|
||||
* accounts exist or let one account's identifier be guessed from the next. The primary key
|
||||
* did both.
|
||||
*/
|
||||
public function testSubIsTheAccountUuidRatherThanItsPrimaryKey(): void
|
||||
{
|
||||
$claims = $this->claims();
|
||||
|
||||
self::assertNotSame('42', $claims['sub']);
|
||||
self::assertMatchesRegularExpression(
|
||||
'/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/',
|
||||
$claims['sub']
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailIsTheAuthenticatedAddressAndNotTheFirstContactOnTheBusProRecord(): void
|
||||
{
|
||||
$claims = $this->claims(['ROLE_OAUTH2_PROFILE']);
|
||||
@@ -160,10 +177,15 @@ class UserinfoControllerTest extends TestCase
|
||||
->setRoles($roles)
|
||||
;
|
||||
|
||||
// The id is generated by Doctrine and has no setter, but it is what `sub` exports.
|
||||
// The id is generated by Doctrine and has no setter. It is deliberately not what `sub`
|
||||
// exports -- see testSubIsTheAccountUuidRatherThanItsPrimaryKey.
|
||||
$property = new \ReflectionProperty(User::class, 'id');
|
||||
$property->setValue($user, 42);
|
||||
|
||||
// The constructor generates a fresh uuid; pin it so the claim can be asserted literally.
|
||||
$property = new \ReflectionProperty(User::class, 'uuid');
|
||||
$property->setValue($user, self::UUID);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Entity;
|
||||
|
||||
use App\Entity\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class UserTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* The uuid is what /api/userinfo exports as `sub`, and consumers key their own accounts on
|
||||
* it, so an account has to carry one from the moment it exists -- there is no later step
|
||||
* that could assign it.
|
||||
*/
|
||||
public function testAnAccountIsGivenAUuidOnCreation(): void
|
||||
{
|
||||
$user = new User('[email protected]');
|
||||
|
||||
self::assertMatchesRegularExpression(
|
||||
'/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/',
|
||||
$user->getUuid()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* v4, not the framework's default v7: a v7 would sort by creation time and carry that
|
||||
* timestamp in the claim, which is the disclosure the column exists to avoid.
|
||||
*/
|
||||
public function testUuidsAreRandomRatherThanOrdered(): void
|
||||
{
|
||||
$uuids = [];
|
||||
for ($i = 0; $i < 50; ++$i) {
|
||||
$uuids[] = (new User("someone{$i}@ep-reisen.de"))->getUuid();
|
||||
}
|
||||
|
||||
self::assertCount(50, array_unique($uuids));
|
||||
|
||||
$sorted = $uuids;
|
||||
sort($sorted);
|
||||
self::assertNotSame($sorted, $uuids, 'v4 uuids must not come out in creation order');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user