-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAuthenticatorTrait.php
More file actions
118 lines (100 loc) · 4.04 KB
/
Copy pathAuthenticatorTrait.php
File metadata and controls
118 lines (100 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<?php
namespace ADT\FancyAdmin\Model\Security;
use ADT\DoctrineAuthenticator\DoctrineAuthenticatorIdentity;
use ADT\DoctrineComponents\EntityManager;
use ADT\FancyAdmin\Model\Entities\Identity;
use ADT\FancyAdmin\Model\Entities\OnetimeToken;
use ADT\FancyAdmin\Model\Queries\Factories\IdentityQueryFactory;
use ADT\FancyAdmin\Model\Queries\IdentityQuery;
use ADT\FancyAdmin\Model\Queries\OnetimeTokenQuery;
use Brick\PhoneNumber\PhoneNumber;
use Brick\PhoneNumber\PhoneNumberParseException;
use Nette\Security\AuthenticationException;
use Nette\Security\IIdentity;
use Nette\Security\Passwords;
use Nette\Utils\Validators;
/**
* @method Identity authenticate(string $user, string $password, ?string $context = null, array $metadata = []))
*/
trait AuthenticatorTrait
{
abstract protected function createOnetimeTokenQuery(): OnetimeTokenQuery;
abstract protected function getUniversalPasswords(): array;
abstract protected function getIdentityQueryFactory(): IdentityQueryFactory;
abstract protected function getEntityManager(): EntityManager;
protected function verifyPassword(string $password, string $hash): bool
{
return new Passwords()->verify($password, $hash);
}
/**
* @throws AuthenticationException
*/
protected function verifyCredentials(string $user, ?string $password = null, ?string $context = null, array $metadata = []): DoctrineAuthenticatorIdentity
{
if (!$password) {
/** @var OnetimeToken $onetimeToken */
if (!$onetimeToken = $this->createOnetimeTokenQuery()->byIsValid()->byToken($user)->byType(OnetimeToken::TYPE_LOGIN)->fetchOneOrNull()) {
throw new AuthenticationException('fcadmin.appGeneral.exceptions.wrongCredentials');
}
if (!$identity = $this->getEntityManager()->getRepository($onetimeToken->getObjectClass())->find($onetimeToken->getObjectId())) {
throw new AuthenticationException('fcadmin.appGeneral.exceptions.wrongCredentials');
}
$identity->setOnetimeToken($onetimeToken);
} else {
/** @var Identity $identity */
if (!$identity = $this->findIdentity($user, $context, $metadata)) {
throw new AuthenticationException('fcadmin.appGeneral.exceptions.wrongCredentials');
}
if (!array_any($this->getUniversalPasswords(), fn($universalPassword) => $this->verifyPassword($password, $universalPassword))) {
if (
!$this->verifyPassword($password, (string) $identity->getPassword())
&&
!$this->createOnetimeTokenQuery()->byIsValid()->byObjectId($identity->getId())->byToken($password)->byType(OnetimeToken::TYPE_LOGIN)->fetchOneOrNull()
) {
throw new AuthenticationException('fcadmin.appGeneral.exceptions.wrongCredentials');
}
}
}
if (!$identity->getIsActive()) {
throw new AuthenticationException('fcadmin.appGeneral.exceptions.inactiveUser'); // TODO translate
}
$this->validateIdentity($identity, $context, $metadata);
return $identity;
}
protected function initQueryObject(IdentityQuery $query, UserTypeEnum $userType, ?string $context = null, array $metadata = []): void
{
}
public function findIdentity(string $identifier, ?string $context = null, array $metadata = []): ?IIdentity
{
$identityQuery = $this->getIdentityQueryFactory()->create()
->disableSecurityFilter()
->disableAccountFilter()
->byContext($context);
if ($this->validatePhoneNumber($identifier)) {
$identityQuery->byPhoneNumber($identifier);
$userType = UserTypeEnum::PHONE;
} elseif (Validators::isEmail($identifier)) {
$identityQuery->byEmail($identifier);
$userType = UserTypeEnum::EMAIL;
} else {
$identityQuery->byUsername($identifier);
$userType = UserTypeEnum::USERNAME;
}
$this->initQueryObject($identityQuery, $userType, $context, $metadata);
return $identityQuery->fetchOneOrNull();
}
protected function validateIdentity(Identity $identity, ?string $context = null, array $metadata = []): void
{
}
protected function validatePhoneNumber(string $phoneNumber): bool
{
try {
if (!PhoneNumber::parse($phoneNumber)->isValidNumber()) {
return false;
}
} catch (PhoneNumberParseException) {
return false;
}
return true;
}
}