diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index dd907d4..ed36eed 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -325,31 +325,6 @@ parameters: count: 1 path: src/lib/Mapper/ContentImageAssetMapperStrategy.php - - - message: "#^Cannot access property \\$attributes on Symfony\\\\Component\\\\HttpFoundation\\\\Request\\|null\\.$#" - count: 2 - path: src/lib/Mutation/Authentication.php - - - - message: "#^Method Ibexa\\\\GraphQL\\\\Mutation\\\\Authentication\\:\\:createToken\\(\\) has parameter \\$args with no type specified\\.$#" - count: 1 - path: src/lib/Mutation/Authentication.php - - - - message: "#^Method Ibexa\\\\GraphQL\\\\Mutation\\\\Authentication\\:\\:createToken\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Mutation/Authentication.php - - - - message: "#^Parameter \\#1 \\$request of method Ibexa\\\\Core\\\\MVC\\\\Symfony\\\\Security\\\\Authentication\\\\AuthenticatorInterface\\:\\:authenticate\\(\\) expects Symfony\\\\Component\\\\HttpFoundation\\\\Request, Symfony\\\\Component\\\\HttpFoundation\\\\Request\\|null given\\.$#" - count: 1 - path: src/lib/Mutation/Authentication.php - - - - message: "#^Parameter \\#1 \\$wrappedUser of class Ibexa\\\\GraphQL\\\\Security\\\\JWTUser constructor expects Symfony\\\\Component\\\\Security\\\\Core\\\\User\\\\UserInterface, Symfony\\\\Component\\\\Security\\\\Core\\\\User\\\\UserInterface\\|null given\\.$#" - count: 1 - path: src/lib/Mutation/Authentication.php - - message: "#^Method Ibexa\\\\GraphQL\\\\Mutation\\\\InputHandler\\\\FieldType\\\\BinaryFile\\:\\:toFieldValue\\(\\) has parameter \\$input with no type specified\\.$#" count: 1 @@ -2330,11 +2305,6 @@ parameters: count: 1 path: src/lib/Schema/Worker.php - - - message: "#^Method Ibexa\\\\GraphQL\\\\Security\\\\NonAdminGraphQLRequestMatcher\\:\\:__construct\\(\\) has parameter \\$siteAccessGroups with no value type specified in iterable type array\\.$#" - count: 1 - path: src/lib/Security/NonAdminGraphQLRequestMatcher.php - - message: "#^Cannot cast object to string\\.$#" count: 1 diff --git a/src/bundle/Resources/config/services/resolvers.yaml b/src/bundle/Resources/config/services/resolvers.yaml index 8b55469..d25fffc 100644 --- a/src/bundle/Resources/config/services/resolvers.yaml +++ b/src/bundle/Resources/config/services/resolvers.yaml @@ -62,9 +62,7 @@ services: tags: - { name: overblog_graphql.resolver, alias: "Thumbnail", method: "resolveThumbnail" } - Ibexa\GraphQL\Mutation\Authentication: - arguments: - $authenticator: '@?ibexa.rest.session_authenticator' + Ibexa\GraphQL\Mutation\AuthenticationMutation: tags: - { name: overblog_graphql.mutation, alias: "CreateToken", method: "createToken" } diff --git a/src/lib/Mutation/Authentication.php b/src/lib/Mutation/Authentication.php deleted file mode 100644 index 3b65a94..0000000 --- a/src/lib/Mutation/Authentication.php +++ /dev/null @@ -1,76 +0,0 @@ -tokenManager = $tokenManager; - $this->requestStack = $requestStack; - $this->authenticator = $authenticator; - } - - /** - * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException - */ - public function createToken($args): array - { - $username = $args['username']; - $password = $args['password']; - - $request = $this->requestStack->getCurrentRequest(); - $request->attributes->set('username', $username); - $request->attributes->set('password', (string) $password); - - try { - $user = $this->getAuthenticator()->authenticate($request)->getUser(); - - $token = $this->tokenManager->create( - new JWTUser($user, $username) - ); - - return ['token' => $token]; - } catch (AuthenticationException $e) { - return ['message' => 'Wrong username or password', 'token' => null]; - } - } - - private function getAuthenticator(): AuthenticatorInterface - { - if (null === $this->authenticator) { - throw new \RuntimeException( - sprintf( - "No %s instance injected. Ensure 'ezpublish_rest_session' is configured under your firewall", - AuthenticatorInterface::class - ) - ); - } - - return $this->authenticator; - } -} diff --git a/src/lib/Mutation/AuthenticationMutation.php b/src/lib/Mutation/AuthenticationMutation.php new file mode 100644 index 0000000..eabb351 --- /dev/null +++ b/src/lib/Mutation/AuthenticationMutation.php @@ -0,0 +1,64 @@ + + * + * @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException + */ + public function createToken(Argument $args): array + { + if (!isset($args['username'], $args['password'])) { + return [ + 'message' => 'Missing username or password', + 'token' => null, + ]; + } + + try { + $user = $this->userService->loadUserByLogin($args['username']); + } catch (NotFoundException) { + return $this->getWrongCredentialsErrorMessage(); + } + + if (!$this->userService->checkUserCredentials($user, $args['password'])) { + return $this->getWrongCredentialsErrorMessage(); + } + + return [ + 'token' => $this->tokenManager->create(new User($user)), + ]; + } + + /** + * @return array + */ + private function getWrongCredentialsErrorMessage(): array + { + return [ + 'message' => 'Wrong username or password', + 'token' => null, + ]; + } +} diff --git a/src/lib/Security/JWTUser.php b/src/lib/Security/JWTUser.php deleted file mode 100644 index a93fe62..0000000 --- a/src/lib/Security/JWTUser.php +++ /dev/null @@ -1,56 +0,0 @@ -wrappedUser = $wrappedUser; - $this->userIdentifier = $userIdentifier; - } - - public function getPassword(): ?string - { - return $this->wrappedUser->getPassword(); - } - - public function eraseCredentials(): void - { - $this->wrappedUser->eraseCredentials(); - } - - public function getRoles(): array - { - return $this->wrappedUser->getRoles(); - } - - public function getSalt(): ?string - { - return $this->wrappedUser->getSalt(); - } - - public function getUsername(): string - { - return $this->userIdentifier ?? $this->wrappedUser->getUsername(); - } - - public function getWrappedUser(): UserInterface - { - return $this->wrappedUser; - } -} diff --git a/src/lib/Security/NonAdminGraphQLRequestMatcher.php b/src/lib/Security/NonAdminGraphQLRequestMatcher.php index 1d88950..f90de2f 100644 --- a/src/lib/Security/NonAdminGraphQLRequestMatcher.php +++ b/src/lib/Security/NonAdminGraphQLRequestMatcher.php @@ -16,16 +16,19 @@ * Security request matcher that excludes admin+graphql requests. * Needed because the admin uses GraphQL without a JWT. */ -class NonAdminGraphQLRequestMatcher implements RequestMatcherInterface +final readonly class NonAdminGraphQLRequestMatcher implements RequestMatcherInterface { - /** @var string[][] */ - private $siteAccessGroups; - - public function __construct(array $siteAccessGroups) - { - $this->siteAccessGroups = $siteAccessGroups; + /** + * @param string[][] $siteAccessGroups + */ + public function __construct( + private array $siteAccessGroups + ) { } + /** + * @throws \Ibexa\AdminUi\Exception\InvalidArgumentException + */ public function matches(Request $request): bool { return