JWTGraphiQLAuthentication::requireUserData()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\GraphiQL;
12
13
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
14
use Symfony\Component\Form\FormBuilderInterface;
15
use Symfony\Component\Form\FormInterface;
16
use Symfony\Component\HttpFoundation\Session\Session;
17
use Symfony\Component\Routing\Router;
18
use function JmesPath\search;
19
20
/**
21
 * JWTGraphiQLAuthentication
22
 *
23
 * @deprecated since v1.1, removed 2.0 (use LexikJWTGraphiQLAuthenticator instead)
24
 */
25
class JWTGraphiQLAuthentication implements GraphiQLAuthenticationProviderInterface
26
{
27
    private const SESSION_PATH = 'graphiql_jwt_api_token';
28
29
    /**
30
     * @var Router
31
     */
32
    protected $router;
33
34
    /**
35
     * @var Session
36
     */
37
    protected $session;
38
39
    /**
40
     * @var array
41
     */
42
    protected $config = [];
43
44
    /**
45
     * @param Router  $router
46
     * @param Session $session
47
     * @param array   $config
48
     */
49
    public function __construct(Router $router, Session $session, array $config)
50
    {
51
        $this->config = $config;
52
        $this->router = $router;
53
        $this->session = $session;
54
    }
55
56
    /**
57
     * {@inheritDoc}
58
     */
59
    public function requireUserData(): bool
60
    {
61
        return true;
62
    }
63
64
    /**
65
     * {@inheritDoc}
66
     */
67
    public function buildUserForm(FormBuilderInterface $builder)
68
    {
69
        $builder
70
            ->add(
71
                $this->config['login']['username_parameter'] ?? 'username',
72
                null,
73
                [
74
                    'label' => $this->config['login']['username_label'] ?? 'Label',
75
                ]
76
            )
77
            ->add(
78
                $this->config['login']['password_parameter'] ?? 'password',
79
                PasswordType::class,
80
                [
81
                    'label' => $this->config['login']['password_label'] ?? 'Password',
82
                ]
83
            );
84
    }
85
86
    /**
87
     * @param null|FormInterface $form
88
     *
89
     * @throws \RuntimeException
90
     * @throws AuthenticationFailedException
91
     */
92
    public function login(?FormInterface $form = null)
93
    {
94
        if (!$form) {
95
            throw new \RuntimeException('This provider require a form');
96
        }
97
98
        $url = $this->config['login']['url'] ?? null;
99
        if ($this->router->getRouteCollection()->get($url)) {
100
            $url = $this->router->generate($url, [], Router::ABSOLUTE_URL);
101
        }
102
103
        $opts = [
104
            CURLOPT_CONNECTTIMEOUT => 10,
105
            CURLOPT_RETURNTRANSFER => true,
106
            CURLOPT_HEADER => true,
107
            CURLOPT_TIMEOUT => 60,
108
            CURLOPT_HTTPHEADER => [],
109
        ];
110
111
        $paramsIn = $this->config['login']['parameters_in'] ?? 'form';
112
        if ('header' === $paramsIn) {
113
            $opts[CURLOPT_HEADER] = true;
114
            $headers = [];
115
            foreach ($form->getData() as $key => $value) {
116
                $headers[] = sprintf('%s: %s', $key, $value);
117
            }
118
            $opts[CURLOPT_HTTPHEADER] = array_merge(["Accept: application/json"], $headers);
119
        } elseif ('query' === $paramsIn) {
120
            $url .= '?'.http_build_query($form->getData(), null, '&');
121
        } else {
122
            $opts[CURLOPT_POSTFIELDS] = http_build_query($form->getData(), null, '&');
123
            $opts[CURLOPT_POST] = true;
124
        }
125
126
        $opts[CURLOPT_URL] = $url;
127
128
        $ch = curl_init();
129
        curl_setopt_array($ch, $opts);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt_array() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
        curl_setopt_array(/** @scrutinizer ignore-type */ $ch, $opts);
Loading history...
130
        $result = curl_exec($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
        $result = curl_exec(/** @scrutinizer ignore-type */ $ch);
Loading history...
131
132
        // Split the HTTP response into header and body.
133
        try {
134
            list($headers, $body) = explode("\r\n\r\n", $result);
135
            $headers = explode("\r\n", $headers);
136
        } catch (\ErrorException $exception) {
137
            throw new AuthenticationFailedException('Authentication Failed');
138
        }
139
140
        // We catch HTTP/1.1 4xx or HTTP/1.1 5xx error response.
141
        if (strpos($headers[0], 'HTTP/1.1 4') !== false || strpos($headers[0], 'HTTP/1.1 5') !== false) {
142
            $result = [
143
                'code' => 0,
144
                'message' => '',
145
            ];
146
147
            if (preg_match('/^HTTP\/1.1 ([0-9]{3,3}) (.*)$/', $headers[0], $matches)) {
148
                $result['code'] = $matches[1];
149
                $result['message'] = $matches[2];
150
            }
151
152
            // In case retrun with WWW-Authenticate replace the description.
153
            foreach ($headers as $header) {
154
                if (preg_match("/^WWW-Authenticate:.*error='(.*)'/", $header, $matches)) {
155
                    $result['message'] = $matches[1];
156
                }
157
            }
158
159
            throw new AuthenticationFailedException($result['message'] ?: 'Authentication Failed', $result['code'] ?: 401);
160
        }
161
162
        $tokenPath = $this->config['login']['response_token_path'] ?? 'token';
163
        $token = $body;
164
165
        if ($tokenPath) {
166
            $token = search($tokenPath, @json_decode($body));
167
        }
168
169
        if (!$token) {
170
            throw new AuthenticationFailedException('Authentication Failed');
171
        }
172
173
        $this->session->set(self::SESSION_PATH, $token);
174
    }
175
176
    /**
177
     * {@inheritDoc}
178
     */
179
    public function logout()
180
    {
181
        $this->session->remove(self::SESSION_PATH);
182
    }
183
184
    /**
185
     * {@inheritDoc}
186
     */
187
    public function isAuthenticated(): bool
188
    {
189
        return $this->session->has(self::SESSION_PATH) && $this->session->get(self::SESSION_PATH);
190
    }
191
192
    /**
193
     * {@inheritDoc}
194
     */
195
    public function prepareRequest(GraphiQLRequest $request)
196
    {
197
        $token = null;
198
        if ($this->isAuthenticated()) {
199
            $token = $this->session->get(self::SESSION_PATH);
200
            if ('header' === $this->config['requests']['token_in']) {
201
                $token = str_replace('{token}', $token, $this->config['requests']['token_template']);
202
            }
203
        }
204
205
        $tokenName = $this->config['requests']['token_name'];
206
        if ('header' === $this->config['requests']['token_in']) {
207
            $request->addHeader($tokenName, $token);
208
        } else {
209
            $request->addParameter($tokenName, $token);
210
        }
211
    }
212
}
213