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