Passed
Pull Request — master (#5753)
by Angel Fernando Quiroz
07:49
created

GenericAuthenticator::userLoader()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 67
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 39
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 67
rs 8.0515

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Security\Authenticator\OAuth2;
8
9
use Chamilo\CoreBundle\Entity\User;
10
use Chamilo\CoreBundle\Repository\ExtraFieldRepository;
11
use Chamilo\CoreBundle\Repository\ExtraFieldValuesRepository;
12
use Chamilo\CoreBundle\Repository\Node\UserRepository;
13
use Chamilo\CoreBundle\ServiceHelper\AccessUrlHelper;
14
use Chamilo\CoreBundle\ServiceHelper\AuthenticationConfigHelper;
15
use ExtraField;
16
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
17
use League\OAuth2\Client\Provider\GenericResourceOwner;
18
use League\OAuth2\Client\Token\AccessToken;
19
use League\OAuth2\Client\Tool\ArrayAccessorTrait;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\Routing\RouterInterface;
22
use Symfony\Component\Security\Core\Exception\AuthenticationException;
23
use UnexpectedValueException;
24
25
class GenericAuthenticator extends AbstractAuthenticator
26
{
27
    use ArrayAccessorTrait;
28
29
    public const EXTRA_FIELD_OAUTH2_ID = 'oauth2_id';
30
31
    protected string $providerName = 'generic';
32
33
    public function __construct(
34
        ClientRegistry $clientRegistry,
35
        RouterInterface $router,
36
        UserRepository $userRepository,
37
        AuthenticationConfigHelper $authenticationConfigHelper,
38
        AccessUrlHelper $urlHelper,
39
        protected readonly ExtraFieldRepository $extraFieldRepository,
40
        protected readonly ExtraFieldValuesRepository $extraFieldValuesRepository,
41
    ) {
42
        parent::__construct(
43
            $clientRegistry,
44
            $router,
45
            $userRepository,
46
            $authenticationConfigHelper,
47
            $urlHelper,
48
        );
49
    }
50
51
    public function supports(Request $request): ?bool
52
    {
53
        return 'chamilo.oauth2_generic_check' === $request->attributes->get('_route');
54
    }
55
56
    protected function userLoader(AccessToken $accessToken): User
57
    {
58
        $providerParams = $this->authenticationConfigHelper->getParams('generic');
59
60
        /** @var GenericResourceOwner $resourceOwner */
61
        $resourceOwner = $this->client->fetchUserFromToken($accessToken);
62
        $resourceOwnerData = $resourceOwner->toArray();
63
        $resourceOwnerId = $resourceOwner->getId();
64
65
        if (empty($resourceOwnerId)) {
66
            throw new UnexpectedValueException('Value for the resource owner identifier not found at the configured key');
67
        }
68
69
        $fieldType = (int) ExtraField::getExtraFieldTypeFromString('user');
70
        $extraField = $this->extraFieldRepository->findByVariable($fieldType, self::EXTRA_FIELD_OAUTH2_ID);
71
72
        $existingUserExtraFieldValue = $this->extraFieldValuesRepository->findByVariableAndValue(
73
            $extraField,
74
            $resourceOwnerId
75
        );
76
77
        if (null === $existingUserExtraFieldValue) {
78
            $username = $this->getValueByKey(
79
                $resourceOwnerData,
80
                $providerParams['resource_owner_username_field'],
81
                "oauth2user_$resourceOwnerId"
82
            );
83
84
            /** @var User $user */
85
            $user = $this->userRepository->findOneBy(['username' => $username]);
86
87
            if (!$user || 'platform' !== $user->getAuthSource()) {
0 ignored issues
show
introduced by
$user is of type Chamilo\CoreBundle\Entity\User, thus it always evaluated to true.
Loading history...
88
                if (!$providerParams['allow_create_new_users']) {
89
                    throw new AuthenticationException('This user doesn\'t have an account yet and auto-provisioning is not enabled. Please contact this portal administration team to request access.');
90
                }
91
92
                // set default values, real values are set in self::updateUserInfo method
93
                $user = (new User())
94
                    ->setFirstname('OAuth2 User default firstname')
95
                    ->setLastname('OAuth2 User default firstname')
96
                    ->setEmail('oauth2user_'.$resourceOwnerId.'@'.(gethostname() ?: 'localhost'))
97
                    ->setUsername($username)
98
                    ->setPlainPassword($username)
99
                    ->setStatus(STUDENT)
100
                    ->setCreatorId($this->userRepository->getRootUser()->getId())
101
                ;
102
            }
103
104
            $this->saveUserInfo($user, $resourceOwnerData, $providerParams);
105
106
            $this->extraFieldValuesRepository->updateItemData(
107
                $extraField,
108
                $user,
109
                $resourceOwnerId
110
            );
111
        } else {
112
            /** @var User $user */
113
            $user = $this->userRepository->find(
114
                $existingUserExtraFieldValue->getItemId()
115
            );
116
117
            if ($providerParams['allow_update_user_info']) {
118
                $this->saveUserInfo($user, $resourceOwnerData, $providerParams);
119
            }
120
        }
121
122
        return $user;
123
    }
124
125
    /**
126
     * Set user information from the resource owner's data or the user itself.
127
     */
128
    public function saveUserInfo(User $user, array $resourceOwnerData, array $providerParams): void
129
    {
130
        $status = $this->getUserStatus($resourceOwnerData, $user->getStatus(), $providerParams);
131
132
        $user
133
            ->setFirstname(
134
                $this->getValueByKey(
135
                    $resourceOwnerData,
136
                    $providerParams['resource_owner_firstname_field'],
137
                    $user->getFirstname()
138
                )
139
            )
140
            ->setLastname(
141
                $this->getValueByKey(
142
                    $resourceOwnerData,
143
                    $providerParams['resource_owner_lastname_field'],
144
                    $user->getLastname()
145
                )
146
            )
147
            ->setUsername(
148
                $this->getValueByKey(
149
                    $resourceOwnerData,
150
                    $providerParams['resource_owner_username_field'],
151
                    $user->getUsername()
152
                )
153
            )
154
            ->setEmail(
155
                $this->getValueByKey(
156
                    $resourceOwnerData,
157
                    $providerParams['resource_owner_email_field'],
158
                    $user->getEmail()
159
                )
160
            )
161
            ->setAuthSource('oauth2')
162
            ->setStatus($status)
163
            ->setRoleFromStatus($status)
164
        ;
165
166
        $this->userRepository->updateUser($user);
167
168
        $url = $this->urlHelper->getCurrent();
169
        $url->addUser($user);
170
    }
171
172
    private function getUserStatus(array $resourceOwnerData, int $defaultStatus, array $providerParams): int
173
    {
174
        $status = $this->getValueByKey(
175
            $resourceOwnerData,
176
            $providerParams['resource_owner_status_field'],
177
            $defaultStatus
178
        );
179
180
        $responseStatus = [];
181
182
        if ($teacherStatus = $providerParams['resource_owner_teacher_status_field']) {
183
            $responseStatus[COURSEMANAGER] = $teacherStatus;
184
        }
185
186
        if ($sessAdminStatus = $providerParams['resource_owner_sessadmin_status_field']) {
187
            $responseStatus[SESSIONADMIN] = $sessAdminStatus;
188
        }
189
190
        if ($drhStatus = $providerParams['resource_owner_hr_status_field']) {
191
            $responseStatus[DRH] = $drhStatus;
192
        }
193
194
        if ($studentStatus = $providerParams['resource_owner_status_status_field']) {
195
            $responseStatus[STUDENT] = $studentStatus;
196
        }
197
198
        if ($anonStatus = $providerParams['resource_owner_anon_status_field']) {
199
            $responseStatus[ANONYMOUS] = $anonStatus;
200
        }
201
202
        $map = array_flip($responseStatus);
203
204
        return $map[$status] ?? $status;
205
    }
206
}
207