Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
93.75% covered (success)
93.75%
15 / 16
88.89% covered (warning)
88.89%
8 / 9
85.71% covered (warning)
85.71%
6 / 7
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ClientAuthenticator
93.75% covered (success)
93.75%
15 / 16
88.89% covered (warning)
88.89%
8 / 9
85.71% covered (warning)
85.71%
6 / 7
80.00% covered (warning)
80.00%
4 / 5
7.14
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
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 authenticate
88.89% covered (warning)
88.89%
8 / 9
80.00% covered (warning)
80.00%
4 / 5
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
3.33
 supports
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 onAuthenticationSuccess
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 onAuthenticationFailure
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Security\Authenticator;
4
5use App\Security\ApiUser;
6use App\Service\Data\ApiKeyServiceInterface;
7use Symfony\Component\DependencyInjection\Attribute\Autowire;
8use Symfony\Component\HttpFoundation\JsonResponse;
9use Symfony\Component\HttpFoundation\Request;
10use Symfony\Component\HttpFoundation\Response;
11use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
12use Symfony\Component\Security\Core\Exception\AuthenticationException;
13use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
14use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
15use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
16use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
17
18/**
19 * @author Wilhelm Zwertvaegher
20 */
21class ClientAuthenticator extends AbstractAuthenticator
22{
23    public function __construct(
24        #[Autowire('%client.api_key_header%')]
25        private readonly string $clientApiKeyHeader,
26        private readonly ApiKeyServiceInterface $apiKeyService,
27    ) {
28    }
29
30    public function authenticate(Request $request): Passport
31    {
32        $clientApiKey = $request->headers->get($this->clientApiKeyHeader);
33
34        if (!$clientApiKey) {
35            throw new AuthenticationException('Invalid api key');
36        }
37
38        $apiKey = $this->apiKeyService->findValidKey($clientApiKey);
39        if (!$apiKey) {
40            throw new AuthenticationException('Invalid api key');
41        }
42
43        return new SelfValidatingPassport(
44            new UserBadge('client', fn (string $userIdentifier) => new ApiUser($userIdentifier, ['ROLE_CLIENT']))
45        );
46    }
47
48    public function supports(Request $request): ?bool
49    {
50        return $request->headers->has($this->clientApiKeyHeader);
51    }
52
53    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
54    {
55        return null;
56    }
57
58    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
59    {
60        $data = [
61            'message' => $exception->getMessage(),
62        ];
63
64        return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
65    }
66}