nixpkgs/pkgs/development/perl-modules/net-amazon-s3-credentials-provider.patch

292 lines
9.6 KiB
Diff

commit 4afa16864ac8ae23a450abf95db023b0c8bea698
Author: Shea Levy <shea@shealevy.com>
Date: Thu Aug 29 07:09:34 2013 -0400
Use CredentialsProviders à la the Java API
Signed-off-by: Shea Levy <shea@shealevy.com>
diff --git a/lib/Net/Amazon/Auth/CredentialsProvider.pm b/lib/Net/Amazon/Auth/CredentialsProvider.pm
new file mode 100755
index 0000000..527acae
--- /dev/null
+++ b/lib/Net/Amazon/Auth/CredentialsProvider.pm
@@ -0,0 +1,9 @@
+package Net::Amazon::Auth::CredentialsProvider;
+
+use Moose::Role 0.85;
+
+requires 'get_credentials';
+
+sub refresh { }
+
+1;
diff --git a/lib/Net/Amazon/Auth/CredentialsProviderChain.pm b/lib/Net/Amazon/Auth/CredentialsProviderChain.pm
new file mode 100755
index 0000000..85cd8e0
--- /dev/null
+++ b/lib/Net/Amazon/Auth/CredentialsProviderChain.pm
@@ -0,0 +1,41 @@
+package Net::Amazon::Auth::CredentialsProviderChain;
+
+use Moose 0.85;
+use MooseX::StrictConstructor 0.16;
+use Net::Amazon::Auth::EnvironmentVariableCredentialsProvider;
+use Net::Amazon::Auth::InstanceProfileCredentialsProvider;
+
+with 'Net::Amazon::Auth::CredentialsProvider';
+
+has 'providers' => ( is => 'ro', isa => 'ArrayRef[Net::Amazon::Auth::CredentialsProvider]', required => 1 );
+
+sub refresh {
+ my $self = shift;
+
+ map { $_->refresh } @{$self->providers};
+}
+
+sub get_credentials {
+ my $self = shift;
+
+ foreach my $provider (@{$self->providers}) {
+ my $res = $provider->get_credentials;
+ if (defined $res->{access_key_id}) {
+ return $res;
+ }
+ }
+
+ return {};
+}
+
+sub default_chain {
+ my $class = shift;
+ return $class->new(providers => [
+ Net::Amazon::Auth::EnvironmentVariableCredentialsProvider->new,
+ Net::Amazon::Auth::InstanceProfileCredentialsProvider->new
+ ]);
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/lib/Net/Amazon/Auth/EnvironmentVariableCredentialsProvider.pm b/lib/Net/Amazon/Auth/EnvironmentVariableCredentialsProvider.pm
new file mode 100755
index 0000000..ac38a84
--- /dev/null
+++ b/lib/Net/Amazon/Auth/EnvironmentVariableCredentialsProvider.pm
@@ -0,0 +1,26 @@
+package Net::Amazon::Auth::EnvironmentVariableCredentialsProvider;
+
+use Moose 0.85;
+use MooseX::StrictConstructor 0.16;
+
+extends 'Net::Amazon::Auth::FixedCredentialsProvider';
+
+around BUILDARGS => sub {
+ my $orig = shift;
+ my $class = shift;
+
+ my %args = (
+ access_key_id => $ENV{AWS_ACCESS_KEY_ID},
+ secret_access_key => $ENV{AWS_SECRET_ACCESS_KEY}
+ );
+
+ if (exists $ENV{AWS_SESSION_TOKEN}) {
+ $args{session_token} = $ENV{AWS_SESSION_TOKEN};
+ }
+
+ return $class->$orig(\%args);
+};
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/lib/Net/Amazon/Auth/FixedCredentialsProvider.pm b/lib/Net/Amazon/Auth/FixedCredentialsProvider.pm
new file mode 100755
index 0000000..21d56c7
--- /dev/null
+++ b/lib/Net/Amazon/Auth/FixedCredentialsProvider.pm
@@ -0,0 +1,23 @@
+package Net::Amazon::Auth::FixedCredentialsProvider;
+
+use Moose 0.85;
+use MooseX::StrictConstructor 0.16;
+
+with 'Net::Amazon::Auth::CredentialsProvider';
+
+has 'access_key_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 );
+has 'secret_access_key' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 );
+has 'session_token' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 );
+
+sub get_credentials {
+ my $self = shift;
+ return {
+ access_key_id => $self->access_key_id,
+ secret_access_key => $self->secret_access_key,
+ session_token => $self->session_token
+ };
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/lib/Net/Amazon/Auth/InstanceProfileCredentialsProvider.pm b/lib/Net/Amazon/Auth/InstanceProfileCredentialsProvider.pm
new file mode 100755
index 0000000..b9f826a
--- /dev/null
+++ b/lib/Net/Amazon/Auth/InstanceProfileCredentialsProvider.pm
@@ -0,0 +1,57 @@
+package Net::Amazon::Auth::InstanceProfileCredentialsProvider;
+
+use Moose 0.85;
+use MooseX::StrictConstructor 0.16;
+use HTTP::Date;
+use JSON;
+
+with 'Net::Amazon::Auth::CredentialsProvider';
+
+has '_ua' => ( is => 'rw', isa => 'LWP::UserAgent', required => 0 );
+has '_access_key_id' => ( is => 'rw', isa => 'Str', required => 0 );
+has '_secret_access_key' => ( is => 'rw', isa => 'Str', required => 0 );
+has '_session_token' => ( is => 'rw', isa => 'Str', required => 0 );
+has '_expiration_date' => ( is => 'rw', isa => 'Int', required => 0, default => 0 );
+
+sub BUILD {
+ my $self = shift;
+ my $ua = LWP::UserAgent->new;
+ $ua->timeout(10);
+ $self->_ua($ua);
+}
+
+sub refresh {
+ my $self = shift;
+
+ my $role_name_response =
+ $self->_ua->get("http://169.254.169.254/latest/meta-data/iam/security-credentials/");
+ if ($role_name_response->code == 200) {
+ my $credentials_response = $self->_ua->get("http://169.254.169.254/latest/meta-data/iam/security-credentials/" . $role_name_response->content);
+
+ if ($credentials_response->code == 200) {
+ my $credentials = decode_json($credentials_response->content);
+ $self->_expiration_date(str2time($credentials->{Expiration}));
+ $self->_access_key_id($credentials->{AccessKeyId});
+ $self->_secret_access_key($credentials->{SecretAccessKey});
+ $self->_session_token($credentials->{Token});
+ }
+ }
+}
+
+sub get_credentials {
+ my $self = shift;
+
+ if (time() - $self->_expiration_date > -5 * 60) { #Credentials available 5 minutes before expiry
+ $self->refresh;
+ }
+
+ return {
+ access_key_id => $self->_access_key_id,
+ secret_access_key => $self->_secret_access_key,
+ session_token => $self->_session_token
+ };
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/lib/Net/Amazon/S3.pm b/lib/Net/Amazon/S3.pm
index 907113e..a369e4b 100755
--- a/lib/Net/Amazon/S3.pm
+++ b/lib/Net/Amazon/S3.pm
@@ -133,9 +133,10 @@ use LWP::UserAgent::Determined;
use URI::Escape qw(uri_escape_utf8);
use XML::LibXML;
use XML::LibXML::XPathContext;
+use Net::Amazon::Auth::FixedCredentialsProvider;
+use Net::Amazon::Auth::CredentialsProviderChain;
-has 'aws_access_key_id' => ( is => 'ro', isa => 'Str', required => 1 );
-has 'aws_secret_access_key' => ( is => 'ro', isa => 'Str', required => 1 );
+has 'credentials_provider' => ( is => 'ro', isa => 'Net::Amazon::Auth::CredentialsProvider', required => 0, default => sub { return Net::Amazon::Auth::CredentialsProviderChain->default_chain; } );
has 'secure' => ( is => 'ro', isa => 'Bool', required => 0, default => 0 );
has 'timeout' => ( is => 'ro', isa => 'Num', required => 0, default => 30 );
has 'retry' => ( is => 'ro', isa => 'Bool', required => 0, default => 0 );
@@ -144,7 +145,23 @@ has 'libxml' => ( is => 'rw', isa => 'XML::LibXML', required => 0 );
has 'ua' => ( is => 'rw', isa => 'LWP::UserAgent', required => 0 );
has 'err' => ( is => 'rw', isa => 'Maybe[Str]', required => 0 );
has 'errstr' => ( is => 'rw', isa => 'Maybe[Str]', required => 0 );
-has 'aws_session_token' => ( is => 'ro', isa => 'Str', required => 0 );
+
+around BUILDARGS => sub {
+ my $orig = shift;
+ my $class = shift;
+
+ my $args = $class->$orig(@_);
+
+ if (exists $args->{aws_access_key_id}) {
+ $args->{credentials_provider} = Net::Amazon::Auth::FixedCredentialsProvider->new({
+ access_key_id => $args->{aws_access_key_id},
+ secret_access_key => $args->{aws_secret_access_key},
+ session_token => $args->{aws_session_token}
+ });
+ delete @{$args}{qw(aws_access_key_id aws_secret_access_key aws_session_token)};
+ }
+ return $args;
+};
__PACKAGE__->meta->make_immutable;
@@ -223,6 +240,24 @@ sub BUILD {
$self->ua($ua);
$self->libxml( XML::LibXML->new );
+
+ die "No AWS credentials found!" unless defined $self->credentials_provider->get_credentials->{access_key_id};
+}
+
+# Backwards compatibility
+sub aws_access_key_id {
+ my $self = shift;
+ return $self->credentials_provider->get_credentials->{access_key_id};
+}
+
+sub aws_secret_access_key {
+ my $self = shift;
+ return $self->credentials_provider->get_credentials->{secret_access_key};
+}
+
+sub aws_session_token {
+ my $self = shift;
+ return $self->credentials_provider->get_credentials->{session_token};
}
=head2 buckets
diff --git a/lib/Net/Amazon/S3/HTTPRequest.pm b/lib/Net/Amazon/S3/HTTPRequest.pm
index 69c6327..d49e95b 100755
--- a/lib/Net/Amazon/S3/HTTPRequest.pm
+++ b/lib/Net/Amazon/S3/HTTPRequest.pm
@@ -63,8 +63,9 @@ sub query_string_authentication_uri {
my $path = $self->path;
my $headers = $self->headers;
- my $aws_access_key_id = $self->s3->aws_access_key_id;
- my $aws_secret_access_key = $self->s3->aws_secret_access_key;
+ my $creds = $self->s3->credentials_provider->get_credentials;
+ my $aws_access_key_id = $creds->{access_key_id};
+ my $aws_secret_access_key = $creds->{secret_access_key};
my $canonical_string
= $self->_canonical_string( $method, $path, $headers, $expires );
my $encoded_canonical
@@ -86,9 +87,10 @@ sub query_string_authentication_uri {
sub _add_auth_header {
my ( $self, $headers, $method, $path ) = @_;
- my $aws_access_key_id = $self->s3->aws_access_key_id;
- my $aws_secret_access_key = $self->s3->aws_secret_access_key;
- my $aws_session_token = $self->s3->aws_session_token;
+ my $creds = $self->s3->credentials_provider->get_credentials;
+ my $aws_access_key_id = $creds->{access_key_id};
+ my $aws_secret_access_key = $creds->{secret_access_key};
+ my $aws_session_token = $creds->{session_token};
if ( not $headers->header('Date') ) {
$headers->header( Date => time2str(time) );