Your IP : 216.73.217.79


Current Path : /var/www/v3.cesa.co.za/src/UserBundle/Security/
Upload File :
Current File : /var/www/v3.cesa.co.za/src/UserBundle/Security/OAuth2Authenticator.php

<?php

namespace App\UserBundle\Security;

use League\OAuth2\Server\ResourceServer;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use App\UserBundle\Entity\UserList;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Http\Message\ServerRequestInterface;

class OAuth2Authenticator extends AbstractAuthenticator
{
    private ResourceServer $resourceServer;
    private EntityManagerInterface $entityManager;

    public function __construct(ResourceServer $resourceServer, EntityManagerInterface $entityManager)
    {
        $this->resourceServer = $resourceServer;
        $this->entityManager = $entityManager;
    }

    public function supports(Request $request): ?bool
    {
        return $request->headers->has('Authorization') &&
            str_starts_with($request->headers->get('Authorization'), 'Bearer ');
    }

    public function authenticate(Request $request): Passport
    {
        $authorizationHeader = $request->headers->get('Authorization');

        if (!$authorizationHeader) {
            throw new CustomUserMessageAuthenticationException('No Authorization header provided');
        }

        if (!str_starts_with($authorizationHeader, 'Bearer ')) {
            throw new CustomUserMessageAuthenticationException('Invalid Authorization header format');
        }

        $token = substr($authorizationHeader, 7); // Remove 'Bearer ' prefix

        try {
            // Create a PSR-7 request for the OAuth2 resource server
            $psrRequest = new \Nyholm\Psr7\ServerRequest(
                'GET',
                $request->getUri(),
                ['Authorization' => 'Bearer ' . $token],
                null,
                '1.1'
            );

            // Validate the OAuth2 token using the resource server
            $serverRequest = $this->resourceServer->validateAuthenticatedRequest($psrRequest);

            // Extract user information from the token
            $userId = $serverRequest->getAttribute('oauth_user_id');
            $clientId = $serverRequest->getAttribute('oauth_client_id');

            if (!$userId && !$clientId) {
                throw new CustomUserMessageAuthenticationException('Invalid OAuth2 token: no user or client ID found');
            }

            return new SelfValidatingPassport(
                new UserBadge($userId ?: $clientId, function ($identifier) use ($userId, $clientId) {
                    // Try to load user by ID first, then by client ID
                    $user = null;

                    if ($userId) {
                        $user = $this->entityManager->getRepository(UserList::class)->findOneBy(['username' => 'oauth_client']);
                    }

                    // If no user found by ID, try to find by client ID or create a system user
                    if (!$user && $clientId) {
                        // For client credentials flow, create a system user
                        $user = new UserList();
                        $user->setUsername('oauth_client');
                        $user->setIsActive(true);
                        $user->setIsSuperAdmin(false); // Set default value to prevent constraint violation
                        $user->setEMailAddressString('system@cesa.org.za');
                        $user->setFirstNameString('OAuth Client');
                        $user->setLastNameString($clientId);
                        $user->setEMailAddressSubscribed(false);
                        $user->setDeleted(false);

                        // Set a default password (not used for OAuth2)
                        $user->setPassword('oauth2_client_' . $clientId);

                        // Persist the user
                        $this->entityManager->persist($user);
                        $this->entityManager->flush();
                    }

                    if (!$user) {
                        throw new CustomUserMessageAuthenticationException('User not found');
                    }

                    return $user;
                })
            );
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $e) {
            throw new CustomUserMessageAuthenticationException('OAuth2 validation failed: ' . $e->getMessage());
        } catch (\Exception $e) {
            throw new CustomUserMessageAuthenticationException('Invalid OAuth2 token: ' . $e->getMessage());
        }
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        // Authentication successful, continue with the request
        return null;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        return new JsonResponse([
            'error' => 'Unauthorized',
            'message' => $exception->getMessage()
        ], Response::HTTP_UNAUTHORIZED);
    }
}