src/App/Service/Security/AuthServer.php line 79

Open in your IDE?
  1. <?php
  2. namespace App\Service\Security;
  3. use App\Exception\Security\ChangePasswordException;
  4. use App\Exception\Security\CreateUserException;
  5. use App\Exception\Security\InvalidAccessTokenException;
  6. use App\Exception\Security\UpdateUserException;
  7. use Aqarmap\Bundle\UserBundle\Constant\Oauth2GrantTypes;
  8. use Aqarmap\Bundle\UserBundle\Entity\User;
  9. use Psr\Cache\CacheItemPoolInterface;
  10. use Psr\Log\LoggerInterface;
  11. use Symfony\Component\HttpFoundation\Request as httpRequest;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Security\Core\User\UserInterface;
  14. use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
  15. use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
  16. use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
  17. use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
  18. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  19. use Symfony\Contracts\HttpClient\HttpClientInterface;
  20. class AuthServer
  21. {
  22.     private HttpClientInterface $client;
  23.     private CacheItemPoolInterface $cachePool;
  24.     private LoggerInterface $logger;
  25.     private string $authClientId;
  26.     private string $authClientSecret;
  27.     private string $publicServerUrl;
  28.     public function __construct(HttpClientInterface $authClientCacheItemPoolInterface $cachePoolLoggerInterface $loggerstring $authClientIdstring $authClientSecretstring $publicServerUrl)
  29.     {
  30.         $this->client $authClient;
  31.         $this->authClientId $authClientId;
  32.         $this->authClientSecret $authClientSecret;
  33.         $this->publicServerUrl $publicServerUrl;
  34.         $this->cachePool $cachePool;
  35.         $this->logger $logger;
  36.     }
  37.     /**
  38.      * @throws TransportExceptionInterface
  39.      * @throws ServerExceptionInterface
  40.      * @throws RedirectionExceptionInterface
  41.      * @throws ClientExceptionInterface
  42.      * @throws DecodingExceptionInterface
  43.      */
  44.     public function getUser(string $token): array
  45.     {
  46.         return $this->client->request('GET''api/profile', [
  47.             'auth_bearer' => $token,
  48.             'headers' => [
  49.                 'Accept' => 'application/json',
  50.             ],
  51.         ])->toArray();
  52.     }
  53.     public function getTokenInfo(string $tokenbool $useCache true): array
  54.     {
  55.         $cachedRequest $this->cachePool->getItem(sprintf('token-info-%s'sha1($token)));
  56.         if (!$useCache || !$cachedRequest->isHit() || empty($cachedRequest->get())) {
  57.             $request $this->client->request('GET''api/token-info', [
  58.                 'auth_bearer' => $token,
  59.                 'headers' => [
  60.                     'Accept' => 'application/json',
  61.                 ],
  62.             ]);
  63.             $this->logger->debug('Token Info: Validating against auth server.');
  64.             if (Response::HTTP_OK == $request->getStatusCode()) {
  65.                 $cachedRequest->set($request->toArray(false));
  66.                 $cachedRequest->expiresAfter(60);
  67.                 $this->cachePool->save($cachedRequest);
  68.             } else {
  69.                 $this->logger->debug(sprintf('Token Info: Invalid token. Status code: %s'$request->getStatusCode()));
  70.                 throw new InvalidAccessTokenException(sprintf('Token Info: Invalid token. Status code: %s'$request->getStatusCode()));
  71.             }
  72.         } else {
  73.             $this->logger->debug('Token Info: Retrieved from cache.');
  74.         }
  75.         return $cachedRequest->get();
  76.     }
  77.     /**
  78.      * @throws TransportExceptionInterface
  79.      * @throws ServerExceptionInterface
  80.      * @throws RedirectionExceptionInterface
  81.      * @throws ClientExceptionInterface
  82.      * @throws DecodingExceptionInterface
  83.      * @throws CreateUserException
  84.      */
  85.     public function register(User $user): array
  86.     {
  87.         $countryCode $user->getCountryCode() ?? $user->getTempCountryCode();
  88.         try {
  89.             $request $this->client->request('POST''api/register', [
  90.                 'body' => [
  91.                     'fullName' => $user->getFullName(),
  92.                     'email' => $user->getEmailCanonical(),
  93.                     'plainPassword' => $user->getPlainPassword(),
  94.                     'phoneNumber' => $countryCode.ltrim($user->getMainPhoneNumber(), '0'),
  95.                 ],
  96.             ]);
  97.             if (Response::HTTP_OK != $request->getStatusCode()) {
  98.                 $response $request->toArray(false);
  99.                 $errors $this->parseFormErrors($response['form'] ?? null);
  100.                 throw new CreateUserException($errors['firstError'], $request->getStatusCode());
  101.             }
  102.             return $request->toArray();
  103.         } catch (\Exception $exception) {
  104.             throw new CreateUserException($exception->getMessage(), $exception->getCode(), $exception);
  105.         }
  106.     }
  107.     public function createUser(string $name, ?string $email, ?string $phoneNumber, ?string $password): array
  108.     {
  109.         try {
  110.             $request $this->client->request('POST''api/register', [
  111.                 'body' => [
  112.                     'fullName' => $name,
  113.                     'email' => $email,
  114.                     'plainPassword' => $password,
  115.                     'phoneNumber' => $phoneNumber,
  116.                 ],
  117.             ]);
  118.             if (Response::HTTP_OK != $request->getStatusCode()) {
  119.                 $response $request->toArray(false);
  120.                 $errors $this->parseFormErrors($response['form'] ?? null);
  121.                 throw new CreateUserException(reset($errors), $request->getStatusCode());
  122.             }
  123.             return $request->toArray();
  124.         } catch (\Exception $exception) {
  125.             throw new CreateUserException($exception->getMessage(), $exception->getCode(), $exception);
  126.         }
  127.     }
  128.     /**
  129.      * @throws TransportExceptionInterface
  130.      * @throws ServerExceptionInterface
  131.      * @throws RedirectionExceptionInterface
  132.      * @throws ClientExceptionInterface
  133.      * @throws DecodingExceptionInterface
  134.      */
  135.     public function getToken(httpRequest $request)
  136.     {
  137.         $grantType $request->get('grant_type'Oauth2GrantTypes::PASSWORD);
  138.         $username $request->get('username'$request->get('email'));
  139.         $password $request->request->get('plainPassword')['first'] ?? $request->request->get('plainPassword');
  140.         return $this->client->request('POST''/token', [
  141.             'body' => [
  142.                 'client_id' => $this->authClientId,
  143.                 'client_secret' => $this->authClientSecret,
  144.                 'grant_type' => $grantType,
  145.                 'username' => $username,
  146.                 'password' => $password,
  147.             ],
  148.         ])->toArray();
  149.     }
  150.     public function getClientCredentialsAccessToken($useCache true)
  151.     {
  152.         $cache $this->cachePool->getItem('client-credentials-access-token');
  153.         if (!$useCache || !$cache->isHit() || empty($cache->get())) {
  154.             $request $this->client->request('POST''/token', [
  155.                 'body' => [
  156.                     'client_id' => $this->authClientId,
  157.                     'client_secret' => $this->authClientSecret,
  158.                     'grant_type' => 'client_credentials',
  159.                 ],
  160.             ])->toArray();
  161.             $cache->set($request['access_token']);
  162.             $cache->expiresAfter((int) floor(($request['expires_in'] ?? 60) / 2));
  163.             $this->cachePool->save($cache);
  164.         }
  165.         return $cache->get();
  166.     }
  167.     public function lookupUserByLoginIdentifier(string $loginIdentifier): ?string
  168.     {
  169.         $request $this->client->request('POST''api/user/lookup', [
  170.             'body' => [
  171.                 'loginIdentifier' => $loginIdentifier,
  172.             ],
  173.             'auth_bearer' => $this->getClientCredentialsAccessToken(),
  174.             'headers' => [
  175.                 'Host' => $this->getPublicHost(),
  176.             ],
  177.         ]);
  178.         return $request->toArray()['user']['id'] ?? null;
  179.     }
  180.     /**
  181.      * @throws TransportExceptionInterface
  182.      * @throws ChangePasswordException
  183.      */
  184.     public function changePassword(UserInterface $userstring $currentPasswordstring $newPassword): void
  185.     {
  186.         try {
  187.             $request $this->client->request('POST''api/user/change-password', [
  188.                 'body' => [
  189.                     'plainPassword[first]' => $newPassword,
  190.                     'plainPassword[second]' => $newPassword,
  191.                     'currentPassword' => $currentPassword,
  192.                 ],
  193.                 'auth_bearer' => $user->getUserAccessToken(),
  194.             ]);
  195.             if (Response::HTTP_OK != $request->getStatusCode()) {
  196.                 $response $request->toArray(false);
  197.                 throw new ChangePasswordException($response['message'], $request->getStatusCode());
  198.             }
  199.         } catch (\Exception $exception) {
  200.             throw new ChangePasswordException($exception->getMessage(), $exception->getCode(), $exception);
  201.         }
  202.     }
  203.     public function resetPassword(string $email): void
  204.     {
  205.         try {
  206.             $this->client->request('POST''api/request-reset-password', [
  207.                 'body' => [
  208.                     'email' => $email,
  209.                 ],
  210.                 'auth_bearer' => $this->getClientCredentialsAccessToken(),
  211.                 'headers' => [
  212.                     'Host' => $this->getPublicHost(),
  213.                 ],
  214.             ]);
  215.         } catch (\Exception $exception) {
  216.             throw new ChangePasswordException($exception->getMessage(), $exception->getCode(), $exception);
  217.         }
  218.     }
  219.     /**
  220.      * @throws UpdateUserException
  221.      */
  222.     public function updateUser(UserInterface $user): void
  223.     {
  224.         $body = [
  225.             'fullName' => $user->getFullName(),
  226.             'phoneNumber' => ltrim($user->getPhoneNumber(), '+'),
  227.             'email' => $user->getEmail(),
  228.         ];
  229.         $response $this->client->request('POST'sprintf('api/user/update?_locale=%s'$user->getLanguage()), [
  230.             'body' => $body,
  231.             'auth_bearer' => $user->getUserAccessToken(),
  232.             'headers' => [
  233.                 'Accept-Language' => $user->getLanguage(),
  234.             ],
  235.         ]);
  236.         if (Response::HTTP_OK != $response->getStatusCode()) {
  237.             $responseBody $response->toArray(false);
  238.             $errors $this->parseFormErrors($responseBody['form'] ?? null);
  239.             throw new UpdateUserException(reset($errors) ?? json_encode(['body' => $body'response' => $responseBody]), $response->getStatusCode());
  240.         }
  241.     }
  242.     public function parseFormErrors(?array $response): array
  243.     {
  244.         $errorList = [];
  245.         if (!empty($response['errors'])) {
  246.             foreach ($response['errors'] as $error) {
  247.                 if ($message $error['message'] ?? null) {
  248.                     $errorList[] = $message;
  249.                 }
  250.             }
  251.         }
  252.         if (isset($response['children'])) {
  253.             foreach ($response['children'] as $children) {
  254.                 $errorList array_merge($errorList$this->parseFormErrors($children));
  255.             }
  256.         }
  257.         return $errorList;
  258.     }
  259.     private function getPublicHost(): string
  260.     {
  261.         return parse_url($this->publicServerUrlPHP_URL_HOST);
  262.     }
  263. }