graphqlite icon indicating copy to clipboard operation
graphqlite copied to clipboard

Security annotation use results in array_combine() error

Open sanderlissenburg opened this issue 4 years ago • 6 comments
trafficstars

I'm trying to use a custom method for the security test as documented under "Accessing the current object".

https://graphqlite.thecodingmachine.io/docs/fine-grained-security#accessing-the-current-object

But this results in the following error.

array_combine(): Both parameters should have an equal number of elements

For example.

/**
 * @Type(class=LocationModel::class)
 */
final class LocationType
{
    /**
     * @Field
     * @Security("this.isAdmin(user)")
     * @param LocationModel $locationModel
     * @return string
     */
    public function name(LocationModel $locationModel): string
    {
        return $locationModel->name;
    }


    public function isAdmin(User $user): bool
    {
        return $user->getType() === 'admin';
    }
}
        #message: "array_combine(): Both parameters should have an equal number of elements"
        #code: 0
        #file: "/app/vendor/thecodingmachine/graphqlite/src/Middlewares/SecurityFieldMiddleware.php"
        #line: 132
        #severity: E_WARNING
        trace: {
          /app/vendor/thecodingmachine/graphqlite/src/Middlewares/SecurityFieldMiddleware.php:132 {
            Laminas\Stratigility\Middleware\ErrorHandler->Laminas\Stratigility\Middleware\{closure} …
            › $argsName = array_keys($parameters);
            › $argsByName = array_combine($argsName, $args);
            › Assert::isArray($argsByName);
          }
          Laminas\Stratigility\Middleware\ErrorHandler->Laminas\Stratigility\Middleware\{closure}() {}
          /app/vendor/thecodingmachine/graphqlite/src/Middlewares/SecurityFieldMiddleware.php:132 {
            TheCodingMachine\GraphQLite\Middlewares\SecurityFieldMiddleware->getVariables(array $args, array $parameters, ResolverInterface $callable): array …
            › $argsName = array_keys($parameters);
            › $argsByName = array_combine($argsName, $args);
            › Assert::isArray($argsByName);
            arguments: {
              $keys: []
              $values: array:1 [ …1]
            }
          }
          /app/vendor/thecodingmachine/graphqlite/src/Middlewares/SecurityFieldMiddleware.php:88 {
            TheCodingMachine\GraphQLite\Middlewares\SecurityFieldMiddleware->TheCodingMachine\GraphQLite\Middlewares\{closure} …
            › $queryFieldDescriptor->setResolver(function (...$args) use ($securityAnnotations, $resolver, $failWith, $parameters, $queryFieldDescriptor, $originalResolver) {
            ›     $variables = $this->getVariables($args, $parameters, $originalResolver);
            › 
            arguments: {
              $args: array:1 [ …1]
              $parameters: []
              $callable: TheCodingMachine\GraphQLite\Middlewares\ServiceResolver {#2401 …}
            }
          }
         ...

I'm using version 4.1.2.

sanderlissenburg avatar Apr 28 '21 16:04 sanderlissenburg

Please provide a stack-trace.

oojacoboo avatar Apr 28 '21 17:04 oojacoboo

Not sure how to get a decent track trace because it's formatted to a JSON result by the Graphql middleware. With some var_dumping and die() I got this. Hope it's enough. I have added it to the initial question/comment.

sanderlissenburg avatar Apr 28 '21 17:04 sanderlissenburg

@sanderlissenburg without digging into this bit of the code further, I'm not entirely certain here. Can you verify that you have an active User session/object available?

We don't use this User "session management stuff" with GraphQLite, as I've stated my opinion on this before, I'm not a fan of this library getting tangled up in the User logic of an application. I, personally, would never advise it's use. IMO, all of your User logic should be managed outside of this library. The @Security annotation is great though, just get your User object within that method, or via a service that method leverages. Parameter injecting is just a really bad pattern IMO.

oojacoboo avatar Apr 30 '21 18:04 oojacoboo

is_granted works, so I'm pretty sure the user object is available. But even when I don't inject any parameter in the method. I get this error. For example

final class Foo
{
    /**
     * @Field
     * @Security("this.foo()")
     * @param FooModel $fooModel
     * @return string
     */
    public function name(FooModel $fooModel): string
    {
        return $fooModel->bar;
    }

    public function foo(): bool
    {
        return false;
    }
}

sanderlissenburg avatar May 03 '21 08:05 sanderlissenburg

Same problem vendor/thecodingmachine/graphqlite/src/Middlewares/SecurityFieldMiddleware.php:132. Here array $parameters is empty, becouse of array_shift at vendor/thecodingmachine/graphqlite/src/FieldsBuilder.php:378, when injectSource class

vyaaki avatar Sep 03 '21 10:09 vyaaki

@vyaaki be great if you could submit a PR with tests.

oojacoboo avatar Sep 03 '21 10:09 oojacoboo