Skip to content

Commit

Permalink
fix: address PR feedback for accountId support
Browse files Browse the repository at this point in the history
In this change we add AccountId resolution for when AccountId is part of the rulesetParameters and accountIdEndpointMode is not disabled, in EndpointV2Middleware. If AccountId should be resolved then, we will resolve the credentialsProvider, which will resolve an identity from which we will extract the accountId, and if an accountId is not present in that resolved identity then, we will log a warning if accountIdEndpointMode is set to preferred or throw an exception if accountIdEndpointMode is required. Another part of this change is, that if we get up to the point of resolving the credentials provider then, we inject the resolved identity into $command['@context'] as the property 'resolved_identity'. We do this for trying to avoid having to resolve credentials more than once per request.
  • Loading branch information
yenfryherrerafeliz committed Feb 27, 2024
1 parent 319169a commit 1a7ed29
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 223 deletions.
66 changes: 0 additions & 66 deletions src/AccountIdLazyResolver.php

This file was deleted.

27 changes: 6 additions & 21 deletions src/AwsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public function __construct(array $args)
$this->api = $config['api'];
$this->signatureProvider = $config['signature_provider'];
$this->endpoint = new Uri($config['endpoint']);
$this->credentialProvider = new CredentialsLazyResolver($config['credentials']);
$this->credentialProvider = $config['credentials'];
$this->tokenProvider = $config['token'];
$this->region = isset($config['region']) ? $config['region'] : null;
$this->config = $config['config'];
Expand All @@ -249,8 +249,6 @@ public function __construct(array $args)
$this->addQueryCompatibleInputMiddleware($this->api);
}

$this->addForceCredentialsResolutionMiddleware();

if (isset($args['with_resolved'])) {
$args['with_resolved']($config);
}
Expand Down Expand Up @@ -376,21 +374,6 @@ private function parseClass()
];
}

private function addForceCredentialsResolutionMiddleware()
{
$middleware = function (callable $handler) {
return function (
CommandInterface $command
) use ($handler) {
$this->credentialProvider->forceResolutionOnce();

return $handler($command);
};
};

$this->handlerList->prependBuild($middleware, 'force-lazy-credentials-resolution');
}

private function addEndpointParameterMiddleware($args)
{
if (empty($args['disable_host_prefix_injection'])) {
Expand Down Expand Up @@ -545,7 +528,8 @@ private function addEndpointV2Middleware()
EndpointV2Middleware::wrap(
$this->endpointProvider,
$this->getApi(),
$endpointArgs
$endpointArgs,
$this->credentialProvider
),
'endpoint-resolution'
);
Expand Down Expand Up @@ -575,7 +559,7 @@ private function setClientContextParams($args)
/**
* Retrieves and sets default values used for endpoint resolution.
*/
private function setClientBuiltIns($args, $clientConfig)
private function setClientBuiltIns($args, $resolvedConfig)
{
$builtIns = [];
$config = $this->getConfig();
Expand All @@ -599,7 +583,8 @@ private function setClientBuiltIns($args, $clientConfig)
$builtIns['AWS::S3::ForcePathStyle'] = $config['use_path_style_endpoint'];
$builtIns['AWS::S3::DisableMultiRegionAccessPoints'] = $config['disable_multiregion_access_points'];
}
$builtIns['AWS::Auth::AccountId'] = new AccountIdLazyResolver($this->credentialProvider, $clientConfig['account_id_endpoint_mode']);
$builtIns['AWS::Auth::AccountId'] = null;
$builtIns['AWS::Auth::AccountIdEndpointMode'] = $resolvedConfig['account_id_endpoint_mode'];

$this->clientBuiltIns += $builtIns;
}
Expand Down
7 changes: 4 additions & 3 deletions src/ClientResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1054,14 +1054,15 @@ public static function _default_account_id_endpoint_mode($args)
'account_id_endpoint_mode',
'preferred',
'string',
['use_aws_shared_config_files' => true]
$args
);
}

public static function _apply_account_id_endpoint_mode($value, array &$args)
{
if (!in_array($value, ['disabled', 'required', 'preferred'])) {
throw new RuntimeException("valid values");
static $accountIdEndpointModes = ['disabled', 'required', 'preferred'];
if (!in_array($value, $accountIdEndpointModes)) {
throw new \RuntimeException("The value provided for the config account_id_endpoint_mode is invalid. Valid values are: " . implode(", ", $accountIdEndpointModes));
}

$args['account_id_endpoint_mode'] = $value;
Expand Down
97 changes: 0 additions & 97 deletions src/CredentialsLazyResolver.php

This file was deleted.

66 changes: 55 additions & 11 deletions src/EndpointV2/EndpointV2Middleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
use Aws\Api\Operation;
use Aws\Api\Service;
use Aws\CommandInterface;
use Aws\LazyResolver;
use Aws\Exception\AccountIdNotFoundException;
use Closure;
use GuzzleHttp\Promise\Create;
use GuzzleHttp\Promise\Promise;

/**
* Handles endpoint rule evaluation and endpoint resolution.
*
Expand Down Expand Up @@ -37,6 +37,8 @@ class EndpointV2Middleware

/** @var array */
private $clientArgs;
/** @var Closure */
private $credentialsProvider;

/**
* Create a middleware wrapper function
Expand All @@ -50,11 +52,12 @@ class EndpointV2Middleware
public static function wrap(
EndpointProviderV2 $endpointProvider,
Service $api,
array $args
array $args,
callable $credentialsProvider
) : Closure
{
return function (callable $handler) use ($endpointProvider, $api, $args) {
return new self($handler, $endpointProvider, $api, $args);
return function (callable $handler) use ($endpointProvider, $api, $args, $credentialsProvider) {
return new self($handler, $endpointProvider, $api, $args, $credentialsProvider);
};
}

Expand All @@ -68,13 +71,15 @@ public function __construct(
callable $nextHandler,
EndpointProviderV2 $endpointProvider,
Service $api,
array $args
array $args,
callable $credentialsProvider
)
{
$this->nextHandler = $nextHandler;
$this->endpointProvider = $endpointProvider;
$this->api = $api;
$this->clientArgs = $args;
$this->credentialsProvider = $credentialsProvider;
}

/**
Expand Down Expand Up @@ -112,6 +117,9 @@ public function __invoke(CommandInterface $command)
private function resolveArgs(array $commandArgs, Operation $operation) : array
{
$rulesetParams = $this->endpointProvider->getRuleset()->getParameters();

$this->resolveAccountIdArgument($commandArgs, $rulesetParams);

$endpointCommandArgs = $this->filterEndpointCommandArgs(
$rulesetParams,
$commandArgs
Expand All @@ -122,7 +130,6 @@ private function resolveArgs(array $commandArgs, Operation $operation) : array
$contextParams = $this->bindContextParams(
$commandArgs, $operation->getContextParams()
);
$this->resolveClientResolvableArguments();

return array_merge(
$this->clientArgs,
Expand Down Expand Up @@ -305,12 +312,49 @@ private function normalizeAuthScheme(array $authScheme) : array
return $normalizedAuthScheme;
}

private function resolveClientResolvableArguments()
/**
* This method tries to resolve an AccountId parameter from a resolved identity.
* We will just perform this operation if the parameter AccountId is part of the ruleset parameters and
* AccountIdEndpointMode is not disabled, otherwise, we will ignore it.
* We also are going to resolve identity from a supplied credentials provider,
* and we will inject the resolved identity into the $command['@context'] property, so it can be reused along the way.
*
* @param array $commandArgs
* @param array $rulesetParams
* @return void
*/
private function resolveAccountIdArgument(array &$commandArgs, array $rulesetParams)
{
foreach ($this->clientArgs as $key => $value) {
if ($value instanceof LazyResolver) {
$this->clientArgs[$key] = $value->resolve();
static $ACCOUNT_ID_PARAM = 'AccountId';
if (!in_array($ACCOUNT_ID_PARAM, array_keys($rulesetParams))) {
return;
}

$accountIdEndpointMode = $this->clientArgs['AccountIdEndpointMode'];
if ($accountIdEndpointMode === 'disabled') {
return;
}

$credentialsProviderFn = $this->credentialsProvider;
$identity = $credentialsProviderFn()->wait();
$commandArgs['@context']['resolved_identity'] = Create::promiseFor($identity);
if (empty($identity->getAccountId())) {
$messageFn = function ($mode) {
return "It is ${mode} to resolve an account id based on the 'account_id_endpoint_mode' configuration. \n- If you are using credentials from a shared ini file, please make sure you have configured the property aws_account_id. \n- If you are using credentials defined in environment variables please make sure you have set AWS_ACCOUNT_ID. \n- Otherwise, if you are supplying credentials as part of client constructor parameters, please make sure you have set the property account_id.\n If you prefer to not use account id endpoint resolution then, please make account_id_endpoint_mode to be disabled by either providing it explicitly in the client, defining a config property in your shared config file account_id_endpoint_mode, or by setting an environment variable called AWS_ACCOUNT_ID_ENDPOINT_MODE, and the value for any of those source should be 'disabled' if the desire is to disable this behavior.";
};
switch ($accountIdEndpointMode) {
case 'preferred':
trigger_error($messageFn($accountIdEndpointMode), E_USER_WARNING);
break;
case 'required':
throw new AccountIdNotFoundException($messageFn($accountIdEndpointMode));
default:
throw new \RuntimeException('account_id_endpoint_mode value not supported: '. $accountIdEndpointMode);
}

return;
}

$commandArgs[$ACCOUNT_ID_PARAM] = $identity->getAccountId();
}
}
Loading

0 comments on commit 1a7ed29

Please sign in to comment.