Completed
Push — master ( 06c1ce...67d37c )
by Jeroen
06:20
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\Session\SessionInterface;
11
use Symfony\Component\Routing\RouterInterface;
12
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
13
use Symfony\Component\Security\Core\Exception\AuthenticationException;
14
use Symfony\Component\Security\Core\User\UserInterface;
15
use Symfony\Component\Security\Core\User\UserProviderInterface;
16
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
17
use Symfony\Component\Translation\TranslatorInterface;
18
19
class OAuthAuthenticator extends AbstractGuardAuthenticator
20
{
21
    /** @var RouterInterface */
22
    private $router;
23
24
    /** @var SessionInterface */
25
    private $session;
26
27
    /** @var TranslatorInterface */
28
    private $translator;
29
30
    /** @var OAuthUserCreator */
31
    private $oAuthUserCreator;
32
33
    /** @var string */
34
    private $clientId;
35
36
    /** @var string */
37
    private $clientSecret;
38
39
    /**
40
     * OAuthAuthenticator constructor.
41
     *
42
     * @param RouterInterface           $router
43
     * @param SessionInterface          $session
44
     * @param TranslatorInterface       $translator
45
     * @param OAuthUserCreatorInterface $oAuthUserCreator
46
     * @param $clientId
47
     * @param $clientSecret
48
     */
49
    public function __construct(RouterInterface $router, SessionInterface $session, TranslatorInterface $translator, OAuthUserCreatorInterface $oAuthUserCreator, $clientId, $clientSecret)
50
    {
51
        $this->router = $router;
52
        $this->session = $session;
53
        $this->translator = $translator;
54
        $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...
55
        $this->clientId = $clientId;
56
        $this->clientSecret = $clientSecret;
57
    }
58
59
    /**
60
     * @param Request $request
61
     *
62
     * @return bool
63
     */
64
    public function supports(Request $request)
65
    {
66
        return $request->attributes->get('_route') == 'KunstmaanAdminBundle_oauth_signin' || $request->request->has('_google_id_token');
67
    }
68
69
    /**
70
     * Returns a response that directs the user to authenticate.
71
     *
72
     * This is called when an anonymous request accesses a resource that
73
     * requires authentication. The job of this method is to return some
74
     * response that "helps" the user start into the authentication process.
75
     *
76
     * Examples:
77
     *  A) For a form login, you might redirect to the login page
78
     *      return new RedirectResponse('/login');
79
     *  B) For an API token authentication system, you return a 401 response
80
     *      return new Response('Auth header required', 401);
81
     *
82
     * @param Request                 $request       The request that resulted in an AuthenticationException
83
     * @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...
84
     *
85
     * @return RedirectResponse
86
     */
87
    public function start(Request $request, AuthenticationException $authException = null)
88
    {
89
        return new RedirectResponse($this->router->generate('fos_user_security_login'));
90
    }
91
92
    /**
93
     * Get the authentication credentials from the request and return them
94
     * as any type (e.g. an associate array).
95
     *
96
     * Whatever value you return here will be passed to getUser() and checkCredentials()
97
     *
98
     * For example, for a form login, you might:
99
     *
100
     *      return array(
101
     *          'username' => $request->request->get('_username'),
102
     *          'password' => $request->request->get('_password'),
103
     *      );
104
     *
105
     * Or for an API token that's on a header, you might use:
106
     *
107
     *      return array('api_key' => $request->headers->get('X-API-TOKEN'));
108
     *
109
     * @param Request $request
110
     *
111
     * @return array
112
     */
113
    public function getCredentials(Request $request)
114
    {
115
        $token = $request->request->get('_google_id_token');
116
117
        return [
118
            'token' => $token,
119
        ];
120
    }
121
122
    /**
123
     * Return a UserInterface object based on the credentials.
124
     *
125
     * The *credentials* are the return value from getCredentials()
126
     *
127
     * You may throw an AuthenticationException if you wish. If you return
128
     * null, then a UsernameNotFoundException is thrown for you.
129
     *
130
     * @param mixed                 $credentials
131
     * @param UserProviderInterface $userProvider
132
     *
133
     * @throws AuthenticationException
134
     *
135
     * @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...
136
     */
137
    public function getUser($credentials, UserProviderInterface $userProvider)
138
    {
139
        $idToken = $credentials['token'];
140
141
        $gc = new \Google_Client();
142
        $gc->setClientId($this->clientId);
143
        $gc->setClientSecret($this->clientSecret);
144
        $ticket = $gc->verifyIdToken($idToken);
145
        if (!$ticket instanceof \Google_LoginTicket) {
146
            return null;
147
        }
148
149
        $data = $ticket->getAttributes()['payload'];
150
        $email = $data['email'];
151
        $googleId = $data['sub'];
152
153
        return $this->oAuthUserCreator->getOrCreateUser($email, $googleId);
154
    }
155
156
    /**
157
     * Returns true if the credentials are valid.
158
     *
159
     * If any value other than true is returned, authentication will
160
     * fail. You may also throw an AuthenticationException if you wish
161
     * to cause authentication to fail.
162
     *
163
     * The *credentials* are the return value from getCredentials()
164
     *
165
     * @param mixed         $credentials
166
     * @param UserInterface $user
167
     *
168
     * @return bool
169
     *
170
     * @throws AuthenticationException
171
     */
172
    public function checkCredentials($credentials, UserInterface $user)
173
    {
174
        return true;
175
    }
176
177
    /**
178
     * Called when authentication executed, but failed (e.g. wrong username password).
179
     *
180
     * This should return the Response sent back to the user, like a
181
     * RedirectResponse to the login page or a 403 response.
182
     *
183
     * If you return null, the request will continue, but the user will
184
     * not be authenticated. This is probably not what you want to do.
185
     *
186
     * @param Request                 $request
187
     * @param AuthenticationException $exception
188
     *
189
     * @return RedirectResponse
190
     */
191
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
192
    {
193
        $this->session->getFlashBag()->add(FlashTypes::DANGER, $this->translator->trans('errors.oauth.invalid'));
194
195
        return new RedirectResponse($this->router->generate('fos_user_security_login'));
196
    }
197
198
    /**
199
     * Called when authentication executed and was successful!
200
     *
201
     * This should return the Response sent back to the user, like a
202
     * RedirectResponse to the last page they visited.
203
     *
204
     * If you return null, the current request will continue, and the user
205
     * will be authenticated. This makes sense, for example, with an API.
206
     *
207
     * @param Request        $request
208
     * @param TokenInterface $token
209
     * @param string         $providerKey The provider (i.e. firewall) key
210
     *
211
     * @return RedirectResponse
212
     */
213
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
214
    {
215
        $targetPath = $request->getSession()->get(
216
            sprintf('_security.%s.target_path', $providerKey),
217
            $this->router->generate('KunstmaanAdminBundle_homepage')
218
        );
219
220
        return new RedirectResponse($targetPath);
221
    }
222
223
    /**
224
     * Does this method support remember me cookies?
225
     *
226
     * Remember me cookie will be set if *all* of the following are met:
227
     *  A) This method returns true
228
     *  B) The remember_me key under your firewall is configured
229
     *  C) The "remember me" functionality is activated. This is usually
230
     *      done by having a _remember_me checkbox in your form, but
231
     *      can be configured by the "always_remember_me" and "remember_me_parameter"
232
     *      parameters under the "remember_me" firewall key
233
     *
234
     * @return bool
235
     */
236
    public function supportsRememberMe()
237
    {
238
        return false;
239
    }
240
}
241