#!perl
use Mojo::Base -strict;
use Test::More;
use Mojo::JSON 'encode_json';
use Mojo::URL;
use Mojo::Headers;
use Mojo::Date;
use Mojo::UserAgent;
use lib 'lib';
use_ok 'Mojo::AWS';
use_ok 'Mojo::AWS::S3';
my $aws = Mojo::AWS->new(
service => 'iam',
region => 'us-east-1',
transactor => Mojo::UserAgent->new->transactor,
access_key => 'ACCESSKEY',
secret_key => 'SECRETKEY',
);
##
## canonical uri and query strings
##
## canonical uri
my $url = Mojo::URL->new('/documents and settings/');
is $aws->canonical_uri($url), '/documents%2520and%2520settings/', 'canonical uri';
$url = Mojo::URL->new('/');
is $aws->canonical_uri($url), '/', 'canonical empty uri';
## sorted parameters with multiple values
$url = Mojo::URL->new('/?b=21&b=3&a=1&c=3');
is $aws->canonical_query_string($url), 'a=1&b=21&b=3&c=3', 'canonical query string';
$url = Mojo::URL->new('/?b=b&b=d&a=f&a=a');
is $aws->canonical_query_string($url), 'a=a&a=f&b=b&b=d', 'canonical query string';
## URL encoded names and values
$url = Mojo::URL->new('/?joe+schmoe=good+boy');
is $aws->canonical_query_string($url), 'joe%20schmoe=good%20boy', 'canonical query string';
## don't encode safe characters
$url = Mojo::URL->new('/?a=A-force&a=a-force&b=B_force&b=b_force&c=C.force&d=D~force');
is $aws->canonical_query_string($url),
'a=A-force&a=a-force&b=B_force&b=b_force&c=C.force&d=D~force', 'canonical query string';
## canonical_uri for s3 objects
$aws = Mojo::AWS::S3->new(
service => 'iam',
region => 'us-east-1',
transactor => Mojo::UserAgent->new->transactor,
access_key => 'ACCESSKEY',
secret_key => 'SECRETKEY',
);
$url = Mojo::URL->new('/example bucket//myphoto.jpg'); ## Mojo::URL does most of our canonicalization for us
is $aws->canonical_uri($url), '/example%20bucket//myphoto.jpg', 'canonical s3 uri';
##
## headers
##
$aws = Mojo::AWS->new(
service => 'iam',
region => 'us-east-1',
transactor => Mojo::UserAgent->new->transactor,
access_key => 'ACCESSKEY',
secret_key => 'SECRETKEY',
);
## example from https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
my $headers = Mojo::Headers->new->parse(<<_HEADERS_);
Host:iam.amazonaws.com
Content-Type:application/x-www-form-urlencoded; charset=utf-8
My-header1: a b c
X-Amz-Date:20150830T123600Z
My-Header2: "a b c"
_HEADERS_
is $aws->canonical_headers($headers->to_hash(1)), <<_HEADERS_, "canonical headers";
content-type:application/x-www-form-urlencoded; charset=utf-8
host:iam.amazonaws.com
my-header1:a b c
my-header2:"a b c"
x-amz-date:20150830T123600Z
_HEADERS_
## example from https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
my $creq = qq{GET
/
Action=ListUsers&Version=2010-05-08
content-type:application/x-www-form-urlencoded; charset=utf-8
host:iam.amazonaws.com
x-amz-date:20150830T123600Z
content-type;host;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855};
$url = Mojo::URL->new('https://iam.amazonaws.com/?Version=2010-05-08&Action=ListUsers');
is $aws->canonical_request(
url => $url,
method => 'GET',
headers => {
'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
Host => 'iam.amazonaws.com',
'x-amz-date' => '20150830T123600Z'
},
signed_headers => [qw/content-type host x-amz-date/],
payload => ''
),
$creq, 'canonical request';
is $aws->canonical_request_hash($creq),
'f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59', 'canonical request hash';
##
## string to sign (step 2)
##
## example from https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
my $string_to_sign = qq{AWS4-HMAC-SHA256
20150830T123600Z
20150830/us-east-1/iam/aws4_request
f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59};
is $aws->string_to_sign(
datetime => '2015-08-30T12:36:00Z',
hash => 'f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59'
),
$string_to_sign, 'string to sign';
##
## calculate signature (step 3)
##
sub hexify {
join '' => map { unpack "H*" => $_ } split // => shift;
}
## example from https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
use Digest::SHA;
$aws = Mojo::AWS->new(
region => 'us-east-1',
service => 'iam',
transactor => Mojo::UserAgent->new->transactor,
access_key => 'ACCESSKEY',
secret_key => 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
);
my $signing_key = $aws->signing_key(datetime => '2015-08-30T12:36:00Z',);
is hexify($signing_key), 'c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9',
'signing key';
is $aws->signature(signing_key => $signing_key, string_to_sign => $string_to_sign),
'5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7', 'calculate signature';
$aws = Mojo::AWS->new(
region => 'us-east-1',
service => 'iam',
transactor => Mojo::UserAgent->new->transactor,
access_key => 'AKIDEXAMPLE',
secret_key => '',
);
is $aws->authorization_header(
credential_scope => '20150830/us-east-1/iam/aws4_request',
signed_headers => [qw/content-type host x-amz-date/],
signature => '5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7'
)->to_string,
'Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7',
'authorization header';
##
## signed HTTP request
##
$aws = Mojo::AWS->new(
region => 'us-east-2',
service => 'sns',
transactor => Mojo::UserAgent->new->transactor,
access_key => 'ACCESSKEY',
secret_key => 'SECRETKEY',
);
my $signed = $aws->signed_request(
method => 'POST',
datetime => Mojo::Date->new(1234567890),
url => Mojo::URL->new('https://sns.us-east-2.amazonaws.com'),
signed_headers => {'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'},
payload => [
form => {
Action => 'Publish',
TopicArn => 'arn:aws:sns:us-east-2:123456789012:my-topic',
Subject => 'Test Subject',
MessageStructure => 'json',
Message => encode_json({default => 'Default message', https => 'An HTTP message'}),
Version => '2010-03-31'
}
]
);
is $signed->req->headers->authorization . "\n", <<_HEADER_, 'authorization header';
AWS4-HMAC-SHA256 Credential=ACCESSKEY/20090213/us-east-2/sns/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=446f404455f7b65058223501857ef61f7d86d27056279ea06680bbb804d71001
_HEADER_
is $signed->req->body . "\n", <<_BODY_, 'signed request body';
Action=Publish&Message=%7B%22default%22%3A%22Default+message%22%2C%22https%22%3A%22An+HTTP+message%22%7D&MessageStructure=json&Subject=Test+Subject&TopicArn=arn%3Aaws%3Asns%3Aus-east-2%3A123456789012%3Amy-topic&Version=2010-03-31
_BODY_
done_testing();