From f03b83f2e8a081d5d652d709b4cb963fbb660b17 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 10:58:04 +0100 Subject: [PATCH 01/26] Change the contract on credential to return a single field --- lib/Paws/Credential.pm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Paws/Credential.pm b/lib/Paws/Credential.pm index 25e5cb26a5..0804d72025 100644 --- a/lib/Paws/Credential.pm +++ b/lib/Paws/Credential.pm @@ -1,13 +1,11 @@ package Paws::Credential; use Moose::Role; - requires 'access_key'; - requires 'secret_key'; - requires 'session_token'; + requires 'credentials'; sub are_set { my $self = shift; - return (defined $self->access_key && defined $self->secret_key); + return (defined $self->credentials); } no Moose; From dedba066b6670cacf4980a3b4b6ab84ff36ea0f8 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 10:58:42 +0100 Subject: [PATCH 02/26] None returns undef --- lib/Paws/Credential/None.pm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/Paws/Credential/None.pm b/lib/Paws/Credential/None.pm index 62b42489a1..a0fb46b77a 100644 --- a/lib/Paws/Credential/None.pm +++ b/lib/Paws/Credential/None.pm @@ -2,12 +2,7 @@ package Paws::Credential::None; use Moose; with 'Paws::Credential'; - sub access_key { q{} } - - sub secret_key { q{} } - - sub session_token { q{} } + sub credentials { return undef; } no Moose; - 1; From 1e89e28e6e45374891fdacf50a61dcb52a2dcae2 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 10:59:46 +0100 Subject: [PATCH 03/26] Environment credentials returns atomically --- lib/Paws/Credential/Environment.pm | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/Paws/Credential/Environment.pm b/lib/Paws/Credential/Environment.pm index 23e01e5917..c956f7ba18 100644 --- a/lib/Paws/Credential/Environment.pm +++ b/lib/Paws/Credential/Environment.pm @@ -1,11 +1,25 @@ package Paws::Credential::Environment; use Moose; + use Paws::Credential::Explicit; + with 'Paws::Credential'; - has access_key => (is => 'ro', default => sub { $ENV{AWS_ACCESS_KEY} || $ENV{AWS_ACCESS_KEY_ID} }); - has secret_key => (is => 'ro', default => sub { $ENV{AWS_SECRET_KEY} || $ENV{AWS_SECRET_ACCESS_KEY} }); - has session_token => (is => 'ro', default => sub { $ENV{AWS_SESSION_TOKEN} }); + sub credentials { + my $self = shift; - with 'Paws::Credential'; + my $access_key = $ENV{AWS_ACCESS_KEY} || $ENV{AWS_ACCESS_KEY_ID}; + my $secret_key = $ENV{AWS_SECRET_KEY} || $ENV{AWS_SECRET_ACCESS_KEY}; + my $session_token = $ENV{AWS_SESSION_TOKEN}; + + if (!$access_key || !$secret_key) { + return undef; + } + + return Paws::Credential::Explicit->new( + access_key => $access_key, + secret_key => $secret_key, + session_token => $session_token, + ); + } no Moose; 1; From b271239f456d821fe84c2e7b6a3eca3f97ceb3b7 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:02:16 +0100 Subject: [PATCH 04/26] Explicit returns itself from credential resolution --- lib/Paws/Credential/Explicit.pm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Paws/Credential/Explicit.pm b/lib/Paws/Credential/Explicit.pm index 5a6d1991c5..9cfaa05269 100644 --- a/lib/Paws/Credential/Explicit.pm +++ b/lib/Paws/Credential/Explicit.pm @@ -1,11 +1,16 @@ package Paws::Credential::Explicit; use Moose; + with 'Paws::Credential'; has access_key => (is => 'ro', isa => 'Str', required => 1); has secret_key => (is => 'ro', isa => 'Str', required => 1); has session_token => (is => 'ro', isa => 'Str'); - with 'Paws::Credential'; + sub credentials { + my $self = shift; + + return $self; + } no Moose; 1; From 98669bfabd98b6064d3a9910a2fac85572699c17 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:05:21 +0100 Subject: [PATCH 05/26] Implement AssumeRole atomically --- lib/Paws/Credential/AssumeRole.pm | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/lib/Paws/Credential/AssumeRole.pm b/lib/Paws/Credential/AssumeRole.pm index 3b6356381c..1c791c7fc3 100644 --- a/lib/Paws/Credential/AssumeRole.pm +++ b/lib/Paws/Credential/AssumeRole.pm @@ -1,6 +1,7 @@ package Paws::Credential::AssumeRole; use Moose; use DateTime::Format::ISO8601; + use Paws::Credential::Explicit; with 'Paws::Credential'; has expiration => ( @@ -10,24 +11,12 @@ package Paws::Credential::AssumeRole; default => sub { 0 } ); - has actual_creds => (is => 'rw'); + has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - sub access_key { + sub credentials { my $self = shift; $self->_refresh; - $self->actual_creds->AccessKeyId; - } - - sub secret_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->SecretAccessKey; - } - - sub session_token { - my $self = shift; - $self->_refresh; - $self->actual_creds->SessionToken; + return $self->actual_creds; } has sts_region => (is => 'ro', isa => 'Str|Undef', default => sub { undef }); @@ -57,7 +46,11 @@ package Paws::Credential::AssumeRole; (defined $self->Policy) ? (Policy => $self->Policy) : (), ); - my $creds = $self->actual_creds($result->Credentials); + $self->actual_creds(Paws::Credential::Explicit->new( + access_key => $result->Credentials->AccessKeyId, + secret_key => $result->Credentials->SecretAccessKey, + session_token => $result->Credentials->SessionToken, + )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($result->Credentials->Expiration)->epoch); } From 7278643fd7145761d42f60221b5adc3bf149e8d7 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:06:11 +0100 Subject: [PATCH 06/26] Implement AssumeRoleWithSAML atomically --- lib/Paws/Credential/AssumeRoleWithSAML.pm | 27 ++++++++--------------- 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/Paws/Credential/AssumeRoleWithSAML.pm b/lib/Paws/Credential/AssumeRoleWithSAML.pm index 8a2d433241..3842787381 100644 --- a/lib/Paws/Credential/AssumeRoleWithSAML.pm +++ b/lib/Paws/Credential/AssumeRoleWithSAML.pm @@ -2,7 +2,7 @@ package Paws::Credential::AssumeRoleWithSAML; use Moose; use DateTime::Format::ISO8601; use Paws::Credential::None; - + use Paws::Credential::Explicit; with 'Paws::Credential'; has expiration => ( @@ -12,24 +12,12 @@ package Paws::Credential::AssumeRoleWithSAML; default => sub { 0 } ); - has actual_creds => (is => 'rw'); - - sub access_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->AccessKeyId; - } - - sub secret_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->SecretAccessKey; - } + has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - sub session_token { + sub credentials { my $self = shift; $self->_refresh; - $self->actual_creds->SessionToken; + return $self->actual_creds; } has sts_region => (is => 'ro', isa => 'Str|Undef', default => sub { undef }); @@ -59,8 +47,11 @@ package Paws::Credential::AssumeRoleWithSAML; (defined $self->Policy) ? (Policy => $self->Policy) : (), ); - my $creds = $self->actual_creds($result->Credentials); - + $self->actual_creds(Paws::Credential::Explicit->new( + access_key => $result->Credentials->AccessKeyId, + secret_key => $result->Credentials->SecretAccessKey, + session_token => $result->Credentials->SessionToken, + )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($result->Credentials->Expiration)->epoch); } From bae45b0a9aa0c817a3ebf8569bcc63441716fa9b Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:13:59 +0100 Subject: [PATCH 07/26] Make CredProcess atomic --- lib/Paws/Credential/CredProcess.pm | 124 +++++------------------------ 1 file changed, 20 insertions(+), 104 deletions(-) diff --git a/lib/Paws/Credential/CredProcess.pm b/lib/Paws/Credential/CredProcess.pm index b929be5fef..dfa0a876b7 100644 --- a/lib/Paws/Credential/CredProcess.pm +++ b/lib/Paws/Credential/CredProcess.pm @@ -3,6 +3,9 @@ package Paws::Credential::CredProcess; use JSON::MaybeXS qw/decode_json/; use Paws::Exception; use DateTime::Format::ISO8601; + use Paws::Credential::Explicit; + + with 'Paws::Credential'; has credential_process => (is => 'ro', isa => 'Str', required => 1); @@ -13,16 +16,20 @@ package Paws::Credential::CredProcess; default => sub { 0 } ); - has actual_creds => ( - is => 'ro', - isa => 'HashRef', - builder => '_build_actual_creds', - clearer => '_clear_actual_creds', - lazy => 1 - ); + has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + + sub credentials { + my $self = shift; + $self->_refresh; + return $self->actual_creds; + } - sub _build_actual_creds { + sub _refresh { my $self = shift; + + return if not defined $self->expiration; + return if $self->expiration >= time; + my $creds; my $rc; { @@ -44,103 +51,12 @@ package Paws::Credential::CredProcess; $self->expiration(undef); } - return $creds; + $self->actual_creds(Paws::Credential::Explicit->new( + access_key => $creds->{ AccessKeyId }, + secret_key => $creds->{ SecretAccessKey }, + session_token => $creds->{ SessionToken }, + )); } - sub access_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->{ AccessKeyId }; - } - - sub secret_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->{ SecretAccessKey } - } - - sub session_token { - my $self = shift; - $self->_refresh; - $self->actual_creds->{ SessionToken }; - } - - sub _refresh { - my $self = shift; - - return if not defined $self->expiration; - return if $self->expiration >= time; - $self->_clear_actual_creds; - } - - with 'Paws::Credential'; - no Moose; 1; -### main pod documentation begin ### - -=encoding UTF-8 - -=head1 NAME - -Paws::Credential::File - -=head1 SYNOPSIS - - use Paws::Credential::File; - - my $paws = Paws->new(config => { - credentials => Paws::Credential::File->new( - profile => 'profile1', - credentials_file => '/etc/aws_system_credentials', - ) - }); - # will open /etc/aws_system_credentials - - - my $paws = Paws->new(config => { - credentials => Paws::Credential::File->new( - profile => 'profile1', - file_name => 'my_creds', - ) - }); - # will open $HOME/.aws/my_creds - - my $paws = Paws->new(config => { - credentials => Paws::Credential::File->new( - profile => 'profile1', - dir => '/etc/', - ) - }); - # will open /etc/credentials - - -=head1 DESCRIPTION - -The File credential provider is to read credentials from AWS SDK config files - -=head2 profile: Str - -The section in the ini file where credentials will be looked up: - -Defaults to the environment variable C, and if that is not defined, to "default" - -=head2 credentials_file: Str - -The path of the ini file to open - -Defaults to the path + file_name (C<$HOME/.aws/credentials> by default) if the environment variable AWS_CONFIG_FILE doesn't exist - -=head2 path: Str - -Path to the ini file - -Defaults to C<$HOME/.aws> - -=head2 file_name: Str - -Name of the ini file - -Defaults to C - -=cut From 8b0edbe0bc1e48648a6f94094e0e0fe83e5853cd Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:15:49 +0100 Subject: [PATCH 08/26] Make ECSContainerProfile atomic --- lib/Paws/Credential/ECSContainerProfile.pm | 33 +++++++++------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/Paws/Credential/ECSContainerProfile.pm b/lib/Paws/Credential/ECSContainerProfile.pm index c161dc5591..28ce1a23ff 100644 --- a/lib/Paws/Credential/ECSContainerProfile.pm +++ b/lib/Paws/Credential/ECSContainerProfile.pm @@ -3,6 +3,7 @@ package Paws::Credential::ECSContainerProfile; use Moose; use DateTime::Format::ISO8601; use URI; + use Paws::Credential::Explicit; with 'Paws::Credential'; has container_local_uri => ( @@ -47,7 +48,13 @@ package Paws::Credential::ECSContainerProfile; default => sub { 0 } ); - has actual_creds => (is => 'rw', default => sub { {} }); + has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + + sub credentials { + my $self = shift; + $self->_refresh; + return $self->actual_creds; + } around are_set => sub { my ($orig, $self) = @_; @@ -55,24 +62,6 @@ package Paws::Credential::ECSContainerProfile; return $self->$orig; }; - sub access_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->{AccessKeyId}; - } - - sub secret_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->{SecretAccessKey}; - } - - sub session_token { - my $self = shift; - $self->_refresh; - $self->actual_creds->{Token}; - } - #TODO: Raise exceptions if HTTP get didn't return success sub _refresh { my $self = shift; @@ -89,7 +78,11 @@ package Paws::Credential::ECSContainerProfile; my $json = eval { decode_json($r->{content}) }; if ($@) { die "Error in JSON from metadata URL" } - $self->actual_creds($json); + $self->actual_creds(Paws::Credential::Explicit->new( + access_key => $json->{AccessKeyId}, + secret_key => $json->{SecretAccessKey}, + session_token => $json->{Token}, + )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($json->{Expiration})->epoch); } From a7c3dbf9ffdd5124aced4b1d0fd603c55c608ae7 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:19:50 +0100 Subject: [PATCH 09/26] Make file atomic --- lib/Paws/Credential/File.pm | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/Paws/Credential/File.pm b/lib/Paws/Credential/File.pm index 70cb720847..370f616bca 100644 --- a/lib/Paws/Credential/File.pm +++ b/lib/Paws/Credential/File.pm @@ -5,6 +5,8 @@ package Paws::Credential::File; use JSON::MaybeXS qw/decode_json/; use Paws::Exception; use Paws::Credential::CredProcess; + use Paws::Credential::Explicit; + with 'Paws::Credential'; has profile => (is => 'ro', default => sub { $ENV{ AWS_DEFAULT_PROFILE } or 'default' }); @@ -30,43 +32,41 @@ package Paws::Credential::File; return $ini; }); - has _profile => (is => 'ro', isa => 'HashRef', lazy => 1, default => sub { + has _profile => (is => 'ro', isa => 'Paws::Credential::Explicit|Undef', lazy => 1, default => sub { my $self = shift; + my $profile = $self->profile; - return $self->_ini_contents->{ $profile } || {}; - }); + my $profile_contents = $self->_ini_contents->{ $profile }; + return undef if (not defined $profile_contents); - has credential_process => (is => 'ro', lazy => 1, default => sub { - my $self = shift; - return undef if (not defined $self->_profile->{ credential_process }); - return Paws::Credential::CredProcess->new( - credential_process => $self->_profile->{ credential_process }, + return Paws::Credential::Explicit->new( + access_key => $profile_contents->{ aws_access_key_id }, + secret_key => $profile_contents->{ aws_secret_access_key }, + session_token => $profile_contents->{ aws_session_token }, ); }); - sub access_key { + has credential_process => (is => 'ro', isa => 'Paws::Credential::CredProcess|Undef', lazy => 1, default => sub { my $self = shift; - return $self->credential_process->access_key if (defined $self->credential_process); - return $self->_profile->{ aws_access_key_id }; - } - - sub secret_key { - my $self = shift; + my $process = $self->_profile->{ credential_process }; + return undef if (not defined $process); - return $self->credential_process->secret_key if (defined $self->credential_process); - return $self->_profile->{ aws_secret_access_key }; - } + return Paws::Credential::CredProcess->new( + credential_process => $process, + ); + }); - sub session_token { + sub credentials { my $self = shift; - - return $self->credential_process->session_token if (defined $self->credential_process); - return $self->_profile->{ aws_session_token }; + + if (defined $self->credential_process) { + return $self->credential_process->credentials; + } else { + return $self->_profile; + } } - with 'Paws::Credential'; - no Moose; 1; ### main pod documentation begin ### From 0e8dd755b1cb926823b478784193de89c0bc9e02 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:20:38 +0100 Subject: [PATCH 10/26] Make InstanceProfile atomic --- lib/Paws/Credential/InstanceProfile.pm | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/lib/Paws/Credential/InstanceProfile.pm b/lib/Paws/Credential/InstanceProfile.pm index 1a4f6c8854..506596b11a 100644 --- a/lib/Paws/Credential/InstanceProfile.pm +++ b/lib/Paws/Credential/InstanceProfile.pm @@ -2,6 +2,7 @@ package Paws::Credential::InstanceProfile; use JSON::MaybeXS; use Moose; use DateTime::Format::ISO8601; + use Paws::Credential::Explicit; with 'Paws::Credential'; has metadata_url => ( @@ -31,24 +32,12 @@ package Paws::Credential::InstanceProfile; default => sub { 0 } ); - has actual_creds => (is => 'rw', default => sub { {} }); + has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - sub access_key { + sub credentials { my $self = shift; $self->_refresh; - $self->actual_creds->{AccessKeyId}; - } - - sub secret_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->{SecretAccessKey}; - } - - sub session_token { - my $self = shift; - $self->_refresh; - $self->actual_creds->{Token}; + return $self->actual_creds; } #TODO: Raise exceptions if HTTP get didn't return success @@ -68,7 +57,11 @@ package Paws::Credential::InstanceProfile; my $json = eval { decode_json($r->{content}) }; if ($@) { die "Error in JSON from metadata URL" } - $self->actual_creds($json); + $self->actual_creds(Paws::Credential::Explicit->new( + access_key => $json->{AccessKeyId}, + secret_key => $json->{SecretAccessKey}, + session_token => $json->{Token}, + )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($json->{Expiration})->epoch); } From c9b8e2afaa0f283f8c0013de6660fae1cc08aeda Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:21:22 +0100 Subject: [PATCH 11/26] Make InstanceProfileV2 atomic --- lib/Paws/Credential/InstanceProfileV2.pm | 25 +++++++++--------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/lib/Paws/Credential/InstanceProfileV2.pm b/lib/Paws/Credential/InstanceProfileV2.pm index de9a455753..02a002d426 100644 --- a/lib/Paws/Credential/InstanceProfileV2.pm +++ b/lib/Paws/Credential/InstanceProfileV2.pm @@ -2,6 +2,7 @@ package Paws::Credential::InstanceProfileV2; use JSON::MaybeXS; use Moose; use DateTime::Format::ISO8601; + use Paws::Credential::Explicit; with 'Paws::Credential'; has metadata_url => ( @@ -37,24 +38,12 @@ package Paws::Credential::InstanceProfileV2; default => sub { 0 } ); - has actual_creds => (is => 'rw', default => sub { {} }); + has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - sub access_key { + sub credentials { my $self = shift; $self->_refresh; - $self->actual_creds->{AccessKeyId}; - } - - sub secret_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->{SecretAccessKey}; - } - - sub session_token { - my $self = shift; - $self->_refresh; - $self->actual_creds->{Token}; + return $self->actual_creds; } #TODO: Raise exceptions if HTTP get didn't return success @@ -81,7 +70,11 @@ package Paws::Credential::InstanceProfileV2; my $json = eval { decode_json($r->{content}) }; if ($@) { die "Error in JSON from metadata URL" } - $self->actual_creds($json); + $self->actual_creds(Paws::Credential::Explicit->new( + access_key => $json->{AccessKeyId}, + secret_key => $json->{SecretAccessKey}, + session_token => $json->{Token}, + )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($json->{Expiration})->epoch); } From f8a313869a96f4a2d0dc38e68637bc407b82e1ef Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:23:06 +0100 Subject: [PATCH 12/26] Make provider chain atomic --- lib/Paws/Credential/ProviderChain.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Paws/Credential/ProviderChain.pm b/lib/Paws/Credential/ProviderChain.pm index c8d074c347..d9249807dd 100644 --- a/lib/Paws/Credential/ProviderChain.pm +++ b/lib/Paws/Credential/ProviderChain.pm @@ -1,6 +1,8 @@ package Paws::Credential::ProviderChain; use Moose; + with 'Paws::Credential'; + has providers => ( is => 'ro', isa => 'ArrayRef[Str]', @@ -17,7 +19,7 @@ package Paws::Credential::ProviderChain; has selected_provider => ( is => 'rw', does => 'Paws::Credential', - handles => [ 'access_key', 'secret_key', 'session_token' ], + handles => [ 'credentials' ], ); sub BUILD { @@ -33,8 +35,6 @@ package Paws::Credential::ProviderChain; # Tried all the providers... none got creds die "Can't find any credentials. I tried with " . (join ',', @{ $self->providers }) } - - with 'Paws::Credential'; 1; ### main pod documentation begin ### From 431c387810bb80c79521ec1a9ee2b6ce30494026 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Mon, 28 Apr 2025 11:23:15 +0100 Subject: [PATCH 13/26] Make STS atomic --- lib/Paws/Credential/STS.pm | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/lib/Paws/Credential/STS.pm b/lib/Paws/Credential/STS.pm index 608fa6a056..e01a6eee2e 100644 --- a/lib/Paws/Credential/STS.pm +++ b/lib/Paws/Credential/STS.pm @@ -1,6 +1,7 @@ package Paws::Credential::STS; use Moose; use DateTime::Format::ISO8601; + use Paws::Credential::Explicit; with 'Paws::Credential'; has expiration => ( @@ -10,24 +11,12 @@ package Paws::Credential::STS; default => sub { 0 } ); - has actual_creds => (is => 'rw'); + has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - sub access_key { + sub credentials { my $self = shift; $self->_refresh; - $self->actual_creds->AccessKeyId; - } - - sub secret_key { - my $self = shift; - $self->_refresh; - $self->actual_creds->SecretAccessKey; - } - - sub session_token { - my $self = shift; - $self->_refresh; - $self->actual_creds->SessionToken; + return $self->actual_creds; } has sts_region => (is => 'ro', isa => 'Str|Undef', default => sub { undef }); @@ -52,7 +41,11 @@ package Paws::Credential::STS; (defined $self->Policy) ? (Policy => $self->Policy) : (), ); - my $creds = $self->actual_creds($result->Credentials); + $self->actual_creds(Paws::Credential::Explicit->new( + access_key => $result->Credentials->AccessKeyId, + secret_key => $result->Credentials->SecretAccessKey, + session_token => $result->Credentials->SessionToken, + )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($result->Credentials->Expiration)->epoch); } From e90f75a6b77aa9ddff7ab907711746213832f08a Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:04:36 +0100 Subject: [PATCH 14/26] Make the credentials contract that they implement refresh --- benchmarks/util/dynamodb-decode.pl | 10 ++++++--- examples/athena.pl | 2 +- lib/Paws/Credential.pm | 4 ++-- lib/Paws/Credential/AssumeRole.pm | 20 ++++++++--------- lib/Paws/Credential/AssumeRoleWithSAML.pm | 19 ++++++---------- lib/Paws/Credential/CredProcess.pm | 21 ++++++++---------- lib/Paws/Credential/ECSContainerProfile.pm | 25 +++++++++++----------- lib/Paws/Credential/Environment.pm | 4 ++-- lib/Paws/Credential/Explicit.pm | 3 +-- lib/Paws/Credential/File.pm | 6 +++--- lib/Paws/Credential/InstanceProfile.pm | 20 ++++++++--------- lib/Paws/Credential/InstanceProfileV2.pm | 22 +++++++++---------- lib/Paws/Credential/None.pm | 2 +- lib/Paws/Credential/ProviderChain.pm | 2 +- lib/Paws/Credential/STS.pm | 20 ++++++++--------- t/lib/Test/CustomCredentials.pm | 10 ++++++--- 16 files changed, 91 insertions(+), 99 deletions(-) diff --git a/benchmarks/util/dynamodb-decode.pl b/benchmarks/util/dynamodb-decode.pl index 7d0b409838..c24f2139ef 100755 --- a/benchmarks/util/dynamodb-decode.pl +++ b/benchmarks/util/dynamodb-decode.pl @@ -45,11 +45,15 @@ BEGIN package Test::CustomCredentials { use Moose; use Paws::Credential; + use Paws::Credential::Explicit; with 'Paws::Credential'; - sub access_key { 'CustomAK' }; - sub secret_key { 'CustomSK' }; - sub session_token {}; + sub refresh { + return Paws::Credential::Explicit->new( + access_key => 'CustomAK', + secret_key => 'CustomSK', + ); + } __PACKAGE__->meta->make_immutable; }; diff --git a/examples/athena.pl b/examples/athena.pl index f9c625cbb4..9971fe276a 100644 --- a/examples/athena.pl +++ b/examples/athena.pl @@ -75,7 +75,7 @@ $status->QueryExecution->ResultConfiguration->OutputLocation . "\n" if $opt->verbose; -my $a = Paws::Credential::ProviderChain->new->selected_provider; +my $a = Paws::Credential::ProviderChain->new->refresh; # Paws::S3 is marked as unstable; the following wouldn't work with IAM roles. my $s3 = Net::Amazon::S3->new( diff --git a/lib/Paws/Credential.pm b/lib/Paws/Credential.pm index 0804d72025..3a0502f251 100644 --- a/lib/Paws/Credential.pm +++ b/lib/Paws/Credential.pm @@ -1,11 +1,11 @@ package Paws::Credential; use Moose::Role; - requires 'credentials'; + requires 'refresh'; sub are_set { my $self = shift; - return (defined $self->credentials); + return (defined $self->refresh); } no Moose; diff --git a/lib/Paws/Credential/AssumeRole.pm b/lib/Paws/Credential/AssumeRole.pm index 1c791c7fc3..eb20486a89 100644 --- a/lib/Paws/Credential/AssumeRole.pm +++ b/lib/Paws/Credential/AssumeRole.pm @@ -4,6 +4,8 @@ package Paws::Credential::AssumeRole; use Paws::Credential::Explicit; with 'Paws::Credential'; + has credentials => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + has expiration => ( is => 'rw', isa => 'Int', @@ -11,14 +13,6 @@ package Paws::Credential::AssumeRole; default => sub { 0 } ); - has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - - sub credentials { - my $self = shift; - $self->_refresh; - return $self->actual_creds; - } - has sts_region => (is => 'ro', isa => 'Str|Undef', default => sub { undef }); has sts => (is => 'ro', isa => 'Paws::STS', lazy => 1, default => sub { @@ -33,10 +27,12 @@ package Paws::Credential::AssumeRole; has RoleArn => (is => 'rw', isa => 'Str', required => 1); has RoleSessionName => (is => 'rw', isa => 'Str', required => 1); - sub _refresh { + sub refresh { my $self = shift; - return if $self->expiration >= time; + if ( $self->credentials && $self->expiration >= time ) { + return $self->credentials; + } my $result = $self->sts->AssumeRole( RoleSessionName => $self->RoleSessionName, @@ -46,12 +42,14 @@ package Paws::Credential::AssumeRole; (defined $self->Policy) ? (Policy => $self->Policy) : (), ); - $self->actual_creds(Paws::Credential::Explicit->new( + $self->credentials(Paws::Credential::Explicit->new( access_key => $result->Credentials->AccessKeyId, secret_key => $result->Credentials->SecretAccessKey, session_token => $result->Credentials->SessionToken, )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($result->Credentials->Expiration)->epoch); + + return $self->credentials; } no Moose; diff --git a/lib/Paws/Credential/AssumeRoleWithSAML.pm b/lib/Paws/Credential/AssumeRoleWithSAML.pm index 3842787381..ae6756da4c 100644 --- a/lib/Paws/Credential/AssumeRoleWithSAML.pm +++ b/lib/Paws/Credential/AssumeRoleWithSAML.pm @@ -5,6 +5,8 @@ package Paws::Credential::AssumeRoleWithSAML; use Paws::Credential::Explicit; with 'Paws::Credential'; + has credentials => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + has expiration => ( is => 'rw', isa => 'Int', @@ -12,14 +14,6 @@ package Paws::Credential::AssumeRoleWithSAML; default => sub { 0 } ); - has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - - sub credentials { - my $self = shift; - $self->_refresh; - return $self->actual_creds; - } - has sts_region => (is => 'ro', isa => 'Str|Undef', default => sub { undef }); has sts => (is => 'ro', isa => 'Paws::STS', lazy => 1, default => sub { @@ -34,10 +28,12 @@ package Paws::Credential::AssumeRoleWithSAML; has PrincipalArn => (is => 'rw', isa => 'Str', required => 1); has SAMLAssertion => (is => 'rw', isa => 'Str', required => 1); - sub _refresh { + sub refresh { my $self = shift; - return if $self->expiration >= time; + if ( $self->credentials && $self->expiration >= time ) { + return $self->credentials; + } my $result = $self->sts->AssumeRoleWithSAML( RoleArn => $self->RoleArn, @@ -47,7 +43,7 @@ package Paws::Credential::AssumeRoleWithSAML; (defined $self->Policy) ? (Policy => $self->Policy) : (), ); - $self->actual_creds(Paws::Credential::Explicit->new( + $self->credentials(Paws::Credential::Explicit->new( access_key => $result->Credentials->AccessKeyId, secret_key => $result->Credentials->SecretAccessKey, session_token => $result->Credentials->SessionToken, @@ -56,5 +52,4 @@ package Paws::Credential::AssumeRoleWithSAML; } no Moose; - 1; diff --git a/lib/Paws/Credential/CredProcess.pm b/lib/Paws/Credential/CredProcess.pm index dfa0a876b7..d0f6aab5ff 100644 --- a/lib/Paws/Credential/CredProcess.pm +++ b/lib/Paws/Credential/CredProcess.pm @@ -9,6 +9,8 @@ package Paws::Credential::CredProcess; has credential_process => (is => 'ro', isa => 'Str', required => 1); + has credentials => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + has expiration => ( is => 'rw', isa => 'Int|Undef', @@ -16,19 +18,12 @@ package Paws::Credential::CredProcess; default => sub { 0 } ); - has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - - sub credentials { + sub refresh { my $self = shift; - $self->_refresh; - return $self->actual_creds; - } - sub _refresh { - my $self = shift; - - return if not defined $self->expiration; - return if $self->expiration >= time; + if ( $self->credentials && $self->expiration >= time ) { + return $self->credentials; + } my $creds; my $rc; @@ -51,11 +46,13 @@ package Paws::Credential::CredProcess; $self->expiration(undef); } - $self->actual_creds(Paws::Credential::Explicit->new( + $self->credentials(Paws::Credential::Explicit->new( access_key => $creds->{ AccessKeyId }, secret_key => $creds->{ SecretAccessKey }, session_token => $creds->{ SessionToken }, )); + + return $self->credentials; } no Moose; diff --git a/lib/Paws/Credential/ECSContainerProfile.pm b/lib/Paws/Credential/ECSContainerProfile.pm index 28ce1a23ff..e7ce2a3977 100644 --- a/lib/Paws/Credential/ECSContainerProfile.pm +++ b/lib/Paws/Credential/ECSContainerProfile.pm @@ -42,20 +42,14 @@ package Paws::Credential::ECSContainerProfile; } ); + has credentials => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + has expiration => ( is => 'rw', isa => 'Int', default => sub { 0 } ); - has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - - sub credentials { - my $self = shift; - $self->_refresh; - return $self->actual_creds; - } - around are_set => sub { my ($orig, $self) = @_; return 0 if (not defined $self->container_local_uri); @@ -63,11 +57,16 @@ package Paws::Credential::ECSContainerProfile; }; #TODO: Raise exceptions if HTTP get didn't return success - sub _refresh { + sub refresh { my $self = shift; - return if $self->expiration - 240 >= time; - return if ! $self->metadata_url; + if ( $self->credentials && $self->expiration - 240 >= time ) { + return $self->credentials; + } + + if ( ! $self->metadata_url ) { + return; + } my $ua = $self->ua; @@ -78,12 +77,14 @@ package Paws::Credential::ECSContainerProfile; my $json = eval { decode_json($r->{content}) }; if ($@) { die "Error in JSON from metadata URL" } - $self->actual_creds(Paws::Credential::Explicit->new( + $self->credentials(Paws::Credential::Explicit->new( access_key => $json->{AccessKeyId}, secret_key => $json->{SecretAccessKey}, session_token => $json->{Token}, )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($json->{Expiration})->epoch); + + return $self->credentials; } no Moose; diff --git a/lib/Paws/Credential/Environment.pm b/lib/Paws/Credential/Environment.pm index c956f7ba18..5927a64ffe 100644 --- a/lib/Paws/Credential/Environment.pm +++ b/lib/Paws/Credential/Environment.pm @@ -3,7 +3,7 @@ package Paws::Credential::Environment; use Paws::Credential::Explicit; with 'Paws::Credential'; - sub credentials { + sub refresh { my $self = shift; my $access_key = $ENV{AWS_ACCESS_KEY} || $ENV{AWS_ACCESS_KEY_ID}; @@ -11,7 +11,7 @@ package Paws::Credential::Environment; my $session_token = $ENV{AWS_SESSION_TOKEN}; if (!$access_key || !$secret_key) { - return undef; + return; } return Paws::Credential::Explicit->new( diff --git a/lib/Paws/Credential/Explicit.pm b/lib/Paws/Credential/Explicit.pm index 9cfaa05269..37a0a9942c 100644 --- a/lib/Paws/Credential/Explicit.pm +++ b/lib/Paws/Credential/Explicit.pm @@ -6,9 +6,8 @@ package Paws::Credential::Explicit; has secret_key => (is => 'ro', isa => 'Str', required => 1); has session_token => (is => 'ro', isa => 'Str'); - sub credentials { + sub refresh { my $self = shift; - return $self; } diff --git a/lib/Paws/Credential/File.pm b/lib/Paws/Credential/File.pm index 370f616bca..54963317be 100644 --- a/lib/Paws/Credential/File.pm +++ b/lib/Paws/Credential/File.pm @@ -57,11 +57,11 @@ package Paws::Credential::File; ); }); - sub credentials { + sub refresh { my $self = shift; - + if (defined $self->credential_process) { - return $self->credential_process->credentials; + return $self->credential_process->refresh; } else { return $self->_profile; } diff --git a/lib/Paws/Credential/InstanceProfile.pm b/lib/Paws/Credential/InstanceProfile.pm index 506596b11a..3d1a0775a0 100644 --- a/lib/Paws/Credential/InstanceProfile.pm +++ b/lib/Paws/Credential/InstanceProfile.pm @@ -26,25 +26,21 @@ package Paws::Credential::InstanceProfile; } ); + has credentials => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + has expiration => ( is => 'rw', isa => 'Int', default => sub { 0 } ); - has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - - sub credentials { - my $self = shift; - $self->_refresh; - return $self->actual_creds; - } - #TODO: Raise exceptions if HTTP get didn't return success - sub _refresh { + sub refresh { my $self = shift; - return if $self->expiration - 240 >= time; + if ($self->credentials && $self->expiration - 240 >= time) { + return $self->credentials; + } my $ua = $self->ua; my $r = $ua->get($self->metadata_url); @@ -57,12 +53,14 @@ package Paws::Credential::InstanceProfile; my $json = eval { decode_json($r->{content}) }; if ($@) { die "Error in JSON from metadata URL" } - $self->actual_creds(Paws::Credential::Explicit->new( + $self->credentials(Paws::Credential::Explicit->new( access_key => $json->{AccessKeyId}, secret_key => $json->{SecretAccessKey}, session_token => $json->{Token}, )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($json->{Expiration})->epoch); + + return $self->credentials; } no Moose; diff --git a/lib/Paws/Credential/InstanceProfileV2.pm b/lib/Paws/Credential/InstanceProfileV2.pm index 02a002d426..9c5d7cb343 100644 --- a/lib/Paws/Credential/InstanceProfileV2.pm +++ b/lib/Paws/Credential/InstanceProfileV2.pm @@ -32,26 +32,22 @@ package Paws::Credential::InstanceProfileV2; } ); + has credentials => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + has expiration => ( is => 'rw', isa => 'Int', default => sub { 0 } ); - has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - - sub credentials { - my $self = shift; - $self->_refresh; - return $self->actual_creds; - } - #TODO: Raise exceptions if HTTP get didn't return success - sub _refresh { + sub refresh { my $self = shift; - return if $self->expiration - 240 >= time; - + if ($self->credentials && $self->expiration - 240 >= time) { + return $self->credentials; + } + my $ua = $self->ua; my $r = $ua->put( $self->token_url, { headers => { 'X-aws-ec2-metadata-token-ttl-seconds' => '21600' } } ); return unless $r->{success}; @@ -70,12 +66,14 @@ package Paws::Credential::InstanceProfileV2; my $json = eval { decode_json($r->{content}) }; if ($@) { die "Error in JSON from metadata URL" } - $self->actual_creds(Paws::Credential::Explicit->new( + $self->credentials(Paws::Credential::Explicit->new( access_key => $json->{AccessKeyId}, secret_key => $json->{SecretAccessKey}, session_token => $json->{Token}, )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($json->{Expiration})->epoch); + + return $self->credentials; } no Moose; diff --git a/lib/Paws/Credential/None.pm b/lib/Paws/Credential/None.pm index a0fb46b77a..5b11289af7 100644 --- a/lib/Paws/Credential/None.pm +++ b/lib/Paws/Credential/None.pm @@ -2,7 +2,7 @@ package Paws::Credential::None; use Moose; with 'Paws::Credential'; - sub credentials { return undef; } + sub refresh { return undef; } no Moose; 1; diff --git a/lib/Paws/Credential/ProviderChain.pm b/lib/Paws/Credential/ProviderChain.pm index d9249807dd..0046f58e58 100644 --- a/lib/Paws/Credential/ProviderChain.pm +++ b/lib/Paws/Credential/ProviderChain.pm @@ -19,7 +19,7 @@ package Paws::Credential::ProviderChain; has selected_provider => ( is => 'rw', does => 'Paws::Credential', - handles => [ 'credentials' ], + handles => [ 'refresh' ], ); sub BUILD { diff --git a/lib/Paws/Credential/STS.pm b/lib/Paws/Credential/STS.pm index e01a6eee2e..9a189bafa9 100644 --- a/lib/Paws/Credential/STS.pm +++ b/lib/Paws/Credential/STS.pm @@ -4,6 +4,8 @@ package Paws::Credential::STS; use Paws::Credential::Explicit; with 'Paws::Credential'; + has credentials => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); + has expiration => ( is => 'rw', isa => 'Int', @@ -11,14 +13,6 @@ package Paws::Credential::STS; default => sub { 0 } ); - has actual_creds => (is => 'rw', isa => 'Paws::Credential::Explicit|Undef'); - - sub credentials { - my $self = shift; - $self->_refresh; - return $self->actual_creds; - } - has sts_region => (is => 'ro', isa => 'Str|Undef', default => sub { undef }); has sts => (is => 'ro', isa => 'Paws::STS', lazy => 1, default => sub { @@ -30,10 +24,12 @@ package Paws::Credential::STS; has DurationSeconds => (is => 'rw', isa => 'Maybe[Int]'); has Policy => (is => 'rw', isa => 'Maybe[Str]'); - sub _refresh { + sub refresh { my $self = shift; - return if $self->expiration >= time; + if ( $self->credentials && $self->expiration >= time ) { + return $self->credentials; + } my $result = $self->sts->GetFederationToken( Name => $self->Name, @@ -41,12 +37,14 @@ package Paws::Credential::STS; (defined $self->Policy) ? (Policy => $self->Policy) : (), ); - $self->actual_creds(Paws::Credential::Explicit->new( + $self->credentials(Paws::Credential::Explicit->new( access_key => $result->Credentials->AccessKeyId, secret_key => $result->Credentials->SecretAccessKey, session_token => $result->Credentials->SessionToken, )); $self->expiration(DateTime::Format::ISO8601->parse_datetime($result->Credentials->Expiration)->epoch); + + return $self->credentials; } no Moose; diff --git a/t/lib/Test/CustomCredentials.pm b/t/lib/Test/CustomCredentials.pm index be0bb1f119..b2cb8cef89 100644 --- a/t/lib/Test/CustomCredentials.pm +++ b/t/lib/Test/CustomCredentials.pm @@ -1,9 +1,13 @@ package Test::CustomCredentials; use Moose; use Paws::Credential; + use Paws::Credential::Explicit; with 'Paws::Credential'; - sub access_key { 'CustomAK' }; - sub secret_key { 'CustomSK' }; - sub session_token {}; + sub refresh { + return Paws::Credential::Explicit->new( + access_key => 'CustomAK', + secret_key => 'CustomSK', + ); + } 1; From bec875bd8ac5b7eea4584cfea1f70d1e6e6897d6 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:15:26 +0100 Subject: [PATCH 15/26] Update tests for the refresh method --- examples/sts-saml.pl | 8 ++- t/04_credentials.t | 130 +++++++++++++++++++++++++++---------------- 2 files changed, 87 insertions(+), 51 deletions(-) diff --git a/examples/sts-saml.pl b/examples/sts-saml.pl index fb2e1840a3..ab30e2e1a8 100755 --- a/examples/sts-saml.pl +++ b/examples/sts-saml.pl @@ -92,13 +92,15 @@ $config = Config::INI::Reader->read_file($aws_creds_file); } +my $a = $creds->refresh; + my $profile = lc $short_role; try { $config->{$profile} = { region => $region, - aws_access_key_id => $creds->access_key, - aws_secret_access_key => $creds->secret_key, - aws_session_token => $creds->session_token, + aws_access_key_id => $a->access_key, + aws_secret_access_key => $a->secret_key, + aws_session_token => $a->session_token, }; } catch(Paws::Exception $e) { die sprintf "FATAL: %s - %s\n", $e->code, $e->message; diff --git a/t/04_credentials.t b/t/04_credentials.t index 8a99933ae4..063f789f61 100644 --- a/t/04_credentials.t +++ b/t/04_credentials.t @@ -53,8 +53,10 @@ delete @ENV{qw( my $creds = Paws::Credential::Environment->new; ok($creds->are_set, 'Creds are set'); - cmp_ok($creds->access_key, 'eq', 'botoAK', 'Access Key boto style'); - cmp_ok($creds->secret_key, 'eq', 'botoSK', 'Secret Key boto style'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'botoAK', 'Access Key boto style'); + cmp_ok($a->secret_key, 'eq', 'botoSK', 'Secret Key boto style'); } { @@ -63,42 +65,54 @@ delete @ENV{qw( my $creds = Paws::Credential::Environment->new; ok($creds->are_set, 'Creds are set'); - cmp_ok($creds->access_key, 'eq', 'AK', 'Access Key short style'); - cmp_ok($creds->secret_key, 'eq', 'SK', 'Secret Key short style'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'AK', 'Access Key short style'); + cmp_ok($a->secret_key, 'eq', 'SK', 'Secret Key short style'); } { my $creds = Paws::Credential::InstanceProfile->new(ua => Test04::StubUAForMetadata->new); - cmp_ok($creds->access_key, 'eq', 'AK1', 'Access Key 1'); - cmp_ok($creds->secret_key, 'eq', 'SK1', 'Secret Key 1'); - cmp_ok($creds->session_token, 'eq', 'TK1', 'Token 1'); + + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'AK1', 'Access Key 1'); + cmp_ok($a->secret_key, 'eq', 'SK1', 'Secret Key 1'); + cmp_ok($a->session_token, 'eq', 'TK1', 'Token 1'); sleep 2; - cmp_ok($creds->access_key, 'eq', 'AK2', 'Access Key 2'); - cmp_ok($creds->secret_key, 'eq', 'SK2', 'Secret Key 2'); - cmp_ok($creds->session_token, 'eq', 'TK2', 'Token 2'); + $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'AK2', 'Access Key 2'); + cmp_ok($a->secret_key, 'eq', 'SK2', 'Secret Key 2'); + cmp_ok($a->session_token, 'eq', 'TK2', 'Token 2'); sleep 2; - dies_ok { $creds->access_key } 'Exception thrown when garbage arrives'; + dies_ok { $creds->refresh }, 'Exception thrown when garbage arrives'; } { my $creds = Paws::Credential::InstanceProfileV2->new(ua => Test04::StubUAForMetadata->new(check_header => 1)); - cmp_ok($creds->access_key, 'eq', 'AK1', 'Access Key 1 (IMDSv2)'); - cmp_ok($creds->secret_key, 'eq', 'SK1', 'Secret Key 1 (IMDSv2)'); - cmp_ok($creds->session_token, 'eq', 'TK1', 'Token 1 (IMDSv2)'); + + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'AK1', 'Access Key 1 (IMDSv2)'); + cmp_ok($a->secret_key, 'eq', 'SK1', 'Secret Key 1 (IMDSv2)'); + cmp_ok($a->session_token, 'eq', 'TK1', 'Token 1 (IMDSv2)'); sleep 2; - cmp_ok($creds->access_key, 'eq', 'AK2', 'Access Key 2 (IMDSv2)'); - cmp_ok($creds->secret_key, 'eq', 'SK2', 'Secret Key 2 (IMDSv2)'); - cmp_ok($creds->session_token, 'eq', 'TK2', 'Token 2 (IMDSv2)'); + $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'AK2', 'Access Key 2 (IMDSv2)'); + cmp_ok($a->secret_key, 'eq', 'SK2', 'Secret Key 2 (IMDSv2)'); + cmp_ok($a->session_token, 'eq', 'TK2', 'Token 2 (IMDSv2)'); sleep 2; - dies_ok { $creds->access_key } 'Exception thrown when garbage arrives (IMDSv2)'; + dies_ok { $creds->refresh }, 'Exception thrown when garbage arrives (IMDSv2)'; } { @@ -122,26 +136,32 @@ delete @ENV{qw( my $creds = Paws::Credential::ECSContainerProfile->new(container_local_uri => '/metadata', ua => Test04::StubUAForECSMetadata->new); cmp_ok($creds->metadata_url, 'eq', "http://169.254.170.2/metadata"); - cmp_ok($creds->access_key, 'eq', 'AK1', 'ECS Access Key 1'); - cmp_ok($creds->secret_key, 'eq', 'SK1', 'ECS Secret Key 1'); - cmp_ok($creds->session_token, 'eq', 'TK1', 'ECS Token 1'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'AK1', 'ECS Access Key 1'); + cmp_ok($a->secret_key, 'eq', 'SK1', 'ECS Secret Key 1'); + cmp_ok($a->session_token, 'eq', 'TK1', 'ECS Token 1'); sleep 2; - cmp_ok($creds->access_key, 'eq', 'AK2', 'ECS Access Key 2'); - cmp_ok($creds->secret_key, 'eq', 'SK2', 'ECS Secret Key 2'); - cmp_ok($creds->session_token, 'eq', 'TK2', 'ECS Token 2'); + $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'AK2', 'ECS Access Key 2'); + cmp_ok($a->secret_key, 'eq', 'SK2', 'ECS Secret Key 2'); + cmp_ok($a->session_token, 'eq', 'TK2', 'ECS Token 2'); sleep 2; - dies_ok { $creds->access_key } 'Exception thrown when garbage arrives to ECS Provider'; + dies_ok { $creds->refresh }, 'Exception thrown when garbage arrives to ECS Provider'; } { my $creds = Paws::Credential::ProviderChain->new(providers => [ 'Test::CustomCredentials', 'Paws::Credentail::Environment' ]); ok($creds->are_set, 'Creds are set'); - cmp_ok($creds->access_key, 'eq', 'CustomAK', 'Access Key short style'); - cmp_ok($creds->secret_key, 'eq', 'CustomSK', 'Secret Key short style'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'CustomAK', 'Access Key short style'); + cmp_ok($a->secret_key, 'eq', 'CustomSK', 'Secret Key short style'); } ## File provider testing @@ -168,8 +188,10 @@ delete @ENV{qw( path => 't/04_credentials/' ); ok($creds->are_set, 'File: Attribute path works correctly'); - cmp_ok($creds->access_key, 'eq', 'defaultAK', 'File: default Access Key loaded correctly'); - cmp_ok($creds->secret_key, 'eq', 'defaultSK', 'File: default Secret Key loaded correctly'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'defaultAK', 'File: default Access Key loaded correctly'); + cmp_ok($a->secret_key, 'eq', 'defaultSK', 'File: default Secret Key loaded correctly'); } { @@ -178,8 +200,10 @@ delete @ENV{qw( profile => 'testprofile' ); ok($creds->are_set, 'File: Attributes path and profile work correctly'); - cmp_ok($creds->access_key, 'eq', 'testAK', 'File: named profile Access Key loaded correctly'); - cmp_ok($creds->secret_key, 'eq', 'testSK', 'File: named profile Secret Key loaded correctly'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'testAK', 'File: named profile Access Key loaded correctly'); + cmp_ok($a->secret_key, 'eq', 'testSK', 'File: named profile Secret Key loaded correctly'); } { @@ -187,8 +211,10 @@ delete @ENV{qw( credentials_file => 't/04_credentials/credentials.alternate', ); ok($creds->are_set, 'File: credentials_file attribute works correctly'); - cmp_ok($creds->access_key, 'eq', 'alternateAK', 'File: alternate Access Key loaded correctly'); - cmp_ok($creds->secret_key, 'eq', 'alternateSK', 'File: alternate Secret Key loaded correctly'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'alternateAK', 'File: alternate Access Key loaded correctly'); + cmp_ok($a->secret_key, 'eq', 'alternateSK', 'File: alternate Secret Key loaded correctly'); } { @@ -197,8 +223,10 @@ delete @ENV{qw( file_name => 'credentials.alternate', ); ok($creds->are_set, 'File: file_name attribute works correctly'); - cmp_ok($creds->access_key, 'eq', 'alternateAK', 'File: alternate Access Key loaded correctly'); - cmp_ok($creds->secret_key, 'eq', 'alternateSK', 'File: alternate Secret Key loaded correctly'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'alternateAK', 'File: alternate Access Key loaded correctly'); + cmp_ok($a->secret_key, 'eq', 'alternateSK', 'File: alternate Secret Key loaded correctly'); } { @@ -207,10 +235,12 @@ delete @ENV{qw( my $creds = Paws::Credential::File->new; ok($creds->are_set, 'File: Attributes from environment variables'); - cmp_ok($creds->access_key, 'eq', 'alternateprofileAK', - 'File: alternate using ENV variables Access Key loaded correctly'); - cmp_ok($creds->secret_key, 'eq', 'alternateprofileSK', + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'alternateprofileAK', + 'File: alternate using ENV variables Access Key loaded correctly'); + cmp_ok($a->secret_key, 'eq', 'alternateprofileSK', 'File: alternate using ENV variables Secret Key loaded correctly'); } @@ -220,9 +250,11 @@ delete @ENV{qw( ); ok($creds->are_set, 'CredProcess: creds are set'); - cmp_ok($creds->access_key, 'eq', 'PCAccessKey', 'process: Access Key loaded correctly'); - cmp_ok($creds->secret_key, 'eq', 'PCSecretKey', 'process: Secret Key loaded correctly'); - cmp_ok($creds->session_token, 'eq', 'PCSessionToken', 'process: Session Token loaded correctly'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'PCAccessKey', 'process: Access Key loaded correctly'); + cmp_ok($a->secret_key, 'eq', 'PCSecretKey', 'process: Secret Key loaded correctly'); + cmp_ok($a->session_token, 'eq', 'PCSessionToken', 'process: Session Token loaded correctly'); ok(not(defined $creds->expiration), 'Creds don\'t expire'); } @@ -245,9 +277,9 @@ delete @ENV{qw( credential_process => 't/04_credentials/test_cred_process.expiry', ); - my $first_execution = $creds->access_key; # the test suite returns the timestamp of execution in the AK + my $first_execution = $creds->refresh->access_key; # the test suite returns the timestamp of execution in the AK sleep 1; - my $second_execution = $creds->access_key; # the test suite returns the timestamp of execution in the AK + my $second_execution = $creds->refresh->access_key; # the test suite returns the timestamp of execution in the AK cmp_ok($first_execution, 'ne', $second_execution, 'Expiring credentials have been refreshed'); } @@ -260,9 +292,11 @@ delete @ENV{qw( ); ok($creds->are_set, 'File with credentials_process'); - cmp_ok($creds->access_key, 'eq', 'PCAccessKey', 'process: Access Key loaded correctly'); - cmp_ok($creds->secret_key, 'eq', 'PCSecretKey', 'process: Secret Key loaded correctly'); - cmp_ok($creds->session_token, 'eq', 'PCSessionToken', 'process: Session Token loaded correctly'); + my $a = $creds->refresh; + ok($a, 'Refresh returns a value'); + cmp_ok($a->access_key, 'eq', 'PCAccessKey', 'process: Access Key loaded correctly'); + cmp_ok($a->secret_key, 'eq', 'PCSecretKey', 'process: Secret Key loaded correctly'); + cmp_ok($a->session_token, 'eq', 'PCSessionToken', 'process: Session Token loaded correctly'); } { @@ -290,9 +324,9 @@ delete @ENV{qw( profile => 'expiry', ); - my $first_execution = $creds->access_key; # the test suite returns the timestamp of execution in the AK + my $first_execution = $creds->refresh->access_key; # the test suite returns the timestamp of execution in the AK sleep 1; - my $second_execution = $creds->access_key; # the test suite returns the timestamp of execution in the AK + my $second_execution = $creds->refresh->access_key; # the test suite returns the timestamp of execution in the AK cmp_ok($first_execution, 'ne', $second_execution, 'Expiring credentials have been refreshed'); } From cc05f3c1d5f820523d3c2b4f0cdd8250b6304bfa Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:38:08 +0100 Subject: [PATCH 16/26] Remove handles forwarding of the credential methods, these aren't implemented on Paws::Credential any more --- lib/Paws/API/Caller.pm | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Paws/API/Caller.pm b/lib/Paws/API/Caller.pm index acdbdd9089..9b0baaf5a9 100644 --- a/lib/Paws/API/Caller.pm +++ b/lib/Paws/API/Caller.pm @@ -10,7 +10,6 @@ package Paws::API::Caller; is => 'ro', does => 'Paws::Credential', required => 1, - handles => [ 'access_key', 'secret_key', 'session_token' ], ); # converts the params the user passed to the call into objects that represent the call From d62e2c5798d03e76bb6e9986b45d09c681efd9ba Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:40:00 +0100 Subject: [PATCH 17/26] Update the signers to use ->refresh to get their fields --- lib/Paws/Net/S3Signature.pm | 4 +++- lib/Paws/Net/S3V4Signature.pm | 8 +++++--- lib/Paws/Net/V2Signature.pm | 10 ++++++---- lib/Paws/Net/V4Signature.pm | 8 +++++--- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/Paws/Net/S3Signature.pm b/lib/Paws/Net/S3Signature.pm index 71fa1c467e..ca76840efa 100755 --- a/lib/Paws/Net/S3Signature.pm +++ b/lib/Paws/Net/S3Signature.pm @@ -40,7 +40,9 @@ package Paws::Net::S3Signature; ? $self->endpoint->host : $self->endpoint->host_port); - my $sig = Net::Amazon::Signature::V4->new( $self->access_key, $self->secret_key, $self->region, $self->service ); + my $creds = $self->credentials->refresh; + + my $sig = Net::Amazon::Signature::V4->new( $creds->access_key, $creds->secret_key, $self->region, $self->service ); my $signed_req = $sig->sign( $request ); return $signed_req; diff --git a/lib/Paws/Net/S3V4Signature.pm b/lib/Paws/Net/S3V4Signature.pm index dd618bf5f3..c4f7148859 100644 --- a/lib/Paws/Net/S3V4Signature.pm +++ b/lib/Paws/Net/S3V4Signature.pm @@ -26,17 +26,19 @@ package Paws::Net::S3V4Signature; sub sign { my ($self, $request) = @_; + my $creds = $self->credentials->refresh; + $request->header( Date => $request->header('X-Amz-Date') // strftime( '%Y%m%dT%H%M%SZ', gmtime ) ); $request->header( 'Host' => $self->endpoint->default_port == $self->endpoint->port ? $self->endpoint->host : $self->endpoint->host_port); - if ($self->session_token) { - $request->header( 'X-Amz-Security-Token' => $self->session_token ); + if ($creds->session_token) { + $request->header( 'X-Amz-Security-Token' => $creds->session_token ); } my $name = $self->can('signing_name') ? $self->signing_name : $self->service; - my $sig = Net::Amazon::Signature::V4->new( $self->access_key, $self->secret_key, $self->_region_for_signature, $name ); + my $sig = Net::Amazon::Signature::V4->new( $creds->access_key, $creds->secret_key, $self->_region_for_signature, $name ); $sig->sign( $request ); } 1; diff --git a/lib/Paws/Net/V2Signature.pm b/lib/Paws/Net/V2Signature.pm index 863b23c64b..bfa96a084e 100644 --- a/lib/Paws/Net/V2Signature.pm +++ b/lib/Paws/Net/V2Signature.pm @@ -71,13 +71,15 @@ sub _split_url { sub sign { my ($self, $request) = @_; + my $creds = $self->credentials->refresh; + $request->parameters->{ SignatureVersion } = "2"; $request->parameters->{ SignatureMethod } = "HmacSHA256"; $request->parameters->{ Timestamp } //= strftime("%Y-%m-%dT%H:%M:%SZ",gmtime); - $request->parameters->{ AWSAccessKeyId } = $self->access_key; + $request->parameters->{ AWSAccessKeyId } = $creds->access_key; - if ($self->session_token) { - $request->parameters->{ SecurityToken } = $self->session_token; + if ($creds->session_token) { + $request->parameters->{ SecurityToken } = $creds->session_token; } my %sign_hash = %{ $request->parameters }; @@ -88,7 +90,7 @@ sub sign { $sign_this .= $self->www_form_urlencode(\%sign_hash); - my $encoded = encode_base64(hmac_sha256($sign_this, $self->secret_key), ''); + my $encoded = encode_base64(hmac_sha256($sign_this, $creds->secret_key), ''); $request->parameters->{ Signature } = $encoded; diff --git a/lib/Paws/Net/V4Signature.pm b/lib/Paws/Net/V4Signature.pm index 4a65edd39f..941f7491dd 100644 --- a/lib/Paws/Net/V4Signature.pm +++ b/lib/Paws/Net/V4Signature.pm @@ -24,17 +24,19 @@ package Paws::Net::V4Signature; sub sign { my ($self, $request) = @_; + my $creds = $self->credentials->refresh; + $request->header( Date => $request->header('X-Amz-Date') // strftime( '%Y%m%dT%H%M%SZ', gmtime ) ); $request->header( 'Host' => $self->endpoint->default_port == $self->endpoint->port ? $self->endpoint->host : $self->endpoint->host_port); - if ($self->session_token) { - $request->header( 'X-Amz-Security-Token' => $self->session_token ); + if ($creds->session_token) { + $request->header( 'X-Amz-Security-Token' => $creds->session_token ); } my $name = $self->can('signing_name') ? $self->signing_name : $self->service; - my $sig = Net::Amazon::Signature::V4->new( $self->access_key, $self->secret_key, $self->_region_for_signature, $name ); + my $sig = Net::Amazon::Signature::V4->new( $creds->access_key, $creds->secret_key, $self->_region_for_signature, $name ); $sig->sign( $request ); } 1; From 84a8d21136255c72a00b9ac3e1eb4c4f5d4789ca Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:43:16 +0100 Subject: [PATCH 18/26] handles doesn't allow with requirements to be satisfied --- lib/Paws/Credential/ProviderChain.pm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Paws/Credential/ProviderChain.pm b/lib/Paws/Credential/ProviderChain.pm index 0046f58e58..42bd527851 100644 --- a/lib/Paws/Credential/ProviderChain.pm +++ b/lib/Paws/Credential/ProviderChain.pm @@ -19,9 +19,13 @@ package Paws::Credential::ProviderChain; has selected_provider => ( is => 'rw', does => 'Paws::Credential', - handles => [ 'refresh' ], ); + sub refresh { + my ($self) = @_; + return $self->selected_provider->refresh; + } + sub BUILD { my ($self) = @_; foreach my $prov (@{ $self->providers }) { From 08bf923fcf5181d945022daa09e4a8cd2e722e20 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:47:36 +0100 Subject: [PATCH 19/26] Fix JSONCaller retriving the access_key --- lib/Paws/Net/JsonCaller.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Paws/Net/JsonCaller.pm b/lib/Paws/Net/JsonCaller.pm index 5c173fe006..7fc2591d52 100644 --- a/lib/Paws/Net/JsonCaller.pm +++ b/lib/Paws/Net/JsonCaller.pm @@ -72,10 +72,12 @@ package Paws::Net::JsonCaller; $request->uri('/'); $request->method('POST'); + my $creds = $self->credentials->refresh; + my @time = gmtime; $request->parameters({ Action => $call->_api_call, Version => $self->version, - AWSAccessKeyId => $self->access_key, + AWSAccessKeyId => $creds->access_key, Timestamp => strftime("%Y-%m-%dT%H:%M:%SZ",@time), }); $request->header('X-Amz-Target', sprintf('%s.%s', $self->target_prefix, $call->_api_call)); From 1a0a07669d37a186c0421b019c0524e55d5a38bc Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:48:05 +0100 Subject: [PATCH 20/26] Add creds as an argument to sign This needs to be passed through in cases where the creds have already been retrieved to avoid shearing --- lib/Paws/Net/JsonCaller.pm | 2 +- lib/Paws/Net/S3Signature.pm | 10 +++++----- lib/Paws/Net/S3V4Signature.pm | 4 ++-- lib/Paws/Net/V2Signature.pm | 4 ++-- lib/Paws/Net/V4Signature.pm | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/Paws/Net/JsonCaller.pm b/lib/Paws/Net/JsonCaller.pm index 7fc2591d52..1774a77f69 100644 --- a/lib/Paws/Net/JsonCaller.pm +++ b/lib/Paws/Net/JsonCaller.pm @@ -92,7 +92,7 @@ package Paws::Net::JsonCaller; my $data = $self->_to_jsoncaller_params($call); $request->content(encode_json($data)); - $self->sign($request); + $self->sign($request, $creds); return $request; } diff --git a/lib/Paws/Net/S3Signature.pm b/lib/Paws/Net/S3Signature.pm index ca76840efa..4a89893e7b 100755 --- a/lib/Paws/Net/S3Signature.pm +++ b/lib/Paws/Net/S3Signature.pm @@ -22,10 +22,12 @@ package Paws::Net::S3Signature; use Net::Amazon::Signature::V4; sub sign { - my ($self, $request) = @_; + my ($self, $request, $creds) = @_; - if ($self->session_token) { - $request->header( 'X-Amz-Security-Token' => $self->session_token ); + $creds ||= $self->credentials->refresh; + + if ($creds->session_token) { + $request->header( 'X-Amz-Security-Token' => $creds->session_token ); } my $hasher = Digest::SHA->new(256); @@ -40,8 +42,6 @@ package Paws::Net::S3Signature; ? $self->endpoint->host : $self->endpoint->host_port); - my $creds = $self->credentials->refresh; - my $sig = Net::Amazon::Signature::V4->new( $creds->access_key, $creds->secret_key, $self->region, $self->service ); my $signed_req = $sig->sign( $request ); return $signed_req; diff --git a/lib/Paws/Net/S3V4Signature.pm b/lib/Paws/Net/S3V4Signature.pm index c4f7148859..ff6eb61053 100644 --- a/lib/Paws/Net/S3V4Signature.pm +++ b/lib/Paws/Net/S3V4Signature.pm @@ -24,9 +24,9 @@ package Paws::Net::S3V4Signature; } sub sign { - my ($self, $request) = @_; + my ($self, $request, $creds) = @_; - my $creds = $self->credentials->refresh; + $creds ||= $self->credentials->refresh; $request->header( Date => $request->header('X-Amz-Date') // strftime( '%Y%m%dT%H%M%SZ', gmtime ) ); $request->header( diff --git a/lib/Paws/Net/V2Signature.pm b/lib/Paws/Net/V2Signature.pm index bfa96a084e..424ec2263a 100644 --- a/lib/Paws/Net/V2Signature.pm +++ b/lib/Paws/Net/V2Signature.pm @@ -69,9 +69,9 @@ sub _split_url { } sub sign { - my ($self, $request) = @_; + my ($self, $request, $creds) = @_; - my $creds = $self->credentials->refresh; + $creds ||= $self->credentials->refresh; $request->parameters->{ SignatureVersion } = "2"; $request->parameters->{ SignatureMethod } = "HmacSHA256"; diff --git a/lib/Paws/Net/V4Signature.pm b/lib/Paws/Net/V4Signature.pm index 941f7491dd..2fac8a84f4 100644 --- a/lib/Paws/Net/V4Signature.pm +++ b/lib/Paws/Net/V4Signature.pm @@ -22,9 +22,9 @@ package Paws::Net::V4Signature; } sub sign { - my ($self, $request) = @_; + my ($self, $request, $creds) = @_; - my $creds = $self->credentials->refresh; + $creds ||= $self->credentials->refresh; $request->header( Date => $request->header('X-Amz-Date') // strftime( '%Y%m%dT%H%M%SZ', gmtime ) ); $request->header( From 67bfd506732855da709b9cf0187ed2db989c2bdd Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 14:57:33 +0100 Subject: [PATCH 21/26] Allow explicit to have an undef session token --- lib/Paws/Credential/Explicit.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Paws/Credential/Explicit.pm b/lib/Paws/Credential/Explicit.pm index 37a0a9942c..5ce45ea0f7 100644 --- a/lib/Paws/Credential/Explicit.pm +++ b/lib/Paws/Credential/Explicit.pm @@ -4,7 +4,7 @@ package Paws::Credential::Explicit; has access_key => (is => 'ro', isa => 'Str', required => 1); has secret_key => (is => 'ro', isa => 'Str', required => 1); - has session_token => (is => 'ro', isa => 'Str'); + has session_token => (is => 'ro', isa => 'Str|Undef'); sub refresh { my $self = shift; From 66aa01de5aad2fd6b35e0fff95427c83591f1ac1 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 15:01:41 +0100 Subject: [PATCH 22/26] Fix the file provider when returning credentials from the profile --- lib/Paws/Credential/File.pm | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/Paws/Credential/File.pm b/lib/Paws/Credential/File.pm index 54963317be..0f1d955e6f 100644 --- a/lib/Paws/Credential/File.pm +++ b/lib/Paws/Credential/File.pm @@ -32,18 +32,11 @@ package Paws::Credential::File; return $ini; }); - has _profile => (is => 'ro', isa => 'Paws::Credential::Explicit|Undef', lazy => 1, default => sub { + has _profile => (is => 'ro', isa => 'HashRef', lazy => 1, default => sub { my $self = shift; my $profile = $self->profile; - my $profile_contents = $self->_ini_contents->{ $profile }; - return undef if (not defined $profile_contents); - - return Paws::Credential::Explicit->new( - access_key => $profile_contents->{ aws_access_key_id }, - secret_key => $profile_contents->{ aws_secret_access_key }, - session_token => $profile_contents->{ aws_session_token }, - ); + return $self->_ini_contents->{ $profile } || {}; }); has credential_process => (is => 'ro', isa => 'Paws::Credential::CredProcess|Undef', lazy => 1, default => sub { @@ -62,9 +55,18 @@ package Paws::Credential::File; if (defined $self->credential_process) { return $self->credential_process->refresh; - } else { - return $self->_profile; } + + my $profile = $self->_profile; + return if (not defined $profile); + return if (not defined $profile->{ aws_access_key_id }); + return if (not defined $profile->{ aws_secret_access_key }); + + return Paws::Credential::Explicit->new( + access_key => $profile->{ aws_access_key_id }, + secret_key => $profile->{ aws_secret_access_key }, + session_token => $profile->{ aws_session_token }, + ); } no Moose; From 731fb02fa609c8b20d2bbceb4c8a3199c48b4edd Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 15:10:12 +0100 Subject: [PATCH 23/26] Fix refreshing creds for credprocess --- lib/Paws/Credential/CredProcess.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Paws/Credential/CredProcess.pm b/lib/Paws/Credential/CredProcess.pm index d0f6aab5ff..d7667b64f0 100644 --- a/lib/Paws/Credential/CredProcess.pm +++ b/lib/Paws/Credential/CredProcess.pm @@ -21,7 +21,7 @@ package Paws::Credential::CredProcess; sub refresh { my $self = shift; - if ( $self->credentials && $self->expiration >= time ) { + if ( $self->credentials && (not defined $self->expiration || $self->expiration >= time ) ) { return $self->credentials; } From 7998ea95b752a38dd950a7e484a8b8508f953ee9 Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 15:10:38 +0100 Subject: [PATCH 24/26] Remove comma creating void context for string rather than argument --- t/04_credentials.t | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/t/04_credentials.t b/t/04_credentials.t index 063f789f61..6661995378 100644 --- a/t/04_credentials.t +++ b/t/04_credentials.t @@ -90,7 +90,7 @@ delete @ENV{qw( sleep 2; - dies_ok { $creds->refresh }, 'Exception thrown when garbage arrives'; + dies_ok { $creds->refresh } 'Exception thrown when garbage arrives'; } { @@ -112,7 +112,7 @@ delete @ENV{qw( sleep 2; - dies_ok { $creds->refresh }, 'Exception thrown when garbage arrives (IMDSv2)'; + dies_ok { $creds->refresh } 'Exception thrown when garbage arrives (IMDSv2)'; } { @@ -152,7 +152,7 @@ delete @ENV{qw( sleep 2; - dies_ok { $creds->refresh }, 'Exception thrown when garbage arrives to ECS Provider'; + dies_ok { $creds->refresh } 'Exception thrown when garbage arrives to ECS Provider'; } { From 6160fbcac94d65226c8ce18ac96eb68d55f4df1c Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 15:13:43 +0100 Subject: [PATCH 25/26] Fix warning in test about comparing numeric to undefined --- lib/Paws/Credential/CredProcess.pm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Paws/Credential/CredProcess.pm b/lib/Paws/Credential/CredProcess.pm index d7667b64f0..f31223299c 100644 --- a/lib/Paws/Credential/CredProcess.pm +++ b/lib/Paws/Credential/CredProcess.pm @@ -21,8 +21,14 @@ package Paws::Credential::CredProcess; sub refresh { my $self = shift; - if ( $self->credentials && (not defined $self->expiration || $self->expiration >= time ) ) { - return $self->credentials; + if ( $self->credentials ) { + if (not defined $self->expiration) { + return $self->credentials; + } + + if ($self->expiration >= time ) { + return $self->credentials; + } } my $creds; From d463e284e9504e4ddd1dd7216fe9aa45f346ceeb Mon Sep 17 00:00:00 2001 From: Keith Duncan Date: Tue, 29 Apr 2025 15:24:09 +0100 Subject: [PATCH 26/26] Replace implementation of refresh with handles and move with to the end of the file --- lib/Paws/Credential/ProviderChain.pm | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/Paws/Credential/ProviderChain.pm b/lib/Paws/Credential/ProviderChain.pm index 42bd527851..8e5cfbf0ee 100644 --- a/lib/Paws/Credential/ProviderChain.pm +++ b/lib/Paws/Credential/ProviderChain.pm @@ -1,8 +1,6 @@ package Paws::Credential::ProviderChain; use Moose; - with 'Paws::Credential'; - has providers => ( is => 'ro', isa => 'ArrayRef[Str]', @@ -19,13 +17,9 @@ package Paws::Credential::ProviderChain; has selected_provider => ( is => 'rw', does => 'Paws::Credential', + handles => [ 'refresh' ], ); - sub refresh { - my ($self) = @_; - return $self->selected_provider->refresh; - } - sub BUILD { my ($self) = @_; foreach my $prov (@{ $self->providers }) { @@ -39,6 +33,8 @@ package Paws::Credential::ProviderChain; # Tried all the providers... none got creds die "Can't find any credentials. I tried with " . (join ',', @{ $self->providers }) } + + with 'Paws::Credential'; 1; ### main pod documentation begin ###