fix: never persist a half-built user on first login

This commit is contained in:
Björn Fromme
2026-08-19 12:30:42 +02:00
parent 0c667d6b69
commit 2601e46ec4
4 changed files with 218 additions and 26 deletions
+32 -4
View File
@@ -56,7 +56,7 @@ class BpnAuthenticatorTest extends TestCase
$user = $this->loadUser($authenticator);
self::assertNull($persisted, 'an existing account must not be persisted again');
self::assertSame($existing, $persisted, 'a login must not create a second account');
self::assertSame(
['ROLE_USER', Role::TEAMER, Role::pending(Role::GROUPS_ADMIN)],
$user->getRoles(),
@@ -159,6 +159,27 @@ class BpnAuthenticatorTest extends TestCase
self::assertSame(['ROLE_USER', Role::CUSTOMER], $this->loadUser($authenticator)->getRoles());
}
public function testANewAccountIsOnlyRegisteredOnceItCarriesItsPassword(): void
{
$persisted = null;
$persistedPassword = null;
// A degraded payload is what makes syncFromCrm() log, and that log write reaches the
// database. An account registered before the profile is complete would be written out
// half-built, and the user table rejects it: password is NOT NULL.
$authenticator = $this->authenticator(
$this->crmAttributes([], [], selectionGroups: []),
null,
$persisted,
$persistedPassword,
);
$this->loadUser($authenticator);
self::assertInstanceOf(User::class, $persisted);
self::assertSame('encrypted', $persistedPassword);
}
/**
* @param string[] $roles
* @param string[] $hotelCodes
@@ -175,8 +196,12 @@ class BpnAuthenticatorTest extends TestCase
return $attributes;
}
private function authenticator(CrmAttributes $crmAttributes, ?User $existing, ?User &$persisted): BpnAuthenticator
{
private function authenticator(
CrmAttributes $crmAttributes,
?User $existing,
?User &$persisted,
?string &$persistedPassword = null,
): BpnAuthenticator {
$personalData = new PersonalData();
$personalData->personId = 42;
$personalData->addressId = 4711;
@@ -192,8 +217,11 @@ class BpnAuthenticatorTest extends TestCase
$entityManager->method('getRepository')->willReturn($repository);
$entityManager
->method('persist')
->willReturnCallback(static function (object $entity) use (&$persisted): void {
->willReturnCallback(static function (object $entity) use (&$persisted, &$persistedPassword): void {
$persisted = $entity;
// Snapshot rather than a reference: what matters is what the account looked like
// at the moment it was registered, not what it grew into afterwards.
$persistedPassword = $entity instanceof User ? $entity->getPassword() : null;
})
;