1+ <?php
2+
3+ /* For licensing terms, see /license.txt */
4+
5+ declare (strict_types=1 );
6+
7+ namespace Chamilo \CoreBundle \Security \Authenticator ;
8+
9+ use Lexik \Bundle \JWTAuthenticationBundle \Services \JWTTokenManagerInterface ;
10+ use Symfony \Component \HttpFoundation \RedirectResponse ;
11+ use Symfony \Component \HttpFoundation \Request ;
12+ use Symfony \Component \HttpFoundation \Response ;
13+ use Symfony \Component \Routing \RouterInterface ;
14+ use Symfony \Component \Security \Core \Authentication \Token \TokenInterface ;
15+ use Symfony \Component \Security \Core \Exception \AuthenticationException ;
16+ use Symfony \Component \Security \Core \User \UserProviderInterface ;
17+ use Symfony \Component \Security \Http \Authenticator \AbstractAuthenticator ;
18+ use Symfony \Component \Security \Http \Authenticator \Passport \Badge \UserBadge ;
19+ use Symfony \Component \Security \Http \Authenticator \Passport \Passport ;
20+ use Symfony \Component \Security \Http \Authenticator \Passport \SelfValidatingPassport ;
21+
22+ class LoginTokenAuthenticator extends AbstractAuthenticator
23+ {
24+ public function __construct (
25+ protected readonly UserProviderInterface $ userProvider ,
26+ protected readonly RouterInterface $ router ,
27+ protected readonly JWTTokenManagerInterface $ jwtManager
28+ ) {}
29+
30+ /**
31+ * @inheritDoc
32+ */
33+ public function supports (Request $ request ): ?bool
34+ {
35+ return $ request ->attributes ->get ('_route ' ) === 'login_token_check '
36+ && $ request ->headers ->has ('Authorization ' )
37+ ;
38+ }
39+
40+ /**
41+ * @inheritDoc
42+ */
43+ public function authenticate (Request $ request ): Passport
44+ {
45+ $ authHeader = $ request ->headers ->get ('Authorization ' );
46+
47+ if (!$ authHeader || !str_starts_with ($ authHeader , 'Bearer ' )) {
48+ throw new AuthenticationException ('Missing token. ' );
49+ }
50+
51+ $ jwt = substr ($ authHeader , 7 );
52+
53+ try {
54+ $ payload = $ this ->jwtManager ->parse ($ jwt );
55+ $ username = $ payload ['username ' ] ?? $ payload ['sub ' ] ?? null ;
56+
57+ if (!$ username ) {
58+ throw new AuthenticationException ('Token does not contain a username. ' );
59+ }
60+
61+ } catch (\Exception $ e ) {
62+ throw new AuthenticationException ('Invalid JWT token: ' .$ e ->getMessage ());
63+ }
64+
65+ return new SelfValidatingPassport (
66+ new UserBadge (
67+ $ username ,
68+ fn (string $ username ) => $ this ->userProvider ->loadUserByIdentifier ($ username )
69+ )
70+ );
71+ }
72+
73+ /**
74+ * @inheritDoc
75+ */
76+ public function onAuthenticationSuccess (Request $ request , TokenInterface $ token , string $ firewallName ): ?Response
77+ {
78+ $ targetUrl = $ this ->router ->generate ('index ' );
79+
80+ return new RedirectResponse ($ targetUrl );
81+ }
82+
83+ /**
84+ * @inheritDoc
85+ */
86+ public function onAuthenticationFailure (Request $ request , AuthenticationException $ exception ): ?Response
87+ {
88+ $ message = strtr ($ exception ->getMessage (), $ exception ->getMessageData ());
89+
90+ return new Response ($ message , Response::HTTP_FORBIDDEN );
91+ }
92+ }
0 commit comments