Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
518 changes: 261 additions & 257 deletions CHANGELOG.md

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion src/ClientResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class ClientResolver
__CLASS__,
'_resolve_from_env_ini'
];
private const ANONYMOUS_SIGNATURE = 'anonymous';
private const DPOP_SIGNATURE = 'dpop';

/** @var array Map of types to a corresponding function */
private static $typeMap = [
Expand Down Expand Up @@ -668,7 +670,10 @@ public static function _apply_credentials($value, array &$args)
$args['credentials'] = CredentialProvider::fromCredentials(
new Credentials('', '')
);
$args['config']['signature_version'] = 'anonymous';
if ($args['config']['signature_version'] !== self::DPOP_SIGNATURE) {
$args['config']['signature_version'] = self::ANONYMOUS_SIGNATURE;
}

$args['config']['configured_signature_version'] = true;
} elseif ($value instanceof CacheInterface) {
$args['credentials'] = CredentialProvider::defaultProvider($args);
Expand Down
126 changes: 88 additions & 38 deletions src/Credentials/CredentialProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@
*/
class CredentialProvider
{
const ENV_ARN = 'AWS_ROLE_ARN';
const ENV_KEY = 'AWS_ACCESS_KEY_ID';
const ENV_PROFILE = 'AWS_PROFILE';
const ENV_ROLE_SESSION_NAME = 'AWS_ROLE_SESSION_NAME';
const ENV_SECRET = 'AWS_SECRET_ACCESS_KEY';
const ENV_ACCOUNT_ID = 'AWS_ACCOUNT_ID';
const ENV_SESSION = 'AWS_SESSION_TOKEN';
const ENV_TOKEN_FILE = 'AWS_WEB_IDENTITY_TOKEN_FILE';
const ENV_SHARED_CREDENTIALS_FILE = 'AWS_SHARED_CREDENTIALS_FILE';
public const ENV_ARN = 'AWS_ROLE_ARN';
public const ENV_KEY = 'AWS_ACCESS_KEY_ID';
public const ENV_PROFILE = 'AWS_PROFILE';
public const ENV_ROLE_SESSION_NAME = 'AWS_ROLE_SESSION_NAME';
public const ENV_SECRET = 'AWS_SECRET_ACCESS_KEY';
public const ENV_ACCOUNT_ID = 'AWS_ACCOUNT_ID';
public const ENV_SESSION = 'AWS_SESSION_TOKEN';
public const ENV_TOKEN_FILE = 'AWS_WEB_IDENTITY_TOKEN_FILE';
public const ENV_SHARED_CREDENTIALS_FILE = 'AWS_SHARED_CREDENTIALS_FILE';
public const ENV_CONFIG_FILE = 'AWS_CONFIG_FILE';
public const ENV_REGION = 'AWS_REGION';
public const FALLBACK_REGION = 'us-east-1';
public const REFRESH_WINDOW = 60;
Expand Down Expand Up @@ -82,6 +83,7 @@ public static function defaultProvider(array $config = [])
$cacheable = [
'web_identity',
'sso',
'login',
'process_credentials',
'process_config',
'ecs',
Expand All @@ -94,24 +96,24 @@ public static function defaultProvider(array $config = [])
'env' => self::env(),
'web_identity' => self::assumeRoleWithWebIdentityCredentialProvider($config),
];
if (
!isset($config['use_aws_shared_config_files'])
if (!isset($config['use_aws_shared_config_files'])
|| $config['use_aws_shared_config_files'] !== false
) {
$defaultChain['sso'] = self::sso(
$profileName,
self::getHomeDir() . '/.aws/config',
self::getConfigFileName(),
$config
);
$defaultChain['login'] = self::login($profileName, $config);
$defaultChain['process_credentials'] = self::process();
$defaultChain['ini'] = self::ini(null, null, $config);
$defaultChain['process_config'] = self::process(
'profile ' . $profileName,
self::getHomeDir() . '/.aws/config'
self::getConfigFileName()
);
$defaultChain['ini_config'] = self::ini(
'profile '. $profileName,
self::getHomeDir() . '/.aws/config'
self::getConfigFileName()
);
}

Expand Down Expand Up @@ -339,11 +341,12 @@ public static function instanceProfile(array $config = [])
*
* @return callable
*/
public static function sso($ssoProfileName = 'default',
$filename = null,
$config = []
public static function sso(
$ssoProfileName = 'default',
$filename = null,
$config = []
) {
$filename = $filename ?: (self::getHomeDir() . '/.aws/config');
$filename = $filename ?? self::getConfigFileName();

return function () use ($ssoProfileName, $filename, $config) {
if (!@is_readable($filename)) {
Expand Down Expand Up @@ -489,17 +492,13 @@ public static function assumeRoleWithWebIdentityCredentialProvider(array $config
*/
public static function ini($profile = null, $filename = null, array $config = [])
{
$filename = self::getFileName($filename);
$filename = self::getCredentialsFileName($filename);
$profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default');

return function () use ($profile, $filename, $config) {
$preferStaticCredentials = isset($config['preferStaticCredentials'])
? $config['preferStaticCredentials']
: false;
$disableAssumeRole = isset($config['disableAssumeRole'])
? $config['disableAssumeRole']
: false;
$stsClient = isset($config['stsClient']) ? $config['stsClient'] : null;
$preferStaticCredentials = $config['preferStaticCredentials'] ?? false;
$disableAssumeRole = $config['disableAssumeRole'] ?? false;
$stsClient = $config['stsClient'] ?? null;

if (!@is_readable($filename)) {
return self::reject("Cannot read credentials from $filename");
Expand Down Expand Up @@ -583,7 +582,7 @@ public static function ini($profile = null, $filename = null, array $config = []
*/
public static function process($profile = null, $filename = null)
{
$filename = self::getFileName($filename);
$filename = self::getCredentialsFileName($filename);
$profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default');

return function () use ($profile, $filename) {
Expand Down Expand Up @@ -659,6 +658,41 @@ public static function process($profile = null, $filename = null)
};
}

/**
* Login credential provider for AWS local development using console credentials
*
* @param string|null $profileName profile containing your console login session information
* @param array $config region used for refresh requests.
* pass `'region' => <your_region>` to configure a region,
* otherwise, provider construction falls back to AWS_REGION,
* then the profile specified for `login`
*
* @return callable
*/
public static function login(
?string $profileName = null,
array $config = [],
): callable
{
$resolvedProfile = $profileName ?? getenv(self::ENV_PROFILE) ?: 'default';

return static function () use ($resolvedProfile, $config) {
try {
$provider = new LoginCredentialProvider(
$resolvedProfile,
$config['region'] ?? null
);
} catch (\Exception $e) {
return self::reject(
"Failed to initialize login credential provider for profile '{$resolvedProfile}': "
. $e->getMessage()
);
}

return $provider();
};
}

/**
* Assumes role for profile that includes role_arn
*
Expand All @@ -672,13 +706,11 @@ private static function loadRoleProfile(
$config = []
) {
$roleProfile = $profiles[$profileName];
$roleArn = isset($roleProfile['role_arn']) ? $roleProfile['role_arn'] : '';
$roleSessionName = isset($roleProfile['role_session_name'])
? $roleProfile['role_session_name']
: 'aws-sdk-php-' . round(microtime(true) * 1000);
$roleArn = $roleProfile['role_arn'] ?? '';
$roleSessionName = $roleProfile['role_session_name']
?? 'aws-sdk-php-' . round(microtime(true) * 1000);

if (
empty($roleProfile['source_profile'])
if (empty($roleProfile['source_profile'])
== empty($roleProfile['credential_source'])
) {
return self::reject("Either source_profile or credential_source must be set " .
Expand Down Expand Up @@ -748,7 +780,7 @@ private static function loadRoleProfile(
*
* @return null|string
*/
private static function getHomeDir()
public static function getHomeDir()
{
// On Linux/Unix-like systems, use the HOME environment variable
if ($homeDir = getenv('HOME')) {
Expand All @@ -765,15 +797,15 @@ private static function getHomeDir()
/**
* Gets profiles from specified $filename, or default ini files.
*/
private static function loadProfiles($filename)
public static function loadProfiles($filename)
{
$profileData = \Aws\parse_ini_file($filename, true, INI_SCANNER_RAW);

// If loading .aws/credentials, also load .aws/config when AWS_SDK_LOAD_NONDEFAULT_CONFIG is set
if ($filename === self::getHomeDir() . '/.aws/credentials'
&& getenv('AWS_SDK_LOAD_NONDEFAULT_CONFIG')
) {
$configFilename = self::getHomeDir() . '/.aws/config';
$configFilename = self::getConfigFileName();
$configProfileData = \Aws\parse_ini_file($configFilename, true, INI_SCANNER_RAW);
foreach ($configProfileData as $name => $profile) {
// standardize config profile names
Expand All @@ -790,7 +822,8 @@ private static function loadProfiles($filename)
/**
* Gets profiles from ~/.aws/credentials and ~/.aws/config ini files
*/
private static function loadDefaultProfiles() {
private static function loadDefaultProfiles()
{
$profiles = [];
$credFile = self::getHomeDir() . '/.aws/credentials';
$configFile = self::getHomeDir() . '/.aws/config';
Expand Down Expand Up @@ -861,15 +894,32 @@ private static function reject($msg)
}

/**
* Locates shared configuration file by first checking for AWS_CONFIG,
* then falling back to the default location. Returns the path of the
* resolved configuration file.
*
* @return string
*/
public static function getConfigFileName(): string
{
return getenv(self::ENV_CONFIG_FILE) ?: self::getHomeDir() . '/.aws/config';
}

/**
* Locates credentials file by first checking for AWS_SHARED_CREDENTIALS_FILE,
* then falling back to the default location. Returns the path of the
* resolved credentials file.
*
* @param $filename
* @return string
*/
private static function getFileName($filename)
public static function getCredentialsFileName($filename): string
{
if (!isset($filename)) {
$filename = getenv(self::ENV_SHARED_CREDENTIALS_FILE) ?:
(self::getHomeDir() . '/.aws/credentials');
}

return $filename;
}

Expand Down
1 change: 1 addition & 0 deletions src/Credentials/CredentialSources.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ final class CredentialSources
const PROFILE_SSO = 'profile_sso';
const PROFILE_SSO_LEGACY = 'profile_sso_legacy';
const PROFILE_PROCESS = 'profile_process';
const PROFILE_LOGIN = 'profile_login';
}
Loading
Loading