Current section

Files

Jump to
elixir_bce_sdk lib auth bce_signer.ex
Raw

lib/auth/bce_signer.ex

defmodule ElixirBceSdk.Auth.BceSigner do
@moduledoc """
module about authorization
Reference https://cloud.baidu.com/doc/Reference/s/Njwvz1wot
"""
alias ElixirBceSdk.Auth.BceCredentials
import ElixirBceSdk.Utils
@bce_prefix "x-bce"
@authorization "authorization"
def get_canonical_headers(headers, nil),
do: get_canonical_headers(headers, ["host", "content-md5", "content-length", "content-type"])
def get_canonical_headers(headers, headers_to_sign) when is_list(headers_to_sign) do
canonical_headers = headers
|> Enum.filter(fn {k,v} ->
to_s_trim(v) != "" and (to_s_down(k) in headers_to_sign or to_s_down(k) |> String.starts_with?(@bce_prefix))
end)
ret_array = canonical_headers
|> Enum.map(fn {k,v} -> "#{to_s_down_encode(k)}:#{to_s_trim_encode(v)}" end)
|> Enum.sort
|> Enum.join("\n")
headers_array = canonical_headers
|> Enum.map(fn {k,_} -> to_s_down(k) end)
|> Enum.sort
{ ret_array, headers_array }
end
def get_canonical_uri_path(path) do
encoded_path = to_s_encode(path) |> String.replace("%2F", "/")
cond do
String.length(encoded_path) == 0 -> "/"
String.starts_with?(encoded_path, "/") -> encoded_path
true -> "/#{encoded_path}"
end
end
def get_canonical_querystring(nil, _), do: ""
def get_canonical_querystring(params, _) when map_size(params) == 0, do: ""
def get_canonical_querystring(params = %{}, for_signature) do
Enum.filter(params, fn {k, _} -> !for_signature || to_s_down(k) != @authorization end)
|> Enum.map(fn {k, v} -> "#{urlencode(to_string(k))}=#{urlencode(to_string(v))}" end)
|> Enum.join("&")
end
def sign(
credentials = %BceCredentials{},
http_method,
path,
headers,
params,
timestamp \\ nil,
expiration_in_seconds \\ 1800,
headers_to_sign \\ nil) do
timestamp = (if timestamp == nil, do: :os.system_time(:second), else: timestamp)
sign_date_time = DateTime.from_unix!(timestamp)
|> DateTime.to_iso8601
sign_key_info = "bce-auth-v1/#{credentials.access_key_id}/#{sign_date_time}/#{expiration_in_seconds}"
sign_key = :crypto.mac(:hmac, :sha256, credentials.secret_access_key, sign_key_info)
|> Base.encode16
|> String.downcase
canonical_uri = get_canonical_uri_path(path)
canonical_querystring = get_canonical_querystring(params, true)
{canonical_headers, headers_to_sign} = get_canonical_headers(headers, headers_to_sign)
canonical_request = Enum.join([http_method, canonical_uri, canonical_querystring, canonical_headers], "\n")
signature = :crypto.mac(:hmac, :sha256, sign_key, canonical_request)
|> Base.encode16
|> String.downcase
headers_str = Enum.join(headers_to_sign, ";")
"#{sign_key_info}/#{headers_str}/#{signature}"
end
end