Skip to content

Commit 7a4379d

Browse files
authored
Fix Security 'this' variable on ExtendType fields (#801)
Fixes #653 Related to #792 When using #[Security] on a field declared in an #[ExtendType], the 'this' variable was incorrectly set to the resolver instance instead of the source object. This breaks authorization logic relying on the domain object. Fix: preserve $source when injectSource=true. Adds test coverage to ensure correct behavior.
1 parent 4a700d8 commit 7a4379d

4 files changed

Lines changed: 26 additions & 2 deletions

File tree

src/Middlewares/SecurityFieldMiddleware.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@ public function process(
8383
$injectSource = $queryFieldDescriptor->isInjectSource();
8484

8585
$queryFieldDescriptor = $queryFieldDescriptor->withResolver(function (object|null $source, ...$args) use ($originalResolver, $securityAnnotations, $resolver, $failWith, $parameters, $queryFieldDescriptor, $injectSource) {
86-
$variables = $this->getVariables($args, $parameters, $originalResolver->executionSource($source), $injectSource);
86+
$variables = $this->getVariables(
87+
$args,
88+
$parameters,
89+
$injectSource ? $source : $originalResolver->executionSource($source),
90+
$injectSource,
91+
);
8792

8893
foreach ($securityAnnotations as $annotation) {
8994
try {

src/Middlewares/SecurityInputFieldMiddleware.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ public function process(InputFieldDescriptor $inputFieldDescriptor, InputFieldHa
5151
$injectSource = $inputFieldDescriptor->isInjectSource();
5252

5353
$inputFieldDescriptor = $inputFieldDescriptor->withResolver(function (object|null $source, ...$args) use ($originalResolver, $securityAnnotations, $resolver, $parameters, $inputFieldDescriptor, $injectSource) {
54-
$variables = $this->getVariables($args, $parameters, $originalResolver->executionSource($source), $injectSource);
54+
$variables = $this->getVariables(
55+
$args,
56+
$parameters,
57+
$injectSource ? $source : $originalResolver->executionSource($source),
58+
$injectSource,
59+
);
5560

5661
foreach ($securityAnnotations as $annotation) {
5762
try {

tests/Fixtures/Integration/Types/ExtendedContactType.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,15 @@ public function extendedSecretName(Contact $contact): string|null
4848
{
4949
return $contact->getName();
5050
}
51+
52+
/**
53+
* Regression: in #[Security] on an #[ExtendType] field, `this` must be
54+
* the source object, not the resolver instance.
55+
*/
56+
#[Field]
57+
#[Security("user && this.getName() == 'Joe'", failWith: null)]
58+
public function sourceAwareSecretName(Contact $contact): string|null
59+
{
60+
return $contact->getName();
61+
}
5162
}

tests/Integration/EndToEndTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,7 @@ public function testEndToEndSecurityOnExtendTypeField(): void
13601360
contacts {
13611361
name
13621362
extendedSecretName
1363+
sourceAwareSecretName
13631364
}
13641365
}
13651366
';
@@ -1368,6 +1369,7 @@ public function testEndToEndSecurityOnExtendTypeField(): void
13681369
$data = $this->getSuccessResult($result);
13691370
$this->assertSame('Joe', $data['contacts'][0]['name']);
13701371
$this->assertNull($data['contacts'][0]['extendedSecretName']);
1372+
$this->assertNull($data['contacts'][0]['sourceAwareSecretName']);
13711373

13721374
// Logged-in user with bar=42 → the Security expression passes and the field returns the name.
13731375
$container = $this->createContainer([
@@ -1394,6 +1396,7 @@ public function getUser(): object|null
13941396
$result = GraphQL::executeQuery($schema, $queryString);
13951397
$data = $this->getSuccessResult($result);
13961398
$this->assertSame('Joe', $data['contacts'][0]['extendedSecretName']);
1399+
$this->assertSame('Joe', $data['contacts'][0]['sourceAwareSecretName']);
13971400
}
13981401

13991402
public function testEndToEndUnions(): void

0 commit comments

Comments
 (0)