Completed
Push — master ( 1de9b7...830752 )
by Kristof
38:46 queued 24:09
created

AdminBundle/Security/OAuthAuthenticator.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\AdminBundle\Security;
4
5
use Kunstmaan\AdminBundle\FlashMessages\FlashTypes;
6
use Kunstmaan\AdminBundle\Helper\Security\OAuth\OAuthUserCreator;
7
use Kunstmaan\AdminBundle\Helper\Security\OAuth\OAuthUserCreatorInterface;
8
use Symfony\Component\HttpFoundation\RedirectResponse;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\Response;
11
use Symfony\Component\HttpFoundation\Session\SessionInterface;
12
use Symfony\Component\Routing\RouterInterface;
13
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
14
use Symfony\Component\Security\Core\Exception\AuthenticationException;
15
use Symfony\Component\Security\Core\User\UserInterface;
16
use Symfony\Component\Security\Core\User\UserProviderInterface;
17
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
18
use Symfony\Component\Translation\TranslatorInterface;
19
20
class OAuthAuthenticator extends AbstractGuardAuthenticator
21
{
22
    /** @var RouterInterface */
23
    private $router;
24
25
    /** @var SessionInterface */
26
    private $session;
27
28
    /** @var TranslatorInterface */
29
    private $translator;
30
31
    /** @var OAuthUserCreator */
32
    private $oAuthUserCreator;
33
34
    /** @var string */
35
    private $clientId;
36
37
    /** @var string */
38
    private $clientSecret;
39
40
    /**
41
     * OAuthAuthenticator constructor.
42
     *
43
     * @param RouterInterface           $router
44
     * @param SessionInterface          $session
45
     * @param TranslatorInterface       $translator
46
     * @param OAuthUserCreatorInterface $oAuthUserCreator
47
     * @param $clientId
48
     * @param $clientSecret
49
     */
50
    public function __construct(RouterInterface $router, SessionInterface $session, TranslatorInterface $translator, OAuthUserCreatorInterface $oAuthUserCreator, $clientId, $clientSecret)
51
    {
52
        $this->router = $router;
53
        $this->session = $session;
54
        $this->translator = $translator;
55
        $this->oAuthUserCreator = $oAuthUserCreator;
0 ignored issues
show
Documentation Bug introduced by
$oAuthUserCreator is of type object<Kunstmaan\AdminBu...thUserCreatorInterface>, but the property $oAuthUserCreator was declared to be of type object<Kunstmaan\AdminBu...OAuth\OAuthUserCreator>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
56
        $this->clientId = $clientId;
57
        $this->clientSecret = $clientSecret;
58
    }
59
60
    /**
61
     * @param Request $request
62
     *
63
     * @return bool
64
     */
65
    public function supports(Request $request)
66
    {
67
        return $request->attributes->get('_route') == 'KunstmaanAdminBundle_oauth_signin' || $request->request->has('_google_id_token');
68
    }
69
70
    /**
71
     * Returns a response that directs the user to authenticate.
72
     *
73
     * This is called when an anonymous request accesses a resource that
74
     * requires authentication. The job of this method is to return some
75
     * response that "helps" the user start into the authentication process.
76
     *
77
     * Examples:
78
     *  A) For a form login, you might redirect to the login page
79
     *      return new RedirectResponse('/login');
80
     *  B) For an API token authentication system, you return a 401 response
81
     *      return new Response('Auth header required', 401);
82
     *
83
     * @param Request                 $request       The request that resulted in an AuthenticationException
84
     * @param AuthenticationException $authException The exception that started the authentication process
0 ignored issues
show
Should the type for parameter $authException not be null|AuthenticationException?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
85
     *
86
     * @return RedirectResponse
87
     */
88
    public function start(Request $request, AuthenticationException $authException = null)
89
    {
90
        return new RedirectResponse($this->router->generate('fos_user_security_login'));
91
    }
92
93
    /**
94
     * Get the authentication credentials from the request and return them
95
     * as any type (e.g. an associate array).
96
     *
97
     * Whatever value you return here will be passed to getUser() and checkCredentials()
98
     *
99
     * For example, for a form login, you might:
100
     *
101
     *      return array(
102
     *          'username' => $request->request->get('_username'),
103
     *          'password' => $request->request->get('_password'),
104
     *      );
105
     *
106
     * Or for an API token that's on a header, you might use:
107
     *
108
     *      return array('api_key' => $request->headers->get('X-API-TOKEN'));
109
     *
110
     * @param Request $request
111
     *
112
     * @return array
113
     */
114
    public function getCredentials(Request $request)
115
    {
116
        $token = $request->request->get('_google_id_token');
117
118
        return [
119
            'token' => $token,
120
        ];
121
    }
122
123
    /**
124
     * Return a UserInterface object based on the credentials.
125
     *
126
     * The *credentials* are the return value from getCredentials()
127
     *
128
     * You may throw an AuthenticationException if you wish. If you return
129
     * null, then a UsernameNotFoundException is thrown for you.
130
     *
131
     * @param mixed                 $credentials
132
     * @param UserProviderInterface $userProvider
133
     *
134
     * @throws AuthenticationException
135
     *
136
     * @return UserInterface|null
0 ignored issues
show
Should the return type not be null|object?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
137
     */
138
    public function getUser($credentials, UserProviderInterface $userProvider)
139
    {
140
        $idToken = $credentials['token'];
141
142
        $gc = new \Google_Client();
143
        $gc->setClientId($this->clientId);
144
        $gc->setClientSecret($this->clientSecret);
145
        $ticket = $gc->verifyIdToken($idToken);
146
        if (!$ticket instanceof \Google_LoginTicket) {
147
            return null;
148
        }
149
150
        $data = $ticket->getAttributes()['payload'];
151
        $email = $data['email'];
152
        $googleId = $data['sub'];
153
154
        return $this->oAuthUserCreator->getOrCreateUser($email, $googleId);
155
    }
156
157
    /**
158
     * Returns true if the credentials are valid.
159
     *
160
     * If any value other than true is returned, authentication will
161
     * fail. You may also throw an AuthenticationException if you wish
162
     * to cause authentication to fail.
163
     *
164
     * The *credentials* are the return value from getCredentials()
165
     *
166
     * @param mixed         $credentials
167
     * @param UserInterface $user
168
     *
169
     * @return bool
170
     *
171
     * @throws AuthenticationException
172
     */
173
    public function checkCredentials($credentials, UserInterface $user)
174
    {
175
        return true;
176
    }
177
178
    /**
179
     * Called when authentication executed, but failed (e.g. wrong username password).
180
     *
181
     * This should return the Response sent back to the user, like a
182
     * RedirectResponse to the login page or a 403 response.
183
     *
184
     * If you return null, the request will continue, but the user will
185
     * not be authenticated. This is probably not what you want to do.
186
     *
187
     * @param Request                 $request
188
     * @param AuthenticationException $exception
189
     *
190
     * @return RedirectResponse
191
     */
192
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
193
    {
194
        $this->session->getFlashBag()->add(FlashTypes::ERROR, $this->translator->trans('errors.oauth.invalid'));
195
196
        return new RedirectResponse($this->router->generate('fos_user_security_login'));
197
    }
198
199
    /**
200
     * Called when authentication executed and was successful!
201
     *
202
     * This should return the Response sent back to the user, like a
203
     * RedirectResponse to the last page they visited.
204
     *
205
     * If you return null, the current request will continue, and the user
206
     * will be authenticated. This makes sense, for example, with an API.
207
     *
208
     * @param Request        $request
209
     * @param TokenInterface $token
210
     * @param string         $providerKey The provider (i.e. firewall) key
211
     *
212
     * @return RedirectResponse
213
     */
214
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
215
    {
216
        $targetPath = $request->getSession()->get(
217
            sprintf('_security.%s.target_path', $providerKey),
218
            $this->router->generate('KunstmaanAdminBundle_homepage')
219
        );
220
221
        return new RedirectResponse($targetPath);
222
    }
223
224
    /**
225
     * Does this method support remember me cookies?
226
     *
227
     * Remember me cookie will be set if *all* of the following are met:
228
     *  A) This method returns true
229
     *  B) The remember_me key under your firewall is configured
230
     *  C) The "remember me" functionality is activated. This is usually
231
     *      done by having a _remember_me checkbox in your form, but
232
     *      can be configured by the "always_remember_me" and "remember_me_parameter"
233
     *      parameters under the "remember_me" firewall key
234
     *
235
     * @return bool
236
     */
237
    public function supportsRememberMe()
238
    {
239
        return false;
240
    }
241
}
242