Skip to content

Commit a4ec790

Browse files
authored
Merge pull request #29 from phulien/main
Support generate presigned URL with tagging
2 parents 0429920 + f608b12 commit a4ec790

File tree

1 file changed

+55
-3
lines changed

1 file changed

+55
-3
lines changed

src/aws_signature.erl

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,14 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
224224
%% a fixed digest value, such as "UNSIGNED-PAYLOAD", when sending requests without
225225
%% signing the body, <strong>which is expected for S3</strong>.
226226
%% </dd>
227+
%% <dt>`tags'</dt>
228+
%% <dd>
229+
%% Optional tagging of the object when generating a pre-signed URL.
230+
%% The value of `tags' is a binary() in the format, for example:
231+
%% `<<"key1=value1&key2=value2">>'. The actual request to put or get the object
232+
%% must use the exact `tags' value to ensure the signature is calculated
233+
%% correctly.
234+
%% </dd>
227235
%% </dl>
228236
-spec sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, Options) -> FinalURL
229237
when AccessKeyID :: binary(),
@@ -239,7 +247,8 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
239247
| {session_token, binary()}
240248
| {ttl, non_neg_integer()}
241249
| {body, binary()}
242-
| {body_digest, binary()},
250+
| {body_digest, binary()}
251+
| {tags, binary()},
243252
FinalURL :: binary().
244253
sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, Options)
245254
when is_binary(AccessKeyID),
@@ -253,6 +262,7 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
253262
URIEncodePath = proplists:get_value(uri_encode_path, Options, true),
254263
TimeToLive = proplists:get_value(ttl, Options, 86400),
255264
SessionToken = proplists:get_value(session_token, Options, undefined),
265+
Tags = proplists:get_value(tags, Options, undefined),
256266
BodyDigest =
257267
case proplists:get_value(body_digest, Options, undefined) of
258268
undefined ->
@@ -263,7 +273,13 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
263273
end,
264274
BaseParams =
265275
[{<<"X-Amz-Algorithm">>, <<"AWS4-HMAC-SHA256">>},
266-
{<<"X-Amz-SignedHeaders">>, <<"host">>}],
276+
{<<"X-Amz-SignedHeaders">>,
277+
if Tags == undefined ->
278+
<<"host">>;
279+
Tags =/= undefined ->
280+
<<"host%3Bx-amz-tagging">>
281+
end}
282+
],
267283

268284
URLMap = aws_signature_utils:parse_url(URL),
269285
LongDate = format_datetime_long(DateTime),
@@ -276,9 +292,15 @@ sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Me
276292

277293
FinalQueryParams = add_date_header(FinalQueryParams2, LongDate),
278294
HostHeader = host_header_from_url(URLMap),
295+
Headers =
296+
if Tags == undefined ->
297+
[HostHeader];
298+
Tags =/= undefined ->
299+
[HostHeader, {<<"X-Amz-Tagging">>, Tags}]
300+
end,
279301

280302
CanonicalRequest =
281-
canonical_request(Method, URLMap, [HostHeader], BodyDigest, URIEncodePath, FinalQueryParams),
303+
canonical_request(Method, URLMap, Headers, BodyDigest, URIEncodePath, FinalQueryParams),
282304

283305
HashedCanonicalRequest = aws_signature_utils:sha256_hexdigest(CanonicalRequest),
284306
SigningKey = signing_key(SecretAccessKey, ShortDate, Region, Service),
@@ -1055,6 +1077,36 @@ sign_v4_query_params_with_authority_well_known_port_test() ->
10551077

10561078
?assertEqual(Expected, Actual).
10571079

1080+
sign_v4_query_params_with_tagging_test() ->
1081+
AccessKeyID = <<"AKIAIOSFODNN7EXAMPLE">>,
1082+
SecretAccessKey = <<"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY">>,
1083+
Region = <<"us-east-1">>,
1084+
Service = <<"s3">>,
1085+
DateTime = {{2013, 5, 24}, {0, 0, 0}},
1086+
Method = <<"GET">>,
1087+
URL = <<"https://examplebucket.s3.amazonaws.com/test.txt">>,
1088+
1089+
Expected =
1090+
<<"https://examplebucket.s3.amazonaws.com/test.txt?",
1091+
"X-Amz-Algorithm=AWS4-HMAC-SHA256&",
1092+
"X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request&",
1093+
"X-Amz-Date=20130524T000000Z&",
1094+
"X-Amz-Expires=86400&",
1095+
"X-Amz-Signature=5c14ef7998d657c3b8293b37abefaef5fa98cc775bcbfffdb2027f4ce05772ef&",
1096+
"X-Amz-SignedHeaders=host%3Bx-amz-tagging">>,
1097+
1098+
Actual =
1099+
sign_v4_query_params(AccessKeyID,
1100+
SecretAccessKey,
1101+
Region,
1102+
Service,
1103+
DateTime,
1104+
Method,
1105+
URL,
1106+
[{tags, <<"key1=value1&key2=value2">>}]),
1107+
1108+
?assertEqual(Expected, Actual).
1109+
10581110
format_date_long_test() ->
10591111
Expected = <<"20210126T200815Z">>,
10601112
Actual = format_datetime_long({{2021,1,26}, {20,8,15}}),

0 commit comments

Comments
 (0)