Completed
Push — 1.0 ( 046da8...d5bf3f )
by Paweł
07:50
created

AuthController::authenticateWithSuperdeskAction()   C

Complexity

Conditions 13
Paths 104

Size

Total Lines 75
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 75
rs 5.245
c 0
b 0
f 0
cc 13
eloc 51
nc 104
nop 1

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 GuzzleHttp;
18
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
19
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
20
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
21
use SWP\Bundle\CoreBundle\Form\Type\SuperdeskCredentialAuthenticationType;
22
use SWP\Bundle\CoreBundle\Form\Type\UserAuthenticationType;
23
use SWP\Bundle\CoreBundle\Model\UserInterface;
24
use SWP\Component\Common\Response\ResponseContext;
25
use SWP\Component\Common\Response\SingleResourceResponse;
26
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
27
use Symfony\Component\HttpFoundation\Request;
28
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
29
30
class AuthController extends Controller
31
{
32
    /**
33
     * Look for user matching provided credentials.
34
     *
35
     * @ApiDoc(
36
     *     resource=true,
37
     *     description="Look for user matching provided credentials",
38
     *     statusCodes={
39
     *         200="Returned on success.",
40
     *         401="No user found or not authorized."
41
     *     },
42
     *     input="SWP\Bundle\CoreBundle\Form\Type\UserAuthenticationType"
43
     * )
44
     * @Route("/api/{version}/auth/", options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_auth")
45
     * @Method("POST")
46
     */
47
    public function authenticateAction(Request $request)
48
    {
49
        $form = $this->createForm(UserAuthenticationType::class, []);
50
        $form->handleRequest($request);
51
        if ($form->isValid()) {
52
            $formData = $form->getData();
53
            try {
54
                $user = $this->get('swp.security.user_provider')->loadUserByUsername($formData['username']);
55
            } catch (UsernameNotFoundException $e) {
56
                $user = null;
57
            }
58
59
            if (null !== $user) {
60
                if ($this->get('security.password_encoder')->isPasswordValid($user, $formData['password'])) {
61
                    return $this->getApiToken($user, null);
62
                }
63
            }
64
        }
65
66
        return new SingleResourceResponse([
67
            'status' => 401,
68
            'message' => 'Unauthorized',
69
        ], new ResponseContext(401));
70
    }
71
72
    /**
73
     * Ask Superdesk server for user with those credentials and tries to authorize.
74
     *
75
     * @ApiDoc(
76
     *     resource=true,
77
     *     description="Authorize using Superdesk credentials",
78
     *     statusCodes={
79
     *         200="Returned on success.",
80
     *         401="No user found or not authorized."
81
     *     },
82
     *     input="SWP\Bundle\CoreBundle\Form\Type\SuperdeskCredentialAuthenticationType"
83
     * )
84
     * @Route("/api/{version}/auth/superdesk/", options={"expose"=true}, defaults={"version"="v1"}, name="swp_api_auth_superdesk")
85
     * @Method("POST")
86
     */
87
    public function authenticateWithSuperdeskAction(Request $request)
88
    {
89
        $form = $this->createForm(SuperdeskCredentialAuthenticationType::class, []);
90
        $form->handleRequest($request);
91
        if ($form->isValid()) {
92
            $formData = $form->getData();
93
            $authorizedSuperdeskHosts = $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['session_id']), [
100
                        'Authorization' => $formData['token'],
101
                    ]);
102
                    $apiResponse = $client->send($apiRequest);
103
                } catch (GuzzleHttp\Exception\ClientException $e) {
104
                    if ($e->getResponse()->getStatusCode() !== 200) {
105
                        continue;
106
                    }
107
                }
108
109
                if ($apiResponse->getStatusCode() !== 200) {
0 ignored issues
show
Bug introduced by
The variable $apiResponse does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
110
                    continue;
111
                }
112
113
                $content = json_decode($apiResponse->getBody()->getContents(), true);
114
                if (is_array($content) && array_key_exists('user', $content)) {
115
                    $superdeskUser = $content['user'];
116
117
                    break;
118
                }
119
            }
120
121
            if (null == $superdeskUser) {
122
                return new SingleResourceResponse([
123
                    'status' => 401,
124
                    'message' => 'Unauthorized (user not found in Superdesk)',
125
                ], new ResponseContext(401));
126
            }
127
128
            $userProvider = $this->get('swp.security.user_provider');
129
            $publisherUser = $userProvider->findOneByEmail($superdeskUser['email']);
130
            if (null === $publisherUser) {
131
                try {
132
                    $publisherUser = $userProvider->loadUserByUsername($superdeskUser['username']);
133
                } catch (UsernameNotFoundException $e) {
134
                    $publisherUser = null;
135
                }
136
            }
137
138
            if (null === $publisherUser) {
139
                $userManager = $this->get('fos_user.user_manager');
140
                /** @var UserInterface $publisherUser */
141
                $publisherUser = $userManager->createUser();
142
                $publisherUser->setUsername($superdeskUser['username']);
143
                $publisherUser->setEmail($superdeskUser['email']);
144
                $publisherUser->setRoles(['ROLE_INTERNAL_API', 'ROLE_USER']);
145
                $publisherUser->setFirstName($superdeskUser['first_name']);
146
                $publisherUser->setLastName($superdeskUser['last_name']);
147
                $publisherUser->setPlainPassword(password_hash(random_bytes(36), PASSWORD_BCRYPT));
148
                $publisherUser->setEnabled(true);
149
                $userManager->updateUser($publisherUser);
150
            }
151
152
            if (null !== $publisherUser) {
153
                return $this->getApiToken($publisherUser, str_replace('Basic ', '', $formData['token']));
154
            }
155
        }
156
157
        return new SingleResourceResponse([
158
            'status' => 401,
159
            'message' => 'Unauthorized',
160
        ], new ResponseContext(401));
161
    }
162
163
    private function getApiToken($user, $token)
164
    {
165
        $apiKey = null;
0 ignored issues
show
Unused Code introduced by
$apiKey is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
166
        $apiKeyRepository = $this->get('swp.repository.api_key');
167
        if (null !== $token) {
168
            $apiKey = $apiKeyRepository
169
                ->getValidToken($token)
170
                ->getQuery()
171
                ->getOneOrNullResult();
172
        } else {
173
            $apiKey = $apiKeyRepository->getValidTokenForUser($user)->getQuery()->getOneOrNullResult();
174
        }
175
176
        if (null === $apiKey) {
177
            $apiKey = $this->get('swp.factory.api_key')->create($user, $token);
178
            $apiKeyRepository->add($apiKey);
179
        }
180
181
        return new SingleResourceResponse([
182
            'token' => [
183
                'api_key' => $apiKey->getApiKey(),
184
                'valid_to' => $apiKey->getValidTo(),
185
            ],
186
            'user' => $user,
187
        ]);
188
    }
189
}
190