AWS-Signature-V4
view release on metacpan or search on metacpan
);
my $r = $s->sign(
method => 'GET',
url => 'https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08',
headers => {'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'},
time => 1440938160, # 20150830T123600Z
);
is $r->{signature},
'5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7',
'HMAC signature matches AWS docs';
is $r->{signed_headers}, 'content-type;host;x-amz-date', 'signed headers';
# X.509 variant: verify with openssl itself
SKIP: {
my $dir = tempdir(CLEANUP => 1);
skip 'openssl not available', 20 if system("openssl version >/dev/null 2>&1");
for my $alg (qw< RSA ECDSA >) {
my $genkey = $alg eq 'RSA'
? "openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048"
: "openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256";
system("$genkey -out $dir/$alg.key 2>/dev/null") == 0 or die "genkey";
time => 1440938160);
ok $verifies->($te->{string_to_sign}, $te->{signature}),
"$alg encrypted $opt signature verifies";
}
is dies { AWS::Signature::V4->new(service => 'x', region => 'y', x509 => {
key_type => $alg, certificate_file => "$dir/$alg.pem",
private_key_file => "$dir/$alg.enc", private_key_password => 'wrong'}) },
object { prop blessed => 'Ouch'; call code => 400 },
"$alg wrong password is rejected";
like $t->{authorization},
qr{^AWS4-X509-$alg-SHA256 Credential=\d+/20150830/eu-west-1/rolesanywhere/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-x509, Signature=[0-9a-f]+$},
"$alg authorization shape";
my $serial = qx{openssl x509 -in $dir/$alg.pem -noout -serial};
my ($hex) = $serial =~ /serial=(\w+)/;
my ($got) = $t->{authorization} =~ /Credential=(\d+)\//;
is $got, Math::BigInt->from_hex($hex)->bstr, "$alg serial decimal";
ok $verifies->($t->{string_to_sign}, $t->{signature}), "$alg signature verifies";
}
}
done_testing;
t/canonical.t view on Meta::CPAN
# names that differ only in case are joined in a repeatable order
is req($std, 'https://h/', headers => {'X-Foo' => 'a', 'x-foo' => 'b', 'X-FOO' => 'c'})
->{headers}{'x-foo'}, 'c,a,b', 'sorted by name as given';
};
subtest 'x-amz-* headers are always signed' => sub {
my $t = AWS::Signature::V4->new(service => 's3', region => 'r',
credentials => {%cred, session_token => 'TOK'});
my $r = $t->sign(method => 'PUT', url => 'https://b.s3.amazonaws.com/k', time => 0,
headers => {'Content-Type' => 'text/plain', 'X-Amz-Acl' => 'private'},
signed_headers => ['content-type'], body => 'abc');
is $r->{signed_headers},
'content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date;x-amz-security-token',
'those given and those added by sign';
is req($std, 'https://h/', signed_headers => [])->{signed_headers}, 'host;x-amz-date',
'even with an empty list';
};
subtest 'payload' => sub {
my $empty = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
my $r = req($std, 'https://h/');
like $r->{canonical_request}, qr/\n$empty\z/, 'empty body';
ok !exists $r->{headers}{'x-amz-content-sha256'}, 'no payload header outside S3';
t/presign.t view on Meta::CPAN
$r = $iam->presign(url => 'https://h/', unsigned_payload => 1, time => 0);
like $r->{canonical_request}, qr/\nUNSIGNED-PAYLOAD\z/, 'unsigned_payload';
my $abc = sha256_hex('abc');
$r = $iam->presign(url => 'https://h/', payload_hash => $abc, time => 0);
like $r->{canonical_request}, qr/\n$abc\z/, 'payload_hash';
$r = $iam->presign(url => 'https://h/', body => 'abc', method => 'put', time => 0);
like $r->{canonical_request}, qr/\APUT\n.*\nba7816bf/s, 'method and body hash';
# extra signed headers
$r = $iam->presign(url => 'https://h/', headers => {'Content-Type' => 'x/y'},
signed_headers => ['content-type', 'host'], time => 0);
is $r->{signed_headers}, 'content-type;host', 'explicit signed headers';
like $r->{url}, qr/X-Amz-SignedHeaders=content-type%3Bhost/, 'encoded in the query';
is dies { $iam->presign(url => 'https://h/', signed_headers => ['nope']) },
bad(qr/missing header/), 'missing header croaks';
# x-amz-* headers given are always signed, as AWS wants
$r = $s3->presign(url => 'https://b.s3.amazonaws.com/k', method => 'PUT', time => 0,
headers => {'x-amz-acl' => 'public-read'});
is $r->{signed_headers}, 'host;x-amz-acl', 'x-amz-* header signed';
is $r->{headers}, {host => 'b.s3.amazonaws.com', 'x-amz-acl' => 'public-read'},
'and to be sent';
( run in 1.601 second using v1.01-cache-2.11-cpan-03fa5a55a2b )