Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
80.65% covered (warning)
80.65%
25 / 31
75.00% covered (warning)
75.00%
9 / 12
55.56% covered (warning)
55.56%
5 / 9
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
EnvAuthenticator
80.65% covered (warning)
80.65%
25 / 31
75.00% covered (warning)
75.00%
9 / 12
55.56% covered (warning)
55.56%
5 / 9
50.00% covered (danger)
50.00%
3 / 6
16.11
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
 getLoginEnvVar
75.00% covered (warning)
75.00%
3 / 4
66.67% covered (warning)
66.67%
2 / 3
50.00% covered (danger)
50.00%
1 / 2
0.00% covered (danger)
0.00%
0 / 1
2.50
 supports
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
3 / 3
50.00% covered (danger)
50.00%
1 / 2
100.00% covered (success)
100.00%
1 / 1
2.50
 authenticate
94.74% covered (success)
94.74%
18 / 19
66.67% covered (warning)
66.67%
2 / 3
50.00% covered (danger)
50.00%
1 / 2
0.00% covered (danger)
0.00%
0 / 1
2.50
 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
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Security;
4
5use Symfony\Component\HttpFoundation\JsonResponse;
6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\HttpFoundation\Response;
8use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
9use Symfony\Component\Security\Core\Exception\AuthenticationException;
10use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
11use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
12use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
13use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
14use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
15
16/**
17 * @phpstan-type Settings array{
18 *     APP_AUTH_FROM_ENV_VAR?:bool|string|null,
19 *     APP_USER_LOGIN?:string|null,
20 *     APP_USER_ROLES?:string|null,
21 *     APP_USER_EMAIL?:string|null,
22 *     APP_USER_FIRSTNAME?:string|null,
23 *     APP_USER_NAME?:string|null,
24 *     APP_USER_FULLNAME?:string|null
25 * }
26 */
27class EnvAuthenticator extends AbstractAuthenticator
28{
29    /** @var Settings */
30    private array $settings;
31
32    /**
33     * @param Settings $settings
34     */
35    public function __construct(array $settings)
36    {
37        $this->settings = $settings;
38    }
39
40    protected function getLoginEnvVar(): ?string
41    {
42        $login = $this->settings['APP_USER_LOGIN'] ?? null;
43        if (is_string($login)) {
44            return mb_strtoupper($login);
45        }
46
47        return null;
48    }
49
50    public function supports(Request $request): ?bool
51    {
52        return filter_var($this->settings['APP_AUTH_FROM_ENV_VAR'] ?? false, FILTER_VALIDATE_BOOLEAN)
53            && null !== $this->getLoginEnvVar();
54    }
55
56    public function authenticate(Request $request): Passport
57    {
58        $login = $this->getLoginEnvVar();
59        if (null === $login) {
60            // The token header was empty, authentication fails with HTTP Status
61            // Code 401 "Unauthorized"
62            throw new CustomUserMessageAuthenticationException('No API token provided');
63        }
64
65        return new SelfValidatingPassport(
66            new UserBadge($login, function ($login): User {
67                $user = new User();
68                /** @var string $ginaRoles */
69                $ginaRoles = $this->settings['APP_USER_ROLES'] ?? '';
70                /** @var array<string, list<string>> $attributes */
71                $attributes = [
72                    User::USERNAME => [$login],
73                    User::EMAIL => [$this->settings['APP_USER_EMAIL'] ?? null],
74                    User::NAME => [$this->settings['APP_USER_NAME'] ?? null],
75                    User::FIRSTNAME => [$this->settings['APP_USER_FIRSTNAME'] ?? null],
76                    User::FULLNAME => [$this->settings['APP_USER_FULLNAME'] ?? null],
77                    User::ROLES => explode('|', mb_strtoupper($ginaRoles)),
78                ];
79                $user->setEnvAttributes($attributes);
80
81                return $user;
82            })
83        );
84    }
85
86    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
87    {
88        // on success, let the request continue
89        return null;
90    }
91
92    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
93    {
94        $data = [
95            // you may want to customize or obfuscate the message first
96            'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
97        ];
98
99        return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
100    }
101}