AWS-Signature-V4

 view release on metacpan or  search on metacpan

t/basic.t  view on Meta::CPAN

);
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";

t/basic.t  view on Meta::CPAN

            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 )