diff --git a/.changes/nextrelease/nextrelease.json b/.changes/nextrelease/nextrelease.json new file mode 100644 index 0000000000..1fc3eca9a8 --- /dev/null +++ b/.changes/nextrelease/nextrelease.json @@ -0,0 +1,7 @@ + [ + { + "type": "bugfix", + "category": "EndpointV2", + "description": "Test fixes related to signing, particularly sigv4a." + } + ] \ No newline at end of file diff --git a/src/EndpointV2/EndpointV2SerializerTrait.php b/src/EndpointV2/EndpointV2SerializerTrait.php index 9f7919be7b..922ec189ec 100644 --- a/src/EndpointV2/EndpointV2SerializerTrait.php +++ b/src/EndpointV2/EndpointV2SerializerTrait.php @@ -173,19 +173,22 @@ private function applyAuthSchemeToCommand($endpoint, $command) private function selectAuthScheme($authSchemes) { - $validAuthSchemes = ['sigv4', 'sigv4a' ]; + $validAuthSchemes = ['sigv4', 'sigv4a', 'none', 'bearer']; + $invalidAuthSchemes = []; foreach($authSchemes as $authScheme) { if (in_array($authScheme['name'], $validAuthSchemes)) { return $this->normalizeAuthScheme($authScheme); } else { - $unsupportedScheme = $authScheme['name']; + $invalidAuthSchemes[] = "`{$authScheme['name']}`"; } } + $invalidAuthSchemesString = implode(', ', $invalidAuthSchemes); + $validAuthSchemesString = '`' . implode('`, `', $validAuthSchemes) . '`'; throw new \InvalidArgumentException( - "This operation requests {$unsupportedScheme} - . but the client only supports sigv4 and sigv4a" + "This operation requests {$invalidAuthSchemesString}" + . " auth schemes, but the client only supports {$validAuthSchemesString}." ); } @@ -200,17 +203,24 @@ private function normalizeAuthScheme($authScheme) if (isset($authScheme['disableDoubleEncoding']) && $authScheme['disableDoubleEncoding'] === true + && $authScheme['name'] !== 'sigv4a' ) { $normalizedAuthScheme['version'] = 's3v4'; - } else { + } elseif ($authScheme['name'] === 'none') { + $normalizedAuthScheme['version'] = 'anonymous'; + } + else { $normalizedAuthScheme['version'] = str_replace( 'sig', '', $authScheme['name'] ); } + $normalizedAuthScheme['name'] = isset($authScheme['signingName']) ? $authScheme['signingName'] : null; $normalizedAuthScheme['region'] = isset($authScheme['signingRegion']) ? $authScheme['signingRegion'] : null; + $normalizedAuthScheme['signingRegionSet'] = isset($authScheme['signingRegionSet']) ? + $authScheme['signingRegionSet'] : null; return $normalizedAuthScheme; } diff --git a/tests/EndpointV2/EndpointProviderV2Test.php b/tests/EndpointV2/EndpointProviderV2Test.php index 17270ce6df..078aaea5ef 100644 --- a/tests/EndpointV2/EndpointProviderV2Test.php +++ b/tests/EndpointV2/EndpointProviderV2Test.php @@ -255,6 +255,7 @@ public function testRulesetProtocolEndpointAndErrorCases($service, $clientArgs, $expectedAuthSchemes = $expectedEndpoint['properties']['authSchemes'][0]; if ((isset($expectedAuthSchemes['disableDoubleEncoding']) && $expectedAuthSchemes['disableDoubleEncoding'] === true) + && $expectedAuthSchemes['name'] !== 'sigv4a' ) { $expectedVersion = 's3v4'; } else { @@ -268,10 +269,17 @@ public function testRulesetProtocolEndpointAndErrorCases($service, $clientArgs, $cmd->getAuthSchemes()['name'], $expectedAuthSchemes['signingName'] ); - $this->assertEquals( - $cmd->getAuthSchemes()['region'], - $expectedAuthSchemes['signingRegion'] - ); + if (isset($cmd->getAuthSchemes()['region'])) { + $this->assertEquals( + $cmd->getAuthSchemes()['region'], + $expectedAuthSchemes['signingRegion'] + ); + } elseif (isset($cmd->getAuthSchemes['signingRegionSet'])) { + $this->assertEquals( + $cmd->getAuthSchemes()['region'], + $expectedAuthSchemes['signingRegionSet'] + ); + } } if (isset($expectedEndpoint['headers'])) { $expectedHeaders = $expectedEndpoint['headers']; diff --git a/tests/EndpointV2/EndpointV2SerializerTraitTest.php b/tests/EndpointV2/EndpointV2SerializerTraitTest.php index 5192336760..37e5f3747c 100644 --- a/tests/EndpointV2/EndpointV2SerializerTraitTest.php +++ b/tests/EndpointV2/EndpointV2SerializerTraitTest.php @@ -1,6 +1,8 @@ resolve(); $handler($command)->wait(); } + + /** + * Ensures SDK-level config options used for ruleset evaluation + * are not overridden by a collision with a command argument + */ + public function testThrowsExceptionForInvalidAuthScheme() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage( + 'This operation requests `sigvfoo`, `sigvbar`, `sigvbaz` auth schemes,' + . ' but the client only supports `sigv4`, `sigv4a`, `none`, `bearer`.' + ); + + $rulesetPath = __DIR__ . '/invalid-rules/invalid-scheme.json'; + $rulesetDefinition = json_decode(file_get_contents($rulesetPath), true); + $partitions = EndpointDefinitionProvider::getPartitions(); + + $clientArgs = [ + 'region' => 'us-east-1', + 'endpoint_provider' => new EndpointProviderV2($rulesetDefinition, $partitions) + ]; + + $client = $this->getTestClient('s3', $clientArgs); + $this->addMockResults($client, [[]]); + $command = $client->getCommand( + 'headBucket', + [ + 'Bucket' => 'foo', + ] + ); + $list = $client->getHandlerList(); + $handler = $list->resolve(); + $handler($command)->wait(); + } } \ No newline at end of file diff --git a/tests/EndpointV2/invalid-rules/invalid-scheme.json b/tests/EndpointV2/invalid-rules/invalid-scheme.json new file mode 100644 index 0000000000..cc6efa023e --- /dev/null +++ b/tests/EndpointV2/invalid-rules/invalid-scheme.json @@ -0,0 +1,54 @@ +{ + "parameters": { + "Region": { + "type": "string", + "builtIn": "AWS::Region", + "documentation": "The region to dispatch this request, eg. `us-east-1`." + } + }, + "rules": [ + { + "documentation": "Template the region into the URI when region is set", + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Region" + } + ] + } + ], + "endpoint": { + "url": "https://{Region}.amazonaws.com", + "properties": { + "authSchemes": [ + { + "name": "sigvfoo", + "signingName": "serviceName", + "signingRegion": "{Region}" + }, + { + "name": "sigvbar", + "signingName": "serviceName", + "signingRegion": "{Region}" + }, + { + "name": "sigvbaz", + "signingName": "serviceName", + "signingRegion": "{Region}" + } + ] + } + }, + "type": "endpoint" + }, + { + "documentation": "fallback when region is unset", + "conditions": [], + "error": "Region must be set to resolve a valid endpoint", + "type": "error" + } + ], + "version": "1.3" +} \ No newline at end of file