Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion lib/goth/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,16 @@ defmodule Goth.Config do
end

defp set_token_source(%{"type" => "external_account"} = map) do
Map.put(map, "token_source", :workload_identity)
# Check if this is an AWS workload identity configuration
is_aws = case map do
%{"subject_token_type" => "urn:x-oauth:params:oauth:token-type:aws"} -> true
%{"credential_source" => %{"regional_cred_verification_url" => _}} -> true
_ -> false
end

map
|> Map.put("token_source", :workload_identity)
|> then(fn m -> if is_aws, do: Map.put(m, "provider", "aws"), else: m end)
end

defp set_token_source(list) when is_list(list) do
Expand Down
23 changes: 22 additions & 1 deletion lib/goth/token.ex
Original file line number Diff line number Diff line change
Expand Up @@ -386,14 +386,27 @@ defmodule Goth.Token do

headers = [{"Content-Type", "application/x-www-form-urlencoded"}]

subject_token =
if is_aws_workload_identity?(credentials) do
case Goth.Token.ExAws.generate_subject_token(audience) do
{:ok, token} ->
token

{:error, reason} ->
raise "Failed to generate AWS subject token: #{reason}"
end
else
subject_token_from_credential_source(credential_source, config)
end

body =
URI.encode_query(%{
"audience" => audience,
"grant_type" => "urn:ietf:params:oauth:grant-type:token-exchange",
"requested_token_type" => "urn:ietf:params:oauth:token-type:access_token",
"scope" => List.first(@default_scopes),
"subject_token_type" => subject_token_type,
"subject_token" => subject_token_from_credential_source(credential_source, config)
"subject_token" => subject_token
})

response = request(config.http_client, method: :post, url: token_url, headers: headers, body: body)
Expand All @@ -416,6 +429,14 @@ defmodule Goth.Token do
{url, audience}
end

defp is_aws_workload_identity?(credentials) do
case credentials do
%{"subject_token_type" => "urn:x-oauth:params:oauth:token-type:aws"} -> true
%{"credential_source" => %{"regional_cred_verification_url" => _}} -> true
_ -> false
end
end

defp subject_token_from_credential_source(%{"url" => url, "headers" => headers, "format" => format}, config) do
with {:ok, %{status: 200, body: body}} <-
request(config.http_client, method: :get, url: url, headers: Enum.to_list(headers), body: "") do
Expand Down
104 changes: 104 additions & 0 deletions lib/goth/token/ex_aws.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
defmodule Goth.Token.ExAws do
@moduledoc """
AWS workload identity integration using ex_aws.

This module provides AWS workload identity federation support by leveraging
the existing ex_aws and ex_aws_sts libraries for credential resolution and
AWS API integration.

## Dependencies

This functionality requires the following optional dependencies:
- `ex_aws ~> 2.1`

If these dependencies are not available, AWS workload identity federation
will not be supported, but other Goth functionality remains unaffected.

## Credential Sources Supported

Through ex_aws, this module automatically supports:
- EC2 Instance Metadata Service (IMDSv1 and IMDSv2)
- ECS Task Credentials
- AWS Lambda execution role
- Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, etc.)
- AWS CLI config files (~/.aws/credentials, ~/.aws/config)
- IAM roles and assume role chains
"""

require Logger

@doc """
Generates a subject token for AWS workload identity federation.

This creates a signed GetCallerIdentity request using ex_aws that can be
exchanged with Google's STS for an access token.

## Parameters

- `audience` - The audience string to include in the signed request,
typically the full resource name of the Google service account.

## Returns

- `{:ok, subject_token}` - Base64-encoded signed request for Google STS
- `{:error, reason}` - Error message, including missing dependencies
"""

if Code.ensure_loaded?(ExAws) && Code.ensure_loaded?(ExAws.STS) do
def generate_subject_token(audience) do
with {:ok, signed_request} <- build_signed_request(audience) do
{:ok, encode_for_google_sts(signed_request)}
end
end

defp build_signed_request(audience) do
url = "https://sts.amazonaws.com/"
params = "Action=GetCallerIdentity&Version=2011-06-15"
url = URI.parse(url) |> URI.append_query(params) |> URI.to_string()

headers = [{"x-goog-cloud-target-resource", audience}]

config = ExAws.Config.new(:sts)

case ExAws.Auth.headers(:post, url, :sts, config, headers, "") do
{:ok, signed_headers} ->
request_details =
%{
"method" => "POST",
"url" => url,
"headers" => Map.new(signed_headers)
}

{:ok, request_details}

{:error, reason} ->
{:error, reason}
end
end

defp encode_for_google_sts(signed_request) do
token = %{
"url" => signed_request["url"],
"method" => signed_request["method"],
"headers" =>
Enum.map(signed_request["headers"], fn {key, value} ->
%{"key" => key, "value" => value}
end)
}

token
|> Jason.encode!()
|> url_quote()
end

defp url_quote(string) do
string
|> :uri_string.quote()
|> to_string()
end
else
def generate_subject_token(_audience) do
{:error, "ex_aws dependency is required for AWS workload identity federation"}
end
end
end
6 changes: 5 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ defmodule Goth.Mixfile do
{:jose, "~> 1.11"},
{:jason, "~> 1.1"},
{:finch, "~> 0.17"},
{:ex_aws, "~> 2.1", optional: true},
{:ex_aws_sts, "~> 2.0", optional: true},
{:bypass, "~> 2.1", only: :test},
{:mimic, "~> 2.1", only: :test},
{:hackney, "~> 1.9", only: :test},
{:ex_doc, "~> 0.19", only: :dev},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 0.5", only: [:dev], runtime: false}
]
end
Expand Down
16 changes: 14 additions & 2 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
%{
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
"bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"},
"certifi": {:hex, :certifi, "2.15.0", "0e6e882fcdaaa0a5a9f2b3db55b1394dba07e8d6d9bcad08318fb604c6839712", [:rebar3], [], "hexpm", "b147ed22ce71d72eafdad94f055165c1c182f61a2ff49df28bcc71d1d5b94a60"},
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
"credo": {:hex, :credo, "1.7.10", "6e64fe59be8da5e30a1b96273b247b5cf1cc9e336b5fd66302a64b25749ad44d", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "71fbc9a6b8be21d993deca85bf151df023a3097b01e09a2809d460348561d8cd"},
"credo": {:hex, :credo, "1.7.13", "126a0697df6b7b71cd18c81bc92335297839a806b6f62b61d417500d1070ff4e", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "47641e6d2bbff1e241e87695b29f617f1a8f912adea34296fb10ecc3d7e9e84f"},
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm", "6c32a70ed5d452c6650916555b1f96c79af5fc4bf286997f8b15f213de786f73"},
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
"ex_aws": {:hex, :ex_aws, "2.5.11", "5646eaad701485505b78246b0cd406fde9b1619459a86e85b53398810d3d0bd3", [:mix], [{:configparser_ex, "~> 5.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7e16100ff93a118ef01c916d945969535cbe8d4ab6593fcf01d1cf854eb75345"},
"ex_aws_sts": {:hex, :ex_aws_sts, "2.3.0", "ce48c4cba7f1595a7d544458d0202ca313124026dba7b1a0021bbb1baa3d66d0", [:mix], [{:ex_aws, "~> 2.2", [hex: :ex_aws, repo: "hexpm", optional: false]}], "hexpm", "f14e4c7da3454514bf253b331e9422d25825485c211896ab3b81d2a4bdbf62f5"},
"ex_doc": {:hex, :ex_doc, "0.35.1", "de804c590d3df2d9d5b8aec77d758b00c814b356119b3d4455e4b8a8687aecaf", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2121c6402c8d44b05622677b761371a759143b958c6c19f6558ff64d0aed40df"},
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
"file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"},
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
"hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"},
"ham": {:hex, :ham, "0.3.2", "02ae195f49970ef667faf9d01bc454fb80909a83d6c775bcac724ca567aeb7b3", [:mix], [], "hexpm", "b71cc684c0e5a3d32b5f94b186770551509e93a9ae44ca1c1a313700f2f6a69a"},
"hpax": {:hex, :hpax, "1.0.1", "c857057f89e8bd71d97d9042e009df2a42705d6d690d54eca84c8b29af0787b0", [:mix], [], "hexpm", "4e2d5a4f76ae1e3048f35ae7adb1641c36265510a2d4638157fbcb53dda38445"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
"mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"},
"mimic": {:hex, :mimic, "2.1.0", "60f0261b3dcd7f70a4e1c06e455d9e703718bf4fca3493bde076485ce8330992", [:mix], [{:ham, "~> 0.3", [hex: :ham, repo: "hexpm", optional: false]}], "hexpm", "9d61c2a70933ed04506208adaf23025c824e8e9dfdd1fea884afffb24b6f0956"},
"mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"},
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
"plug_cowboy": {:hex, :plug_cowboy, "2.7.2", "fdadb973799ae691bf9ecad99125b16625b1c6039999da5fe544d99218e662e4", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "245d8a11ee2306094840c000e8816f0cbed69a23fc0ac2bcf8d7835ae019bb2f"},
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},
}
50 changes: 50 additions & 0 deletions test/goth/token/ex_aws_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
defmodule Goth.Token.ExAwsTest do
use ExUnit.Case, async: true

@moduletag :integration

alias Goth.Token.ExAws

describe "generate_subject_token/0" do
test "generates a properly formatted subject token" do
case ExAws.generate_subject_token() do
{:ok, token} ->
assert is_binary(token)
decoded_token = Base.url_decode64!(token, padding: false)
token_data = Jason.decode!(decoded_token)

assert Map.has_key?(token_data, "url")
assert Map.has_key?(token_data, "method")
assert Map.has_key?(token_data, "headers")
assert Map.has_key?(token_data, "body")

assert token_data["method"] == "POST"

url = token_data["url"]
assert String.contains?(url, "sts")
assert String.contains?(url, "GetCallerIdentity")

headers = token_data["headers"]
assert is_list(headers)

Enum.each(headers, fn header ->
assert Map.has_key?(header, "key")
assert Map.has_key?(header, "value")
end)

auth_header = Enum.find(headers, fn h -> h["key"] == "authorization" end)
assert auth_header != nil
assert String.contains?(auth_header["value"], "AWS4-HMAC-SHA256")

assert is_binary(token_data["body"])

{:error, reason} when is_binary(reason) ->
flunk("Expected success but got error: #{reason}")

other ->
flunk("Unexpected return value: #{inspect(other)}")
end
end
end
end

1 change: 1 addition & 0 deletions test/goth/token_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule Goth.TokenTest do
use ExUnit.Case, async: true
use Mimic

test "fetch/1 with service account" do
bypass = Bypass.open()
Expand Down
Loading