Passed
Push — master ( 13c68b...d6cf3f )
by Angel Fernando Quiroz
09:49 queued 19s
created

AzureAuthenticatorHelper   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 231
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 133
c 1
b 0
f 0
dl 0
loc 231
rs 10
wmc 17

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A registerUser() 0 69 3
A formatUserData() 0 34 5
A getUpdateActionByRole() 0 22 1
A getAzureUidField() 0 5 1
A getUserIdByVerificationOrder() 0 22 3
A getAzureIdField() 0 5 1
A getOrganizationEmailField() 0 5 1
A getExistingUserVerificationOrder() 0 3 1
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Helpers;
8
9
use Chamilo\CoreBundle\Entity\ExtraField;
10
use Chamilo\CoreBundle\Entity\ExtraFieldValues;
11
use Chamilo\CoreBundle\Entity\User;
12
use Chamilo\CoreBundle\Repository\ExtraFieldRepository;
13
use Chamilo\CoreBundle\Repository\ExtraFieldValuesRepository;
14
use Chamilo\CoreBundle\Repository\Node\UserRepository;
15
use Doctrine\ORM\EntityManagerInterface;
16
use Doctrine\ORM\NonUniqueResultException;
17
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
18
19
readonly class AzureAuthenticatorHelper
20
{
21
    public const EXTRA_FIELD_ORGANISATION_EMAIL = 'organisationemail';
22
    public const EXTRA_FIELD_AZURE_ID = 'azure_id';
23
    public const EXTRA_FIELD_AZURE_UID = 'azure_uid';
24
25
    public const QUERY_USER_FIELDS = [
26
        'givenName',
27
        'surname',
28
        'mail',
29
        'userPrincipalName',
30
        'businessPhones',
31
        'mobilePhone',
32
        'accountEnabled',
33
        'mailNickname',
34
        'id',
35
    ];
36
    public const QUERY_GROUP_FIELDS = [
37
        'id',
38
        'displayName',
39
        'description',
40
    ];
41
42
    public const QUERY_GROUP_MEMBERS_FIELDS = [
43
        'mail',
44
        'mailNickname',
45
        'id',
46
    ];
47
48
    public function __construct(
49
        private ExtraFieldValuesRepository $extraFieldValuesRepo,
50
        private ExtraFieldRepository $extraFieldRepo,
51
        private UserRepository $userRepository,
52
        private EntityManagerInterface $entityManager,
53
        private AccessUrlHelper $accessUrlHelper,
54
    ) {}
55
56
    /**
57
     * @throws NonUniqueResultException
58
     */
59
    public function registerUser(array $azureUserInfo): User
60
    {
61
        if (empty($azureUserInfo)) {
62
            throw new UnauthorizedHttpException('User info not found.');
63
        }
64
65
        [
66
            $firstNme,
67
            $lastName,
68
            $username,
69
            $email,
70
            $phone,
71
            $authSource,
72
            $active,
73
            $extra,
74
        ] = $this->formatUserData($azureUserInfo);
75
76
        $userId = $this->getUserIdByVerificationOrder($azureUserInfo);
77
78
        if (empty($userId)) {
79
            $user = (new User())
80
                ->setCreatorId($this->userRepository->getRootUser()->getId())
81
            ;
82
        } else {
83
            $user = $this->userRepository->find($userId);
84
        }
85
86
        $user
87
            ->setFirstname($firstNme)
88
            ->setLastname($lastName)
89
            ->setEmail($email)
90
            ->setUsername($username)
91
            ->setPlainPassword('azure')
92
            ->setStatus(STUDENT)
93
            ->addAuthSourceByAuthentication(
94
                $authSource,
95
                $this->accessUrlHelper->getCurrent()
96
            )
97
            ->setPhone($phone)
98
            ->setActive($active)
99
            ->setRoleFromStatus(STUDENT)
100
        ;
101
102
        $this->userRepository->updateUser($user);
103
104
        $url = $this->accessUrlHelper->getCurrent();
105
        $url->addUser($user);
106
107
        $this->entityManager->flush();
108
109
        $this->extraFieldValuesRepo->updateItemData(
110
            $this->getOrganizationEmailField(),
111
            $user,
112
            $extra['extra_'.self::EXTRA_FIELD_ORGANISATION_EMAIL]
113
        );
114
115
        $this->extraFieldValuesRepo->updateItemData(
116
            $this->getAzureIdField(),
117
            $user,
118
            $extra['extra_'.self::EXTRA_FIELD_AZURE_ID]
119
        );
120
121
        $this->extraFieldValuesRepo->updateItemData(
122
            $this->getAzureUidField(),
123
            $user,
124
            $extra['extra_'.self::EXTRA_FIELD_AZURE_UID]
125
        );
126
127
        return $user;
128
    }
129
130
    private function getOrganizationEmailField(): ExtraField
131
    {
132
        return $this->extraFieldRepo->findByVariable(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->extraField...ELD_ORGANISATION_EMAIL) could return the type null which is incompatible with the type-hinted return Chamilo\CoreBundle\Entity\ExtraField. Consider adding an additional type-check to rule them out.
Loading history...
133
            ExtraField::USER_FIELD_TYPE,
134
            self::EXTRA_FIELD_ORGANISATION_EMAIL
135
        );
136
    }
137
138
    private function getAzureIdField(): ExtraField
139
    {
140
        return $this->extraFieldRepo->findByVariable(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->extraField...::EXTRA_FIELD_AZURE_ID) could return the type null which is incompatible with the type-hinted return Chamilo\CoreBundle\Entity\ExtraField. Consider adding an additional type-check to rule them out.
Loading history...
141
            ExtraField::USER_FIELD_TYPE,
142
            self::EXTRA_FIELD_AZURE_ID
143
        );
144
    }
145
146
    private function getAzureUidField(): ExtraField
147
    {
148
        return $this->extraFieldRepo->findByVariable(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->extraField...:EXTRA_FIELD_AZURE_UID) could return the type null which is incompatible with the type-hinted return Chamilo\CoreBundle\Entity\ExtraField. Consider adding an additional type-check to rule them out.
Loading history...
149
            ExtraField::USER_FIELD_TYPE,
150
            self::EXTRA_FIELD_AZURE_UID
151
        );
152
    }
153
154
    /**
155
     * @throws NonUniqueResultException
156
     */
157
    public function getUserIdByVerificationOrder(array $azureUserData): ?int
158
    {
159
        $selectedOrder = $this->getExistingUserVerificationOrder();
160
161
        $organisationEmailField = $this->getOrganizationEmailField();
162
        $azureIdField = $this->getAzureIdField();
163
        $azureUidField = $this->getAzureUidField();
164
165
        /** @var array<int, ExtraFieldValues> $positionsAndFields */
166
        $positionsAndFields = [
167
            1 => $this->extraFieldValuesRepo->findByVariableAndValue($organisationEmailField, $azureUserData['mail']),
168
            2 => $this->extraFieldValuesRepo->findByVariableAndValue($azureIdField, $azureUserData['mailNickname']),
169
            3 => $this->extraFieldValuesRepo->findByVariableAndValue($azureUidField, $azureUserData['id']),
170
        ];
171
172
        foreach ($selectedOrder as $position) {
173
            if (!empty($positionsAndFields[$position])) {
174
                return $positionsAndFields[$position]->getItemId();
175
            }
176
        }
177
178
        return null;
179
    }
180
181
    public function getExistingUserVerificationOrder(): array
182
    {
183
        return [1, 2, 3];
184
    }
185
186
    private function formatUserData(array $azureUserData): array
187
    {
188
        $phone = null;
189
190
        if (isset($azureUserData['telephoneNumber'])) {
191
            $phone = $azureUserData['telephoneNumber'];
192
        } elseif (isset($azureUserData['businessPhones'][0])) {
193
            $phone = $azureUserData['businessPhones'][0];
194
        } elseif (isset($azureUserData['mobilePhone'])) {
195
            $phone = $azureUserData['mobilePhone'];
196
        }
197
198
        // If the option is set to create users, create it
199
        $firstNme = $azureUserData['givenName'];
200
        $lastName = $azureUserData['surname'];
201
        $email = $azureUserData['mail'];
202
        $username = $azureUserData['userPrincipalName'];
203
        $authSource = 'azure';
204
        $active = ($azureUserData['accountEnabled'] ? 1 : 0);
205
        $extra = [
206
            'extra_'.self::EXTRA_FIELD_ORGANISATION_EMAIL => $azureUserData['mail'],
207
            'extra_'.self::EXTRA_FIELD_AZURE_ID => $azureUserData['mailNickname'],
208
            'extra_'.self::EXTRA_FIELD_AZURE_UID => $azureUserData['id'],
209
        ];
210
211
        return [
212
            $firstNme,
213
            $lastName,
214
            $username,
215
            $email,
216
            $phone,
217
            $authSource,
218
            $active,
219
            $extra,
220
        ];
221
    }
222
223
    /**
224
     * The keys are the user roles, as defined for the group_ip parameter in the authentication.yaml file for Azure.
225
     *
226
     * @return array<string, callable>
227
     */
228
    public function getUpdateActionByRole(): array
229
    {
230
        return [
231
            'admin' => function (User $user): void {
232
                $user
233
                    ->setStatus(COURSEMANAGER)
234
                    ->addUserAsAdmin()
235
                    ->setRoleFromStatus(COURSEMANAGER)
236
                ;
237
            },
238
            'session_admin' => function (User $user): void {
239
                $user
240
                    ->setStatus(SESSIONADMIN)
241
                    ->removeUserAsAdmin()
242
                    ->setRoleFromStatus(SESSIONADMIN)
243
                ;
244
            },
245
            'teacher' => function (User $user): void {
246
                $user
247
                    ->setStatus(COURSEMANAGER)
248
                    ->removeUserAsAdmin()
249
                    ->setRoleFromStatus(COURSEMANAGER)
250
                ;
251
            },
252
        ];
253
    }
254
}
255