Completed
Push — master ( bbff6f...c51acf )
by Rafał
19:14 queued 09:31
created

AuthController::authenticateWithSuperdeskAction()   C

Complexity

Conditions 16
Paths 44

Size

Total Lines 74

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 16

Importance

Changes 0
Metric Value
dl 0
loc 74
rs 5.5666
c 0
b 0
f 0
ccs 11
cts 11
cp 1
cc 16
nc 44
nop 1
crap 16

How to fix   Long Method    Complexity   

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
/*
4
 * This file is part of the Superdesk Web Publisher Core Bundle.
5
 *
6
 * Copyright 2016 Sourcefabric z.ú. and contributors.
7
 *
8
 * For the full copyright and license information, please see the
9
 * AUTHORS and LICENSE files distributed with this source code.
10
 *
11
 * @copyright 2016 Sourcefabric z.ú
12
 * @license http://www.superdesk.org/license
13
 */
14
15
namespace SWP\Bundle\CoreBundle\Controller;
16
17
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
18
use GuzzleHttp;
19
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
20
use Symfony\Component\Routing\Annotation\Route;
21
use SWP\Bundle\CoreBundle\Form\Type\SuperdeskCredentialAuthenticationType;
22
use SWP\Bundle\CoreBundle\Form\Type\UserAuthenticationType;
23
use SWP\Bundle\CoreBundle\Model\ApiKeyInterface;
24
use SWP\Bundle\CoreBundle\Model\UserInterface;
25
use SWP\Component\Common\Response\ResponseContext;
26
use SWP\Component\Common\Response\SingleResourceResponse;
27
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
28
use Symfony\Component\HttpFoundation\Request;
29
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
30
31
class AuthController extends Controller
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...e\Controller\Controller has been deprecated with message: since Symfony 4.2, use {@see AbstractController} instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
32
{
33
    /**
34
     * Look for user matching provided credentials.
35
     *
36
     * @ApiDoc(
37
     *     resource=true,
38
     *     description="Look for user matching provided credentials",
39
     *     statusCodes={
40
     *         200="Returned on success.",
41
     *         401="No user found or not authorized."
42
     *     },
43
     *     input="SWP\Bundle\CoreBundle\Form\Type\UserAuthenticationType"
44
     * )
45
     * @Route("/api/{version}/auth/", options={"expose"=true}, defaults={"version"="v2"}, methods={"POST"}, name="swp_api_auth")
46 2
     */
47
    public function authenticateAction(Request $request)
48 2
    {
49 2
        $form = $this->get('form.factory')->createNamed('', UserAuthenticationType::class, []);
50 2
        $form->handleRequest($request);
51 2
        if ($form->isSubmitted() && $form->isValid()) {
52
            $formData = $form->getData();
53 2
54 1
            try {
55 1
                $user = $this->get('swp.security.user_provider')->loadUserByUsername($formData['username']);
56
            } catch (UsernameNotFoundException $e) {
57
                $user = null;
58 2
            }
59 1
60 1
            if (null !== $user) {
61
                if ($this->get('security.password_encoder')->isPasswordValid($user, $formData['password'])) {
62
                    return $this->returnApiTokenResponse($user, null);
63
                }
64
            }
65 1
        }
66 1
67
        return new SingleResourceResponse([
68 1
            'status' => 401,
69
            'message' => 'Unauthorized',
70
        ], new ResponseContext(401));
71
    }
72
73
    /**
74
     * Ask Superdesk server for user with those credentials and tries to authorize.
75
     *
76
     * @ApiDoc(
77
     *     resource=true,
78
     *     description="Authorize using Superdesk credentials",
79
     *     statusCodes={
80
     *         200="Returned on success.",
81
     *         401="No user found or not authorized."
82
     *     },
83
     *     input="SWP\Bundle\CoreBundle\Form\Type\SuperdeskCredentialAuthenticationType"
84
     * )
85
     * @Route("/api/{version}/auth/superdesk/", options={"expose"=true}, methods={"POST"}, defaults={"version"="v2"}, name="swp_api_auth_superdesk")
86
     */
87
    public function authenticateWithSuperdeskAction(Request $request)
88
    {
89
        $form = $this->get('form.factory')->createNamed('', SuperdeskCredentialAuthenticationType::class, []);
90
        $form->handleRequest($request);
91
        if ($form->isSubmitted() && $form->isValid()) {
92
            $formData = $form->getData();
93
            $authorizedSuperdeskHosts = (array) $this->container->getParameter('superdesk_servers');
94
            $superdeskUser = null;
95
            $client = new GuzzleHttp\Client();
96
97
            foreach ($authorizedSuperdeskHosts as $baseUrl) {
98
                try {
99
                    $apiRequest = new GuzzleHttp\Psr7\Request('GET', sprintf('%s/api/sessions/%s', $baseUrl, $formData['sessionId']), [
100
                        'Authorization' => $formData['token'],
101
                    ]);
102
                    $apiResponse = $client->send($apiRequest);
103
                    if (200 !== $apiResponse->getStatusCode()) {
104
                        continue;
105
                    }
106
107
                    $content = json_decode($apiResponse->getBody()->getContents(), true);
108
                    if (is_array($content) && array_key_exists('user', $content)) {
109
                        $superdeskUser = $content['user'];
110
111
                        break;
112
                    }
113
                } catch (GuzzleHttp\Exception\ClientException $e) {
114
                    if (200 !== $e->getResponse()->getStatusCode()) {
115
                        continue;
116
                    }
117
                }
118
            }
119
120
            if (null === $superdeskUser) {
121
                return new SingleResourceResponse([
122
                    'status' => 401,
123
                    'message' => 'Unauthorized (user not found in Superdesk)',
124
                ], new ResponseContext(401));
125
            }
126
127
            $userProvider = $this->get('swp.security.user_provider');
128
            $publisherUser = $userProvider->findOneByEmail($superdeskUser['email']);
129
            if (null === $publisherUser) {
130
                try {
131
                    $publisherUser = $userProvider->loadUserByUsername($superdeskUser['username']);
132
                } catch (UsernameNotFoundException $e) {
133
                    $publisherUser = null;
134
                }
135
            }
136
137 1
            if (null === $publisherUser) {
138
                $userManager = $this->get('fos_user.user_manager');
139 1
                /** @var UserInterface $publisherUser */
140 1
                $publisherUser = $userManager->createUser();
141 1
                $publisherUser->setUsername($superdeskUser['username']);
142
                $publisherUser->setEmail($superdeskUser['email']);
143
                $publisherUser->setRoles(['ROLE_INTERNAL_API']);
144
                $publisherUser->setFirstName(\array_key_exists('first_name', $superdeskUser) ? $superdeskUser['first_name'] : 'Anon.');
145
                $publisherUser->setLastName(\array_key_exists('last_name', $superdeskUser) ? $superdeskUser['last_name'] : '');
146
                $publisherUser->setPlainPassword(password_hash(random_bytes(36), PASSWORD_BCRYPT));
147
                $publisherUser->setEnabled(true);
148 1
                $userManager->updateUser($publisherUser);
149 1
            }
150 1
151
            if (null !== $publisherUser) {
152
                return $this->returnApiTokenResponse($publisherUser, str_replace('Basic ', '', $formData['token']));
153 1
            }
154
        }
155 1
156 1
        return new SingleResourceResponse([
157
            'status' => 401,
158 1
            'message' => 'Unauthorized',
159
        ], new ResponseContext(401));
160
    }
161
162
    /**
163
     * @param UserInterface $user
164
     * @param string        $token
165
     *
166
     * @return SingleResourceResponse
167
     */
168
    private function returnApiTokenResponse(UserInterface $user, $token)
169
    {
170
        /** @var ApiKeyInterface $apiKey */
171
        $apiKey = $this->generateOrGetApiKey($user, $token);
172
173
        return new SingleResourceResponse([
174
            'token' => [
175
                'api_key' => $apiKey->getApiKey(),
176
                'valid_to' => $apiKey->getValidTo(),
177
            ],
178
            'user' => $user,
179
        ]);
180
    }
181
182
    private function generateOrGetApiKey(UserInterface $user, $token)
183
    {
184
        $apiKey = null;
185
        $apiKeyRepository = $this->get('swp.repository.api_key');
186
        if (null !== $token) {
187
            $apiKey = $apiKeyRepository->getValidToken($token)->getQuery()->getOneOrNullResult();
188
        } else {
189
            $validKeys = $apiKeyRepository->getValidTokenForUser($user)->getQuery()->getResult();
190
            if (count($validKeys) > 0) {
191
                $apiKey = reset($validKeys);
192
            }
193
        }
194
195
        if (null === $apiKey) {
196
            $apiKey = $this->get('swp.factory.api_key')->create($user, $token);
197
198
            try {
199
                $apiKeyRepository->add($apiKey);
200
            } catch (UniqueConstraintViolationException $e) {
201
                return $this->generateOrGetApiKey($user, $token);
202
            }
203
        }
204
205
        return $apiKey;
206
    }
207
}
208