77% %% Created : 1 Feb 2017 by Mike Watters <[email protected] >88-module (awsv4 ).
99
10- -export ([headers /2 , headers /3 , headers / 11 , canonical_query /1 , long_term_credentials /2 ,
10+ -export ([headers /2 , headers /3 , canonical_query /1 , long_term_credentials /2 ,
1111 credentials_from_plist /1 , isonow /0 , isonow /1 ]).
12+ -export ([credentials_from_tuple /1 , is_aws_credentials /1 , credentials_expiration /1 ]).
1213
13- -include (" erliam.hrl" ).
14+ -record (credentials ,
15+ {expiration :: undefined | erliam :iso_datetime (),
16+ security_token :: undefined | string (), % required when using temporary credentials
17+ secret_access_key :: string (),
18+ access_key_id :: string ()}).
1419
15- -type credentials () :: # credentials {}.
16-
17- -export_type ([credentials / 0 ]).
20+ -opaque credentials () :: # credentials {}.
1821
22+ -type datetime () :: string (). % "YYYYMMDDTHHMMSSZ"
1923-type pairs () :: #{string () => iodata ()} | [{string (), iodata ()}].
2024
25+ -export_type ([credentials / 0 , datetime / 0 , pairs / 0 ]).
26+
2127% %%% API
2228
29+ % % @doc Function used to "convert" a tuple returned from an ets:lookup/2 call
30+ % % into a valid opaque term of type credentials/0.
31+ -spec credentials_from_tuple (tuple ()) -> credentials ().
32+ credentials_from_tuple (# credentials {} = Credentials ) ->
33+ Credentials .
34+
35+ -spec is_aws_credentials (any ()) -> boolean ().
36+ is_aws_credentials (# credentials {}) ->
37+ true ;
38+ is_aws_credentials (_ ) ->
39+ false .
40+
41+ -spec credentials_expiration (credentials ()) -> undefined | erliam :iso_datetime ().
42+ credentials_expiration (# credentials {expiration = ExpTime }) ->
43+ ExpTime .
44+
45+ -spec headers (credentials (), map ()) -> [{string (), iodata ()}].
2346headers (Credentials , Parameters ) ->
2447 headers (Credentials , Parameters , <<>>).
2548
49+ -spec headers (credentials (), map (), undefined | binary ()) -> [{string (), iodata ()}].
2650headers (Credentials , Parameters , undefined ) ->
2751 headers (Credentials , Parameters , <<>>);
2852headers (Credentials ,
@@ -38,31 +62,19 @@ headers(Credentials,
3862 host => join ($. , [Service , Region , " amazonaws.com" ])},
3963 headers_ (Credentials , maps :merge (Defaults , Parameters ), RequestPayload ).
4064
41- -spec headers (Credentials :: credentials (),
42- Service :: string (),
43- Region :: string (),
44- Host :: string (),
45- AwsDate :: undefined | aws_datetime (),
46- TargetAPI :: string () | undefined ,
47- Method :: string (),
48- Path :: string (),
49- QueryParams :: pairs (),
50- ExtraSignedHeaders :: pairs (),
51- RequestPayload :: binary ()) ->
52- [{HeaderName :: string (), HeaderValue :: iodata ()}].
53- headers (# credentials {secret_access_key = SecretAccessKey ,
54- access_key_id = AccessKeyId ,
55- security_token = SecurityToken },
56- Service ,
57- Region ,
58- Host ,
59- AwsDate ,
60- TargetAPI ,
61- Method ,
62- Path ,
63- QueryParams ,
64- ExtraSignedHeaders ,
65- RequestPayload ) ->
65+ headers_ (# credentials {secret_access_key = SecretAccessKey ,
66+ access_key_id = AccessKeyId ,
67+ security_token = SecurityToken },
68+ #{service := Service ,
69+ region := Region ,
70+ host := Host ,
71+ target_api := TargetAPI ,
72+ aws_date := AwsDate ,
73+ method := Method ,
74+ path := Path ,
75+ query_params := QueryParams ,
76+ signed_headers := ExtraSignedHeaders },
77+ RequestPayload ) ->
6678 ActualAwsDate =
6779 case AwsDate of
6880 undefined ->
@@ -133,7 +145,7 @@ headers(#credentials{secret_access_key = SecretAccessKey,
133145 {" x-amz-content-sha256" , PayloadHash }
134146 | Headers ].
135147
136- -spec isonow (calendar :datetime ()) -> aws_datetime ().
148+ -spec isonow (calendar :datetime ()) -> datetime ().
137149isonow ({{Year , Month , Day }, {Hour , Min , Sec }}) ->
138150 lists :flatten (
139151 io_lib :format (" ~4.10.0B~2.10.0B~2.10.0B T~2.10.0B~2.10.0B~2.10.0B Z" ,
@@ -165,29 +177,6 @@ credentials_from_plist(Plist) ->
165177
166178% %%% INTERNAL FUNCTIONS
167179
168- headers_ (Credentials ,
169- #{service := Service ,
170- region := Region ,
171- host := Host ,
172- target_api := TargetAPI ,
173- aws_date := AwsDate ,
174- method := Method ,
175- path := Path ,
176- query_params := QueryParams ,
177- signed_headers := ExtraSignedHeaders },
178- RequestPayload ) ->
179- headers (Credentials ,
180- Service ,
181- Region ,
182- Host ,
183- AwsDate ,
184- TargetAPI ,
185- Method ,
186- Path ,
187- QueryParams ,
188- ExtraSignedHeaders ,
189- RequestPayload ).
190-
191180canonical_path (Path ) ->
192181 % % note: should remove redundant and relative path components, except leave empty path
193182 % % components for s3.
@@ -255,24 +244,27 @@ join_test() ->
255244flattened (KVs ) ->
256245 [{K , lists :flatten (V )} || {K , V } <- KVs ].
257246
258- flattened_headers (Args ) ->
259- flattened (apply (? MODULE , headers , Args )).
247+ flattened_headers (Credentials , Parameters ) ->
248+ flattened (headers (Credentials , Parameters )).
249+
250+ flattened_headers (Credentials , Parameters , RequestPayload ) ->
251+ flattened (headers (Credentials , Parameters , RequestPayload )).
260252
261253basic_headers_test () ->
262254 Actual =
263- flattened_headers ([ # credentials {secret_access_key = " secretkey" ,
264- access_key_id = " accesskey" ,
265- security_token = " securitytoken" },
266- " kinesis" ,
267- " us-east-1" ,
268- " kinesis.us-east-1.amazonaws.com" ,
269- " 20140629T022822Z " ,
270- " Kinesis_20131202.ListStreams " ,
271- " POST" ,
272- " /" ,
273- [],
274- #{ },
275- " something" ] ),
255+ flattened_headers (# credentials {secret_access_key = " secretkey" ,
256+ access_key_id = " accesskey" ,
257+ security_token = " securitytoken" },
258+ #{ service => " kinesis" ,
259+ region => " us-east-1" ,
260+ host => " kinesis.us-east-1.amazonaws.com" ,
261+ target_api => " Kinesis_20131202.ListStreams " ,
262+ aws_date => " 20140629T022822Z " ,
263+ method => " POST" ,
264+ path => " /" ,
265+ query_params => [],
266+ signed_headers => #{} },
267+ " something" ),
276268 Expected =
277269 flattened ([{" authorization" ,
278270 [" AWS4-HMAC-SHA256 Credential=accesskey/20140629/us-east-1/kinesis/aws"
@@ -291,14 +283,14 @@ basic_headers_test() ->
291283aws4_example1_test () ->
292284 % % get-vanilla-query-order-key-case from AWSv4 test suite
293285 Actual =
294- flattened_headers ([ # credentials {secret_access_key =
295- " wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ,
296- access_key_id = " AKIDEXAMPLE" },
297- #{aws_date => " 20150830T123600Z" ,
298- service => " service" ,
299- region => " us-east-1" ,
300- host => " example.amazonaws.com" ,
301- query_params => #{" Param2" => " value2" , " Param1" => " value1" }}] ),
286+ flattened_headers (# credentials {secret_access_key =
287+ " wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ,
288+ access_key_id = " AKIDEXAMPLE" },
289+ #{aws_date => " 20150830T123600Z" ,
290+ service => " service" ,
291+ region => " us-east-1" ,
292+ host => " example.amazonaws.com" ,
293+ query_params => #{" Param2" => " value2" , " Param1" => " value1" }}),
302294 Expected =
303295 flattened ([{" authorization" ,
304296 [" AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/a"
@@ -315,15 +307,15 @@ aws4_example1_test() ->
315307aws4_example2_test () ->
316308 % % post-vanilla-query from AWSv4 test suite
317309 Actual =
318- flattened_headers ([ # credentials {secret_access_key =
319- " wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ,
320- access_key_id = " AKIDEXAMPLE" },
321- #{aws_date => " 20150830T123600Z" ,
322- service => " service" ,
323- region => " us-east-1" ,
324- host => " example.amazonaws.com" ,
325- method => " POST" ,
326- query_params => #{" Param1" => " value1" }}] ),
310+ flattened_headers (# credentials {secret_access_key =
311+ " wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ,
312+ access_key_id = " AKIDEXAMPLE" },
313+ #{aws_date => " 20150830T123600Z" ,
314+ service => " service" ,
315+ region => " us-east-1" ,
316+ host => " example.amazonaws.com" ,
317+ method => " POST" ,
318+ query_params => #{" Param1" => " value1" }}),
327319 Expected =
328320 flattened ([{" authorization" ,
329321 [" AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/a"
@@ -340,16 +332,16 @@ aws4_example2_test() ->
340332aws4_example3_test () ->
341333 % % get-unreserved from AWSv4 test suite
342334 Actual =
343- flattened_headers ([ # credentials {secret_access_key =
344- " wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ,
345- access_key_id = " AKIDEXAMPLE" },
346- #{aws_date => " 20150830T123600Z" ,
347- service => " service" ,
348- region => " us-east-1" ,
349- host => " example.amazonaws.com" ,
350- path =>
351- " /-._~0 123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
352- ++ " abcdefghijklmnopqrstuvwxyz" }] ),
335+ flattened_headers (# credentials {secret_access_key =
336+ " wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" ,
337+ access_key_id = " AKIDEXAMPLE" },
338+ #{aws_date => " 20150830T123600Z" ,
339+ service => " service" ,
340+ region => " us-east-1" ,
341+ host => " example.amazonaws.com" ,
342+ path =>
343+ " /-._~0 123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
344+ ++ " abcdefghijklmnopqrstuvwxyz" }),
353345 Expected =
354346 flattened ([{" authorization" ,
355347 [" AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/a"
0 commit comments