Skip to content

Commit

Permalink
Merge pull request #18 from UnrealAkama/master
Browse files Browse the repository at this point in the history
Adding support for s3 presigned urls.
  • Loading branch information
andersfugmann authored Mar 3, 2019
2 parents 33b6d24 + d54b97a commit 22a0e83
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
49 changes: 49 additions & 0 deletions aws-s3/authorization.ml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,55 @@ let make_auth_header ~credentials ~scope ~signed_headers ~signature =
signed_headers
signature

let make_presigned_url ?(scheme=`Https) ~credentials ~date ~region ~path ~bucket ~verb ~duration () =
let service = "s3" in
let ((y, m, d), ((h, mi, s), _)) = Ptime.to_date_time date in
let verb = match verb with
| `Get -> "GET"
| `Put -> "PUT" in
let scheme = match scheme with
| `Http -> "http"
| `Https -> "https" in
let date = sprintf "%02d%02d%02d" y m d in
let time = sprintf "%02d%02d%02d" h mi s in
let host = sprintf "%s.s3.amazonaws.com" bucket in
let duration = string_of_int duration in
let region = Region.to_string region in
let headers = Headers.singleton "Host" host in
let query = [
("X-Amz-Algorithm", "AWS4-HMAC-SHA256");
("X-Amz-Credential", sprintf "%s/%s/%s/s3/aws4_request" credentials.Credentials.access_key date region);
("X-Amz-Date", sprintf "%sT%sZ" date time);
("X-Amz-Expires", duration);
("X-Amz-SignedHeaders", "host");
] in
let scope = make_scope ~date ~region ~service in
let signing_key = make_signing_key ~date ~region ~service ~credentials () in
let signature, _signed_headers =
make_signature ~date ~time ~verb ~path ~headers ~query ~signing_key ~scope ~payload_sha:"UNSIGNED-PAYLOAD"
in
let query =
("X-Amz-Signature", signature) :: query
|> List.map ~f:(fun (k, v) -> (k, [v]))
in
Uri.make ~scheme ~host ~path ~query ()

let%test "presigned_url" =
let credentials = Credentials.make
~access_key:"AKIAIOSFODNN7EXAMPLE"
~secret_key:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
()
in
let date = match Ptime.of_date (2013, 5, 24) with Some x -> x | _ -> Ptime.epoch in
let region = Region.of_string "us-east-1" in
let path = "/test.txt" in
let bucket = "examplebucket" in
let verb = `Get in
let duration = 86400 in
let expected = "https://examplebucket.s3.amazonaws.com/test.txt?X-Amz-Signature=aeeed9bbccd4d02ee5c0109b86d86835f995330da4c265957d157751f604d404&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request&X-Amz-Date=20130524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host" in
let actual = make_presigned_url ~credentials ~date ~region ~path ~bucket ~verb ~duration () |> Uri.to_string in
expected = actual

let%test "signing key" =
let credentials = Credentials.make
~access_key:"AKIAIOSFODNN7EXAMPLE"
Expand Down
13 changes: 13 additions & 0 deletions aws-s3/authorization.mli
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,16 @@ val chunk_signature:
previous_signature:string ->
sha:Digestif.SHA256.t -> Digestif.SHA256.t
(**/**)

(** This makes a presigned url that can be used to upload or download a file from s3 without any credentials other than those embedded in the url. [verb] should be either the string GET for download or PUT for upload.*)
val make_presigned_url :
?scheme:[`Http | `Https] ->
credentials:Credentials.t ->
date:Ptime.t ->
region:Region.t ->
path:string ->
bucket:string ->
verb:[`Get | `Put] ->
duration:int ->
unit ->
Uri.t
1 change: 1 addition & 0 deletions aws-s3/aws_s3.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ module S3 = S3
module Types = Types
module Credentials = Credentials
module Region = Region
module Authorization = Authorization

0 comments on commit 22a0e83

Please sign in to comment.