Skip to content

Commit 214d737

Browse files
committed
Move to dedicated UserEntity Factory
1 parent c59a036 commit 214d737

File tree

10 files changed

+196
-122
lines changed

10 files changed

+196
-122
lines changed

src/Entities/UserEntity.php

Lines changed: 15 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -16,85 +16,22 @@
1616

1717
namespace SimpleSAML\Module\oidc\Entities;
1818

19-
use DateTime;
19+
use DateTimeImmutable;
2020
use League\OAuth2\Server\Entities\UserEntityInterface;
2121
use SimpleSAML\Module\oidc\Entities\Interfaces\ClaimSetInterface;
2222
use SimpleSAML\Module\oidc\Entities\Interfaces\MementoInterface;
23-
use SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException;
24-
use SimpleSAML\Module\oidc\Utils\TimestampGenerator;
2523

2624
/**
2725
* @psalm-suppress PropertyNotSetInConstructor
2826
*/
2927
class UserEntity implements UserEntityInterface, MementoInterface, ClaimSetInterface
3028
{
31-
/**
32-
* @var string
33-
*/
34-
private string $identifier;
35-
36-
/**
37-
* @var array
38-
*/
39-
private array $claims;
40-
41-
/**
42-
* @var DateTime
43-
*/
44-
private DateTime $createdAt;
45-
46-
/**
47-
* @var DateTime
48-
*/
49-
private DateTime $updatedAt;
50-
51-
private function __construct()
52-
{
53-
}
54-
55-
/**
56-
* @throws \Exception
57-
*/
58-
public static function fromData(string $identifier, array $claims = []): self
59-
{
60-
$user = new self();
61-
62-
$user->identifier = $identifier;
63-
$user->createdAt = TimestampGenerator::utc();
64-
$user->updatedAt = $user->createdAt;
65-
$user->claims = $claims;
66-
67-
return $user;
68-
}
69-
70-
/**
71-
* @throws \Exception
72-
* @throws \SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException
73-
*/
74-
public static function fromState(array $state): self
75-
{
76-
$user = new self();
77-
78-
if (
79-
!is_string($state['id']) ||
80-
!is_string($state['claims']) ||
81-
!is_string($state['updated_at']) ||
82-
!is_string($state['created_at'])
83-
) {
84-
throw OidcServerException::serverError('Invalid user entity data');
85-
}
86-
87-
$user->identifier = $state['id'];
88-
$claims = json_decode($state['claims'], true, 512, JSON_INVALID_UTF8_SUBSTITUTE);
89-
90-
if (!is_array($claims)) {
91-
throw OidcServerException::serverError('Invalid user entity data');
92-
}
93-
$user->claims = $claims;
94-
$user->updatedAt = TimestampGenerator::utc($state['updated_at']);
95-
$user->createdAt = TimestampGenerator::utc($state['created_at']);
96-
97-
return $user;
29+
public function __construct(
30+
private readonly string $identifier,
31+
private readonly DateTimeImmutable $createdAt,
32+
private DateTimeImmutable $updatedAt,
33+
private array $claims = [],
34+
) {
9835
}
9936

10037
/**
@@ -120,23 +57,24 @@ public function getClaims(): array
12057
return $this->claims;
12158
}
12259

123-
/**
124-
* @throws \Exception
125-
*/
12660
public function setClaims(array $claims): self
12761
{
12862
$this->claims = $claims;
129-
$this->updatedAt = TimestampGenerator::utc();
130-
13163
return $this;
13264
}
13365

134-
public function getUpdatedAt(): DateTime
66+
public function getUpdatedAt(): DateTimeImmutable
13567
{
13668
return $this->updatedAt;
13769
}
13870

139-
public function getCreatedAt(): DateTime
71+
public function setUpdatedAt(DateTimeImmutable $updatedAt): self
72+
{
73+
$this->updatedAt = $updatedAt;
74+
return $this;
75+
}
76+
77+
public function getCreatedAt(): DateTimeImmutable
14078
{
14179
return $this->createdAt;
14280
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SimpleSAML\Module\oidc\Factories\Entities;
6+
7+
use SimpleSAML\Module\oidc\Entities\UserEntity;
8+
use SimpleSAML\Module\oidc\Helpers;
9+
use SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException;
10+
11+
class UserEntityFactory
12+
{
13+
public function __construct(
14+
protected readonly Helpers $helpers,
15+
) {
16+
}
17+
18+
public function fromData(string $identifier, array $claims = []): UserEntity
19+
{
20+
$createdAt = $updatedAt = $this->helpers->dateTime()->getUtc();
21+
22+
return new UserEntity(
23+
$identifier,
24+
$createdAt,
25+
$updatedAt,
26+
$claims,
27+
);
28+
}
29+
30+
/**
31+
* @throws \SimpleSAML\Module\oidc\Server\Exceptions\OidcServerException
32+
*/
33+
public function fromState(array $state): UserEntity
34+
{
35+
if (
36+
!is_string($state['id']) ||
37+
!is_string($state['claims']) ||
38+
!is_string($state['updated_at']) ||
39+
!is_string($state['created_at'])
40+
) {
41+
throw OidcServerException::serverError('Invalid user entity data');
42+
}
43+
44+
$identifier = $state['id'];
45+
$claims = json_decode($state['claims'], true, 512, JSON_INVALID_UTF8_SUBSTITUTE);
46+
47+
if (!is_array($claims)) {
48+
throw OidcServerException::serverError('Invalid user entity data');
49+
}
50+
$updatedAt = $this->helpers->dateTime()->getUtc($state['updated_at']);
51+
$createdAt = $this->helpers->dateTime()->getUtc($state['created_at']);
52+
53+
return new UserEntity(
54+
$identifier,
55+
$createdAt,
56+
$updatedAt,
57+
$claims,
58+
);
59+
}
60+
}

src/Repositories/UserRepository.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,29 @@
1616

1717
namespace SimpleSAML\Module\oidc\Repositories;
1818

19+
use DateTimeImmutable;
1920
use Exception;
2021
use League\OAuth2\Server\Entities\ClientEntityInterface as OAuth2ClientEntityInterface;
2122
use League\OAuth2\Server\Entities\UserEntityInterface;
2223
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
2324
use SimpleSAML\Module\oidc\Entities\UserEntity;
25+
use SimpleSAML\Module\oidc\Factories\Entities\UserEntityFactory;
26+
use SimpleSAML\Module\oidc\Helpers;
27+
use SimpleSAML\Module\oidc\ModuleConfig;
2428
use SimpleSAML\Module\oidc\Repositories\Interfaces\IdentityProviderInterface;
2529

2630
class UserRepository extends AbstractDatabaseRepository implements UserRepositoryInterface, IdentityProviderInterface
2731
{
2832
final public const TABLE_NAME = 'oidc_user';
2933

34+
public function __construct(
35+
ModuleConfig $moduleConfig,
36+
protected readonly Helpers $helpers,
37+
protected readonly UserEntityFactory $userEntityFactory,
38+
) {
39+
parent::__construct($moduleConfig);
40+
}
41+
3042
public function getTableName(): string
3143
{
3244
return $this->database->applyPrefix(self::TABLE_NAME);
@@ -57,7 +69,7 @@ public function getUserEntityByIdentifier(string $identifier): ?UserEntity
5769
return null;
5870
}
5971

60-
return UserEntity::fromState($row);
72+
return $this->userEntityFactory->fromState($row);
6173
}
6274

6375
/**
@@ -95,8 +107,10 @@ public function delete(UserEntity $user): void
95107
);
96108
}
97109

98-
public function update(UserEntity $user): void
110+
public function update(UserEntity $user, ?DateTimeImmutable $updatedAt = null): void
99111
{
112+
$user->setUpdatedAt($updatedAt ?? $this->helpers->dateTime()->getUtc());
113+
100114
$stmt = sprintf(
101115
"UPDATE %s SET claims = :claims, updated_at = :updated_at, created_at = :created_at WHERE id = :id",
102116
$this->getTableName(),

src/Services/AuthenticationService.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use SimpleSAML\Module\oidc\Entities\Interfaces\ClientEntityInterface;
3030
use SimpleSAML\Module\oidc\Entities\UserEntity;
3131
use SimpleSAML\Module\oidc\Factories\AuthSimpleFactory;
32+
use SimpleSAML\Module\oidc\Factories\Entities\UserEntityFactory;
3233
use SimpleSAML\Module\oidc\Factories\ProcessingChainFactory;
3334
use SimpleSAML\Module\oidc\Helpers;
3435
use SimpleSAML\Module\oidc\ModuleConfig;
@@ -66,6 +67,7 @@ public function __construct(
6667
private readonly StateService $stateService,
6768
private readonly Helpers $helpers,
6869
private readonly RequestParamsResolver $requestParamsResolver,
70+
private readonly UserEntityFactory $userEntityFactory,
6971
) {
7072
$this->userIdAttr = $this->moduleConfig->getUserIdentifierAttribute();
7173
}
@@ -140,13 +142,14 @@ public function getAuthenticateUser(
140142
}
141143

142144
$userId = (string)$claims[$this->userIdAttr][0];
145+
143146
$user = $this->userRepository->getUserEntityByIdentifier($userId);
144147

145148
if ($user) {
146149
$user->setClaims($claims);
147150
$this->userRepository->update($user);
148151
} else {
149-
$user = UserEntity::fromData($userId, $claims);
152+
$user = $this->userEntityFactory->fromData($userId, $claims);
150153
$this->userRepository->add($user);
151154
}
152155

src/Services/Container.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
use SimpleSAML\Module\oidc\Factories\Entities\ClaimSetEntityFactory;
4444
use SimpleSAML\Module\oidc\Factories\Entities\ClientEntityFactory;
4545
use SimpleSAML\Module\oidc\Factories\Entities\RefreshTokenEntityFactory;
46+
use SimpleSAML\Module\oidc\Factories\Entities\UserEntityFactory;
4647
use SimpleSAML\Module\oidc\Factories\FederationFactory;
4748
use SimpleSAML\Module\oidc\Factories\FormFactory;
4849
use SimpleSAML\Module\oidc\Factories\Grant\AuthCodeGrantFactory;
@@ -205,7 +206,14 @@ public function __construct()
205206
$clientRepository = new ClientRepository($moduleConfig, $clientEntityFactory);
206207
$this->services[ClientRepository::class] = $clientRepository;
207208

208-
$userRepository = new UserRepository($moduleConfig);
209+
$userEntityFactory = new UserEntityFactory($helpers);
210+
$this->services[UserEntityFactory::class] = $userEntityFactory;
211+
212+
$userRepository = new UserRepository(
213+
$moduleConfig,
214+
$helpers,
215+
$userEntityFactory,
216+
);
209217
$this->services[UserRepository::class] = $userRepository;
210218

211219
$authCodeEntityFactory = new AuthCodeEntityFactory($helpers);
@@ -277,6 +285,7 @@ public function __construct()
277285
$stateService,
278286
$helpers,
279287
$requestParamsResolver,
288+
$userEntityFactory,
280289
);
281290
$this->services[AuthenticationService::class] = $authenticationService;
282291

tests/integration/src/Repositories/Traits/RevokeTokenByAuthCodeIdTraitTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ public function getDatabase(): Database
171171
$this->mock->getDatabase()->write('DELETE from ' . $clientRepositoryMock->getTableName());
172172
$clientRepositoryMock->add($client);
173173

174-
175-
$user = UserEntity::fromData(self::USER_ID);
174+
$createUpdatedAt = new \DateTimeImmutable();
175+
$user = new UserEntity(self::USER_ID, $createUpdatedAt, $createUpdatedAt, []);
176176
$userRepositoryMock = new UserRepository($moduleConfig);
177177
$this->mock->getDatabase()->write('DELETE from ' . $userRepositoryMock->getTableName());
178178
$userRepositoryMock->add($user);

0 commit comments

Comments
 (0)