Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
7.69% covered (danger)
7.69%
2 / 26
28.57% covered (danger)
28.57%
2 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
GoogleAuthenticator
7.69% covered (danger)
7.69%
2 / 26
28.57% covered (danger)
28.57%
2 / 7
58.34
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 supports
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 authenticate
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getGoogleClient
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUser
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 getSuccessRedirectUrl
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFailureRedirectUrl
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace App\Security;
6
7use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
8use App\Entity\User;
9use App\Repository\UserRepository;
10use Doctrine\ORM\EntityManagerInterface;
11use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
12use KnpU\OAuth2ClientBundle\Client\OAuth2ClientInterface;
13use League\OAuth2\Client\Provider\GoogleUser;
14use Symfony\Component\HttpFoundation\Request;
15use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
17use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
18use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
19use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
20use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
21use Symfony\Component\Security\Http\Util\TargetPathTrait;
22
23class GoogleAuthenticator extends AbstractAuthenticator
24{
25    use TargetPathTrait;
26    use AuthenticationResultTrait;
27
28    public function __construct(
29        private readonly ClientRegistry $clientRegistry,
30        private readonly EntityManagerInterface $entityManager,
31        private readonly UserRepository $userRepository,
32        private readonly UrlGeneratorInterface $urlGenerator,
33    ) {}
34
35    public function supports(Request $request): bool
36    {
37        return $request->getPathInfo() === '/connect/google/check';
38    }
39
40    /**
41     * @throws IdentityProviderException
42     */
43    public function authenticate(Request $request): Passport
44    {
45        $token = $this->getGoogleClient()->getAccessToken();
46
47        /** @var GoogleUser $googleUser */
48        $googleUser = $this->getGoogleClient()
49            ->fetchUserFromToken($token);
50
51        $user = $this->getUser($googleUser);
52
53        return new SelfValidatingPassport(
54            new UserBadge($user->getUserIdentifier()),
55            [new RememberMeBadge()],
56        );
57    }
58
59    private function getGoogleClient(): OAuth2ClientInterface
60    {
61        return $this->clientRegistry->getClient('google');
62    }
63
64    private function getUser(GoogleUser $googleUser): User
65    {
66        $user = $this->userRepository->findOneBy(
67            ['googleId' => $googleUser->getId()]
68        );
69
70        if ($user instanceof User) {
71            return $user;
72        }
73
74        /** @var string $email */
75        $email = $googleUser->getEmail();
76        /** @var string $googleId */
77        $googleId = $googleUser->getId();
78        $user = new User()
79            ->setIdentifier($email)
80            ->setGoogleId($googleId);
81
82        $this->entityManager->persist($user);
83        $this->entityManager->flush();
84
85        return $user;
86    }
87
88    private function getSuccessRedirectUrl(): string
89    {
90        return $this->urlGenerator->generate('default');
91    }
92
93    private function getFailureRedirectUrl(): string
94    {
95        return $this->urlGenerator->generate('login');
96    }
97}