Current section
Files
Jump to
Current section
Files
src/aws_rds_iam_token.erl
-module(aws_rds_iam_token).
-export([rds_token_create/4]).
-define(SIGNING_ID, <<"rds-db">>).
-define(EMPTY_PAYLOAD_HASH, <<"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855">>).
%%====================================================================
%% API
%%====================================================================
-spec rds_token_create(aws_client:aws_client(), binary(), non_neg_integer(), binary()) -> {ok, binary()}.
rds_token_create(Client, DBEndpoint, DBPort, DBUser) when is_map(Client) andalso
is_binary(DBEndpoint) andalso
is_integer(DBPort) andalso
is_binary(DBUser) ->
Method = <<"GET">>,
QueryParams = [{<<"Action">>, <<"connect">>}, {<<"DBUser">>, DBUser}],
Endpoint = <<"https://", DBEndpoint/binary, ":", (integer_to_binary(DBPort))/binary>>,
Url = aws_request:add_query(Endpoint, QueryParams),
AccessKeyID = aws_client:access_key_id(Client),
SecurityToken = aws_client:token(Client),
SecretAccessKey = aws_client:secret_access_key(Client),
Region = aws_client:region(Client),
Now = calendar:universal_time(),
Options0 = [ {ttl, timer:minutes(15) div 1000} %% Time in seconds
, {body_digest, ?EMPTY_PAYLOAD_HASH}
, {uri_encode_path, false} %% We already encode in build_path/4
],
Options = case SecurityToken of
undefined ->
Options0;
_ ->
[{session_token, hackney_url:urlencode(SecurityToken)} | Options0]
end,
<<"https://", SignedUrl/binary>> = aws_signature:sign_v4_query_params(AccessKeyID, SecretAccessKey, Region, ?SIGNING_ID, Now, Method, Url, Options),
{ok, SignedUrl}.
%%====================================================================
%% Unit tests
%%====================================================================
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-include_lib("hackney/include/hackney_lib.hrl").
fetch_auth_token_test() ->
Client = aws_client:make_temporary_client(<<"AccessKeyID">>, <<"SecretAccessKey">>,
<<"Token">>, <<"eu-west-1">>),
{ok, Url} = rds_token_create(Client, <<"db_endpoint">>, 5432, <<"db_user">>),
HackneyUrl = hackney_url:parse_url(Url),
ParsedQs = hackney_url:parse_qs(HackneyUrl#hackney_url.qs),
Credential = proplists:get_value(<<"X-Amz-Credential">>, ParsedQs),
[AccessKeyId, _ShortDate, Region, Service, Request] = binary:split(Credential, <<"/">>, [global]),
?assertEqual(5432, HackneyUrl#hackney_url.port),
?assertEqual("db_endpoint", HackneyUrl#hackney_url.host),
?assertEqual(<<"">>, HackneyUrl#hackney_url.path),
?assertEqual(9, length(ParsedQs)),
?assertEqual(<<"AccessKeyID">>, AccessKeyId),
?assertEqual(<<"eu-west-1">>, Region),
?assertEqual(<<"rds-db">>, Service),
?assertEqual(<<"aws4_request">>, Request),
?assertEqual(<<"AWS4-HMAC-SHA256">>, proplists:get_value(<<"X-Amz-Algorithm">>, ParsedQs)),
?assertEqual(<<"900">>, proplists:get_value(<<"X-Amz-Expires">>, ParsedQs)),
?assertEqual(<<"Token">>, proplists:get_value(<<"X-Amz-Security-Token">>, ParsedQs)),
?assertEqual(<<"host">>, proplists:get_value(<<"X-Amz-SignedHeaders">>, ParsedQs)).
-endif.