Completed
Push — main ( 2df326...083b32 )
by Michael
19s queued 13s
created

ApiTokenAuthenticator::onAuthenticationFailure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 11
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Licensed under MIT. See file /LICENSE.
7
 */
8
9
namespace App\Security;
10
11
use App\Entity\Api\AccessKey;
12
use App\Entity\User;
13
use Doctrine\ORM\EntityManagerInterface;
14
use Symfony\Component\HttpFoundation\JsonResponse;
15
use Symfony\Component\HttpFoundation\Request;
16
use Symfony\Component\HttpFoundation\Response;
17
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
18
use Symfony\Component\Security\Core\Exception\AuthenticationException;
19
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
20
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
21
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
22
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
23
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
24
25
class ApiTokenAuthenticator extends AbstractAuthenticator
26
{
27
    private EntityManagerInterface $entityManager;
28
29
    public function __construct(
30
        EntityManagerInterface $entityManager
31
    ) {
32
        $this->entityManager = $entityManager;
33
    }
34
35
    /**
36
     * Called on every request to decide if this authenticator should be
37
     * used for the request. Returning `false` will cause this authenticator
38
     * to be skipped.
39
     */
40
    public function supports(Request $request): ?bool
41
    {
42
        return $request->headers->has('X-API-TOKEN');
43
    }
44
45
    public function authenticate(Request $request): Passport
46
    {
47
        $apiToken = $request->headers->get('X-API-TOKEN');
48
        if (null === $apiToken) {
0 ignored issues
show
introduced by
The condition null === $apiToken is always false.
Loading history...
49
            // The token header was empty, authentication fails with HTTP Status
50
            // Code 401 "Unauthorized"
51
            throw new CustomUserMessageAuthenticationException('No API token provided');
52
        }
53
54
        /** @var AccessKey|null $apiToken */
55
        $apiToken = $this->entityManager->getRepository(AccessKey::class)->findBy(['code' => $request->headers->get('x-api-token')]);
56
        if (empty($apiToken)) {
57
            throw new AuthenticationException('API token invalid.');
58
        }
59
60
        /** @var User|null $user */
61
        $user = $apiToken[0]->getOwner();
62
        if (null === $user) {
63
            throw new AuthenticationException('API token invalid.');
64
        }
65
66
        return new SelfValidatingPassport(new UserBadge($user->getEmail()));
67
    }
68
69
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
70
    {
71
        // on success, let the request continue
72
        return null;
73
    }
74
75
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
76
    {
77
        $data = [
78
            // you may want to customize or obfuscate the message first
79
            'message' => \strtr($exception->getMessageKey(), $exception->getMessageData()),
80
81
            // or to translate this message
82
            // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
83
        ];
84
85
        return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
86
    }
87
}
88