LexikJWTGraphiQLAuthenticator::isAuthenticated()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

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 2
nc 2
nop 0
crap 6
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 Lexik\Bundle\JWTAuthenticationBundle\Security\Http\Authentication\AuthenticationSuccessHandler;
14
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
15
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
16
use Symfony\Component\Form\FormBuilderInterface;
17
use Symfony\Component\Form\FormInterface;
18
use Symfony\Component\HttpFoundation\Session\SessionInterface;
19
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
20
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
21
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
22
use Symfony\Component\Security\Core\User\UserProviderInterface;
23
24
class LexikJWTGraphiQLAuthenticator implements GraphiQLAuthenticationProviderInterface
25
{
26
    protected const SESSION_PATH = 'graphiql_jwt_api_token';
27
28
    /**
29
     * @var EncoderFactoryInterface
30
     */
31
    protected $encoder;
32
33
    /**
34
     * @var UserProviderInterface
35
     */
36
    protected $userProvider;
37
38
    /**
39
     * @var JWTTokenManagerInterface
40
     */
41
    protected $jwtTokenManager;
42
43
    /**
44
     * @var SessionInterface
45
     */
46
    protected $session;
47
48
    /**
49
     * @var AuthenticationSuccessHandler|null
50
     */
51
    protected $authenticationSuccessHandler;
52
53
    /**
54
     * @var array
55
     */
56
    protected $config = [];
57
58
    /**
59
     * LexikJWTGraphiQLAuthenticator constructor.
60
     *
61
     * @param UserPasswordEncoderInterface $encoder
62
     * @param UserProviderInterface        $userProvider
63
     * @param JWTTokenManagerInterface     $jwtTokenManager
64
     * @param SessionInterface             $session
65
     */
66
    public function __construct(UserPasswordEncoderInterface $encoder, UserProviderInterface $userProvider, JWTTokenManagerInterface $jwtTokenManager, SessionInterface $session)
67
    {
68
        $this->encoder = $encoder;
0 ignored issues
show
Documentation Bug introduced by
It seems like $encoder of type Symfony\Component\Securi...asswordEncoderInterface is incompatible with the declared type Symfony\Component\Securi...EncoderFactoryInterface of property $encoder.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
69
        $this->userProvider = $userProvider;
70
        $this->jwtTokenManager = $jwtTokenManager;
71
        $this->session = $session;
72
        $this->config = [
73
            'username_label' => 'Username',
74
            'password_label' => 'Password',
75
        ];
76
    }
77
78
    /**
79
     * @param AuthenticationSuccessHandler|null $authenticationSuccessHandler
80
     */
81
    public function setAuthenticationSuccessHandler(?AuthenticationSuccessHandler $authenticationSuccessHandler): void
82
    {
83
        $this->authenticationSuccessHandler = $authenticationSuccessHandler;
84
    }
85
86
    /**
87
     * @param array $config
88
     */
89
    public function setConfig(array $config): void
90
    {
91
        $this->config = array_merge($this->config, $config);
92
    }
93
94
    /**
95
     * @inheritDoc
96
     */
97
    public function requireUserData(): bool
98
    {
99
        return true;
100
    }
101
102
    /**
103
     * @inheritDoc
104
     */
105
    public function buildUserForm(FormBuilderInterface $builder)
106
    {
107
        $builder
108
            ->add(
109
                'username',
110
                null,
111
                [
112
                    'label' => $this->config['username_label'],
113
                ]
114
            )
115
            ->add(
116
                'password',
117
                PasswordType::class,
118
                [
119
                    'label' => $this->config['password_label'],
120
                ]
121
            );
122
    }
123
124
    /**
125
     * @inheritDoc
126
     */
127
    public function login(?FormInterface $form = null)
128
    {
129
        if (!$form) {
130
            throw new \RuntimeException('This provider require a form');
131
        }
132
133
        $username = $form->get('username')->getData();
134
        $password = $form->get('password')->getData();
135
136
        try {
137
            $user = $this->userProvider->loadUserByUsername($username);
138
        } catch (UsernameNotFoundException $exception) {
139
            $user = null;
140
        }
141
142
        if (!$user || !$this->encoder->isPasswordValid($user, $password)) {
0 ignored issues
show
Bug introduced by
The method isPasswordValid() does not exist on Symfony\Component\Securi...EncoderFactoryInterface. ( Ignorable by Annotation )

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

142
        if (!$user || !$this->encoder->/** @scrutinizer ignore-call */ isPasswordValid($user, $password)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
143
            throw new AuthenticationFailedException();
144
        }
145
146
        $token = $this->jwtTokenManager->create($user);
147
148
        if ($this->authenticationSuccessHandler) {
149
            $this->authenticationSuccessHandler->handleAuthenticationSuccess($user, $token);
150
        }
151
152
        $this->session->set(self::SESSION_PATH, $token);
153
    }
154
155
    /**
156
     * @inheritDoc
157
     */
158
    public function logout()
159
    {
160
        $this->session->remove(self::SESSION_PATH);
161
    }
162
163
    /**
164
     * @inheritDoc
165
     */
166
    public function isAuthenticated(): bool
167
    {
168
        return $this->session->has(self::SESSION_PATH) && $this->session->get(self::SESSION_PATH);
169
    }
170
171
    /**
172
     * @inheritDoc
173
     */
174
    public function prepareRequest(GraphiQLRequest $request)
175
    {
176
        $token = null;
177
        if ($this->isAuthenticated()) {
178
            $token = $this->session->get(self::SESSION_PATH);
179
        }
180
181
        $request->addHeader('Authorization', sprintf('Bearer %s', $token));
182
    }
183
}
184