Skip to content

Commit

Permalink
enhancement: user agent 2.1
Browse files Browse the repository at this point in the history
This change provides:
- A builder class for appending metrics
- Default initialization of a metrics builder within command instantiation
- Wraps user agent logic into a single middleware class
- Adds middlewares into the different features from where metrics can be gather, to acomplish this purpose.
- Move the user agent middleware after the signing step in order to gather signature metrics.
- Add request compression metric gathering.
- Add specific testing for signatures.
- Add specific testing for request compression.
- Add specific testing for s3 encryption clients.
- Add credentials metric gathering logic.
- Add tests for credentials metrics.
- Make existent credentials tests to work with the new field `source`. For example, for tests around profile credentials the source property for credentials MUST be `profile`. The default value for this field is `static`.
- Use static mapping instead of multiple if/else-ifs.
- Remove the endpoint_id metric tracking since it was removed from the spec.
- Make method's name to be verb based.
- Remove the getMetricsBuilder from the CommandInterface.
- Add tests cases to cover credentials sets the correct source when resolved.
- Fix the sso, sso_legacy, and process metrics. They should be all a profile based metric.
  • Loading branch information
yenfryherrerafeliz committed Dec 13, 2024
1 parent 3b4fa21 commit 253930f
Show file tree
Hide file tree
Showing 37 changed files with 3,344 additions and 447 deletions.
45 changes: 35 additions & 10 deletions src/AwsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ public function __construct(array $args)
if (isset($args['with_resolved'])) {
$args['with_resolved']($config);
}
$this->addUserAgentMiddleware($config);
}

public function getHandlerList()
Expand Down Expand Up @@ -449,7 +450,7 @@ private function addSignatureMiddleware(array $args)
}

$resolver = static function (
CommandInterface $c
CommandInterface $command
) use (
$api,
$provider,
Expand All @@ -460,17 +461,17 @@ private function addSignatureMiddleware(array $args)
$signingRegionSet
) {
if (!$configuredSignatureVersion) {
if (!empty($c['@context']['signing_region'])) {
$region = $c['@context']['signing_region'];
if (!empty($command['@context']['signing_region'])) {
$region = $command['@context']['signing_region'];
}
if (!empty($c['@context']['signing_service'])) {
$name = $c['@context']['signing_service'];
if (!empty($command['@context']['signing_service'])) {
$name = $command['@context']['signing_service'];
}
if (!empty($c['@context']['signature_version'])) {
$signatureVersion = $c['@context']['signature_version'];
if (!empty($command['@context']['signature_version'])) {
$signatureVersion = $command['@context']['signature_version'];
}

$authType = $api->getOperation($c->getName())['authtype'];
$authType = $api->getOperation($command->getName())['authtype'];
switch ($authType){
case 'none':
$signatureVersion = 'anonymous';
Expand All @@ -485,15 +486,21 @@ private function addSignatureMiddleware(array $args)
}

if ($signatureVersion === 'v4a') {
$commandSigningRegionSet = !empty($c['@context']['signing_region_set'])
? implode(', ', $c['@context']['signing_region_set'])
$commandSigningRegionSet = !empty($command['@context']['signing_region_set'])
? implode(', ', $command['@context']['signing_region_set'])
: null;

$region = $signingRegionSet
?? $commandSigningRegionSet
?? $region;
}

// Capture signature metric
$command->getMetricsBuilder()->identifyMetricByValueAndAppend(
'signature',
$signatureVersion
);

return SignatureProvider::resolve($provider, $signatureVersion, $name, $region);
};
$this->handlerList->appendSign(
Expand Down Expand Up @@ -611,6 +618,24 @@ private function addEndpointV2Middleware()
);
}

/**
* Appends the user agent middleware.
* This middleware MUST be appended after the
* signature middleware `addSignatureMiddleware`,
* so that metrics around signatures are properly
* captured.
*
* @param $args
* @return void
*/
private function addUserAgentMiddleware($args)
{
$this->getHandlerList()->appendSign(
UserAgentMiddleware::wrap($args),
'user-agent'
);
}

/**
* Retrieves client context param definition from service model,
* creates mapping of client context param names with client-provided
Expand Down
98 changes: 16 additions & 82 deletions src/ClientResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -991,68 +991,14 @@ public static function _default_app_id(array $args)
);
}

public static function _apply_user_agent($inputUserAgent, array &$args, HandlerList $list)
public static function _apply_user_agent(
$inputUserAgent,
array &$args,
HandlerList $list
): void
{
// Add SDK version
$userAgent = ['aws-sdk-php/' . Sdk::VERSION];

// User Agent Metadata
$userAgent[] = 'ua/2.0';

// If on HHVM add the HHVM version
if (defined('HHVM_VERSION')) {
$userAgent []= 'HHVM/' . HHVM_VERSION;
}

// Add OS version
$disabledFunctions = explode(',', ini_get('disable_functions'));
if (function_exists('php_uname')
&& !in_array('php_uname', $disabledFunctions, true)
) {
$osName = "OS/" . php_uname('s') . '#' . php_uname('r');
if (!empty($osName)) {
$userAgent []= $osName;
}
}

// Add the language version
$userAgent []= 'lang/php#' . phpversion();

// Add exec environment if present
if ($executionEnvironment = getenv('AWS_EXECUTION_ENV')) {
$userAgent []= $executionEnvironment;
}

// Add endpoint discovery if set
if (isset($args['endpoint_discovery'])) {
if (($args['endpoint_discovery'] instanceof \Aws\EndpointDiscovery\Configuration
&& $args['endpoint_discovery']->isEnabled())
) {
$userAgent []= 'cfg/endpoint-discovery';
} elseif (is_array($args['endpoint_discovery'])
&& isset($args['endpoint_discovery']['enabled'])
&& $args['endpoint_discovery']['enabled']
) {
$userAgent []= 'cfg/endpoint-discovery';
}
}

// Add retry mode if set
if (isset($args['retries'])) {
if ($args['retries'] instanceof \Aws\Retry\Configuration) {
$userAgent []= 'cfg/retry-mode#' . $args["retries"]->getMode();
} elseif (is_array($args['retries'])
&& isset($args["retries"]["mode"])
) {
$userAgent []= 'cfg/retry-mode#' . $args["retries"]["mode"];
}
}

// AppID Metadata
if (!empty($args['app_id'])) {
$userAgent[] = 'app/' . $args['app_id'];
}

$userAgent = [];
// Add the input to the end
if ($inputUserAgent){
if (!is_array($inputUserAgent)) {
Expand All @@ -1064,29 +1010,17 @@ public static function _apply_user_agent($inputUserAgent, array &$args, HandlerL

$args['ua_append'] = $userAgent;

$list->appendBuild(static function (callable $handler) use ($userAgent) {
return function (
CommandInterface $command,
RequestInterface $request
) use ($handler, $userAgent) {
return $handler(
$command,
$request->withHeader(
'X-Amz-User-Agent',
implode(' ', array_merge(
$userAgent,
$request->getHeader('X-Amz-User-Agent')
))
)->withHeader(
'User-Agent',
implode(' ', array_merge(
$userAgent,
$request->getHeader('User-Agent')
))
)
$list->appendBuild(
Middleware::mapRequest(function (RequestInterface $request) use ($userAgent) {
return $request->withHeader(
'X-Amz-User-Agent',
implode(' ', array_merge(
$userAgent,
$request->getHeader('X-Amz-User-Agent')
))
);
};
});
})
);
}

public static function _apply_endpoint($value, array &$args, HandlerList $list)
Expand Down
25 changes: 23 additions & 2 deletions src/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ class Command implements CommandInterface
/** @var HandlerList */
private $handlerList;

/** @var Array */
/** @var array */
private $authSchemes;

/** @var MetricsBuilder */
private $metricsBuilder;

/**
* Accepts an associative array of command options, including:
*
Expand All @@ -26,7 +29,12 @@ class Command implements CommandInterface
* @param array $args Arguments to pass to the command
* @param HandlerList $list Handler list
*/
public function __construct($name, array $args = [], ?HandlerList $list = null)
public function __construct(
$name,
array $args = [],
?HandlerList $list = null,
?MetricsBuilder $metricsBuilder = null
)
{
$this->name = $name;
$this->data = $args;
Expand All @@ -38,6 +46,7 @@ public function __construct($name, array $args = [], ?HandlerList $list = null)
if (!isset($this->data['@context'])) {
$this->data['@context'] = [];
}
$this->metricsBuilder = $metricsBuilder ?: new MetricsBuilder();
}

public function __clone()
Expand Down Expand Up @@ -110,4 +119,16 @@ public function get($name)
{
return $this[$name];
}

/**
* Returns the metrics builder instance tied up to this command.
*
* @internal
*
* @return MetricsBuilder
*/
public function getMetricsBuilder(): MetricsBuilder
{
return $this->metricsBuilder;
}
}
5 changes: 4 additions & 1 deletion src/Credentials/AssumeRoleCredentialProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ public function __invoke()
$client = $this->client;
return $client->assumeRoleAsync($this->assumeRoleParams)
->then(function (Result $result) {
return $this->client->createCredentials($result);
return $this->client->createCredentials(
$result,
CredentialSources::STS_ASSUME_ROLE
);
})->otherwise(function (\RuntimeException $exception) {
throw new CredentialsException(
"Error in retrieving assume role credentials.",
Expand Down
24 changes: 14 additions & 10 deletions src/Credentials/AssumeRoleWithWebIdentityCredentialProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ class AssumeRoleWithWebIdentityCredentialProvider

/** @var integer */
private $tokenFileReadAttempts;
/** @var string */
private $source;

/**
* The constructor attempts to load config from environment variables.
* If not set, the following config options are used:
* - WebIdentityTokenFile: full path of token filename
* - RoleArn: arn of role to be assumed
* - SessionName: (optional) set by SDK if not provided
* - source: To identify if the provider was sourced by a profile or
* from environment definition. Default will be `sts_web_id_token`.
*
* @param array $config Configuration options
* @throws \InvalidArgumentException
Expand All @@ -66,15 +70,9 @@ public function __construct(array $config = [])
$this->retries = (int) getenv(self::ENV_RETRIES) ?: (isset($config['retries']) ? $config['retries'] : 3);
$this->authenticationAttempts = 0;
$this->tokenFileReadAttempts = 0;

$this->session = isset($config['SessionName'])
? $config['SessionName']
: 'aws-sdk-php-' . round(microtime(true) * 1000);

$region = isset($config['region'])
? $config['region']
: 'us-east-1';

$this->session = $config['SessionName']
?? 'aws-sdk-php-' . round(microtime(true) * 1000);
$region = $config['region'] ?? 'us-east-1';
if (isset($config['client'])) {
$this->client = $config['client'];
} else {
Expand All @@ -84,6 +82,9 @@ public function __construct(array $config = [])
'version' => 'latest'
]);
}

$this->source = $config['source']
?? CredentialSources::STS_WEB_ID_TOKEN;
}

/**
Expand Down Expand Up @@ -160,7 +161,10 @@ public function __invoke()
$this->authenticationAttempts++;
}

yield $this->client->createCredentials($result);
yield $this->client->createCredentials(
$result,
$this->source
);
});
}
}
Loading

0 comments on commit 253930f

Please sign in to comment.