AWS-S3

 view release on metacpan or  search on metacpan

lib/AWS/S3/Signer/V4.pm  view on Meta::CPAN

    my $self = shift;
    my ( $request, $region, $payload_sha256_hex ) = @_;
    return if $request->header('Authorization');    # don't overwrite

    my $datetime = $self->_datetime($request);

    unless ( $request->header('host') ) {
        my $host = $request->uri->host;
        $request->header( host => $host );
    }

    my $scope = $self->_scope( $request, $region );
    my ( $date, $service );
    ( $date, $region, $service ) = $self->_parse_scope($scope);

    my $secret_key = $self->secret_key;
    my $access_key = $self->access_key;
    my $algorithm  = $self->_algorithm;

    my ( $hashed_request, $signed_headers ) =
      $self->_hash_canonical_request( $request, $payload_sha256_hex );
    my $string_to_sign =
      $self->_string_to_sign( $datetime, $scope, $hashed_request );
    my $signature =
      $self->_calculate_signature( $secret_key, $service, $region, $date,
        $string_to_sign );
    $request->header( Authorization =>
"$algorithm Credential=$access_key/$scope, SignedHeaders=$signed_headers, Signature=$signature"
    );
}

sub _zulu_time {
    my $self     = shift;
    my $request  = shift;
    my $date     = $request->header('Date');
    my @datetime = $date ? gmtime( str2time($date) ) : gmtime();
    return strftime( '%Y%m%dT%H%M%SZ', @datetime );
}

sub _hash_canonical_request {
    my $self = shift;
    my ( $request, $hashed_payload ) =
      @_;    # (HTTP::Request,sha256_hex($content))
    my $method  = $request->method;
    my $uri     = $request->uri;
    my $path    = $uri->path || '/';
    my @params  = $uri->query_form;
    my $headers = $request->headers;
    $hashed_payload ||= sha256_hex( $request->content );

    # canonicalize query string

    # in the case of the S3 api, but its still expected to be part of a
    # canonical request.
    if (scalar(@params) == 0 && defined($uri->query) && $uri->query ne '') {
        push @params, ($uri->query, '');
    }

    my %canonical;
    while ( my ( $key, $value ) = splice( @params, 0, 2 ) ) {
        $key   = uri_escape($key);
        $value = uri_escape($value);
        push @{ $canonical{$key} }, $value;
    }
    my $canonical_query_string = join '&', map {
        my $key = $_;
        map { "$key=$_" } sort @{ $canonical{$key} }
    } sort keys %canonical;

    # canonicalize the request headers
    my ( @canonical, %signed_fields );
    for my $header ( sort map { lc } $headers->header_field_names ) {
        next if $header =~ /^date$/i;
        my @values = $headers->header($header);

        # remove redundant whitespace
        foreach (@values) {
            next if /^".+"$/;
            s/^\s+//;
            s/\s+$//;
            s/(\s)\s+/$1/g;
        }
        push @canonical, "$header:" . join( ',', @values );
        $signed_fields{$header}++;
    }
    my $canonical_headers = join "\n", @canonical;
    $canonical_headers .= "\n";
    my $signed_headers = join ';', sort map { lc } keys %signed_fields;

    my $canonical_request = join( "\n",
        $method,            $path,           $canonical_query_string,
        $canonical_headers, $signed_headers, $hashed_payload );
    my $request_digest = sha256_hex($canonical_request);

    return ( $request_digest, $signed_headers );
}

sub _string_to_sign {
    my $self = shift;
    my ( $datetime, $credential_scope, $hashed_request ) = @_;
    return join( "\n",
        'AWS4-HMAC-SHA256', $datetime, $credential_scope, $hashed_request );
}

=item $signing_key = AWS::S3::Signer::V4->signing_key($secret_access_key,$service_name,$region,$date)

Return just the signing key in the event you wish to roll your own signature.

=cut

sub signing_key {
    my $self = shift;
    my ( $kSecret, $service, $region, $date ) = @_;
    my $kDate    = hmac_sha256( $date,          'AWS4' . $kSecret );
    my $kRegion  = hmac_sha256( $region,        $kDate );
    my $kService = hmac_sha256( $service,       $kRegion );
    my $kSigning = hmac_sha256( 'aws4_request', $kService );
    return $kSigning;
}

sub _calculate_signature {
    my $self = shift;



( run in 0.911 second using v1.01-cache-2.11-cpan-39bf76dae61 )