diff --git a/lib/ex_aws/sts/auth_cache/assume_role_web_identity_adapter.ex b/lib/ex_aws/sts/auth_cache/assume_role_web_identity_adapter.ex index 13a89d5..41a7db7 100644 --- a/lib/ex_aws/sts/auth_cache/assume_role_web_identity_adapter.ex +++ b/lib/ex_aws/sts/auth_cache/assume_role_web_identity_adapter.ex @@ -27,7 +27,13 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapter do duration: duration ) - with {:ok, result} <- ExAws.request(assume_role_request, auth) do + config_overrides = + case auth.use_regional_endpoints do + false -> auth |> Map.put(:host, "sts.amazonaws.com") + true -> auth + end + + with {:ok, result} <- ExAws.request(assume_role_request, config_overrides) do %{ access_key_id: result.body.access_key_id, secret_access_key: result.body.secret_access_key, @@ -56,6 +62,8 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapter do role_arn: env_role_arn(config), role_session_name: role_session_name(config), web_identity_token: web_identity_token(config), + region: aws_region(config), + use_regional_endpoints: use_regional_endpoints(config), # necessary for now due to how ExAws.request() works access_key_id: "dummy", # necessary for now due to how ExAws.request() works @@ -80,4 +88,18 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapter do defp role_session_name(config) do config[:role_session_name] || "default_session" end + + defp use_regional_endpoints(config) do + regional_endpoints = + config[:sts_regional_endpoints] || System.get_env("AWS_STS_REGIONAL_ENDPOINTS") + + case regional_endpoints do + "regional" -> true + _ -> false + end + end + + defp aws_region(config) do + System.get_env("AWS_REGION") || config[:region] + end end diff --git a/mix.exs b/mix.exs index b76149c..dceca84 100644 --- a/mix.exs +++ b/mix.exs @@ -52,6 +52,7 @@ defmodule ExAws.STS.Mixfile do {:hackney, ">= 0.0.0", only: [:dev, :test]}, {:sweet_xml, ">= 0.0.0", only: [:dev, :test]}, {:jason, ">= 0.0.0", only: [:dev, :test]}, + {:xml_builder, "~> 2.1", only: [:test]}, ex_aws() ] end diff --git a/mix.lock b/mix.lock index 1776f10..f1f0586 100644 --- a/mix.lock +++ b/mix.lock @@ -1,23 +1,25 @@ %{ "briefly": {:hex, :briefly, "0.3.0", "16e6b76d2070ebc9cbd025fa85cf5dbaf52368c4bd896fb482b5a6b95a540c2f", [:mix], [], "hexpm", "c6ebf8fc3dcd4950dd10c03e953fb4f553a8bcf0ff4c8c40d71542434cd7e046"}, - "certifi": {:hex, :certifi, "2.6.1", "dbab8e5e155a0763eea978c913ca280a6b544bfa115633fa20249c3d396d9493", [:rebar3], [], "hexpm", "524c97b4991b3849dd5c17a631223896272c6b0af446778ba4675a1dff53bb7e"}, + "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, "earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm", "e3be2bc3ae67781db529b80aa7e7c49904a988596e2dbff897425b48b3581161"}, "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"}, - "ex_aws": {:hex, :ex_aws, "2.2.3", "f9bb1b04aaed3270f08c99d0268ff2c6596edb3a4a8792d18ffd37a74dd4810d", [:mix], [{:configparser_ex, "~> 4.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, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8ddf1da94624e5f92afe36d4146086f72d85bb15998cec137c1fd854a3f04bc4"}, + "ex_aws": {:hex, :ex_aws, "2.2.0", "3d3cea26cb2c15939b50ab686f7b6b0a3a7932b2fe15c7be70bc185c1aab612e", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "7d67150316e2a20e7b64915c8eca98fe5777890dc88a75ab9126cf994f421d82"}, "ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"}, - "hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [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.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.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.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"}, + "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.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.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.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.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "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.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, + "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mox": {:hex, :mox, "0.5.2", "55a0a5ba9ccc671518d068c8dddd20eeb436909ea79d1799e2209df7eaa98b6c", [:mix], [], "hexpm", "df4310628cd628ee181df93f50ddfd07be3e5ecc30232d3b6aadf30bdfe6092b"}, "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"}, + "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, + "xml_builder": {:hex, :xml_builder, "2.2.0", "cc5f1eeefcfcde6e90a9b77fb6c490a20bc1b856a7010ce6396f6da9719cbbab", [:mix], [], "hexpm", "9d66d52fb917565d358166a4314078d39ef04d552904de96f8e73f68f64a62c9"}, } diff --git a/test/lib/auth_cache/assume_role_credentials_adapter_test.exs b/test/lib/auth_cache/assume_role_credentials_adapter_test.exs index 2aafa91..1d9037e 100644 --- a/test/lib/auth_cache/assume_role_credentials_adapter_test.exs +++ b/test/lib/auth_cache/assume_role_credentials_adapter_test.exs @@ -8,30 +8,33 @@ defmodule ExAws.STS.AuthCache.AssumeRoleCredentialsAdapterTest do profile = "default" auth = test_loader(profile) - body = %{ - access_key_id: "1", - secret_access_key: "secret", - session_token: "token" + expected = %{ + access_key_id: "accessKeYz", + secret_access_key: "secret_access_KeY", + security_token: "SeCURItyToken", + role_arn: auth.role_arn, + role_session_name: auth.role_session_name, + source_profile: auth.source_profile } + sts_xml_resp = + sts_xml_response( + expected.role_session_name, + expected.role_arn, + expected.security_token, + expected.access_key_id, + expected.secret_access_key + ) + ExAws.Request.HttpMock |> expect(:request, fn _method, _url, "Action=AssumeRole&DurationSeconds=900&RoleArn=1111111%2Ftest_role&RoleSessionName=test&Version=2011-06-15", _headers, _opts -> - {:ok, %{status_code: 200, body: body}} + {:ok, %{status_code: 200, body: sts_xml_resp}} end) - expected = %{ - access_key_id: body.access_key_id, - secret_access_key: body.secret_access_key, - security_token: body.session_token, - role_arn: auth.role_arn, - role_session_name: auth.role_session_name, - source_profile: auth.source_profile - } - assert expected == AssumeRoleCredentialsAdapter.adapt_auth_config(auth, profile, 300, &test_loader/1) end @@ -52,4 +55,32 @@ defmodule ExAws.STS.AuthCache.AssumeRoleCredentialsAdapterTest do region: "us-east-1" } end + + defp sts_xml_response(session_name, role_arn, security_token, access_key_id, secret_access_key) do + { + "AssumeRoleResponse", + [xmlns: "https://sts.amazonaws.com/doc/2011-06-15/"], + [ + { + "AssumeRoleResult", + nil, + [ + {"AssumedRoleUser", nil, + [ + {"Arn", nil, "#{role_arn}/#{session_name}"}, + {"AssumedRoleId", nil, "AROACLKWSDQRAOEXAMPLE:#{session_name}"} + ]}, + {"Credentials", nil, + [ + {"SessionToken", nil, security_token}, + {"SecretAccessKey", nil, secret_access_key}, + {"Expiration", nil, "2014-10-24T23:00:23Z"}, + {"AccessKeyId", nil, access_key_id} + ]} + ] + } + ] + } + |> XmlBuilder.generate() + end end diff --git a/test/lib/auth_cache/assume_role_web_identity_adapter_test.exs b/test/lib/auth_cache/assume_role_web_identity_adapter_test.exs index 5d0865b..57601d9 100644 --- a/test/lib/auth_cache/assume_role_web_identity_adapter_test.exs +++ b/test/lib/auth_cache/assume_role_web_identity_adapter_test.exs @@ -1,5 +1,5 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do - use ExUnit.Case, async: true + use ExUnit.Case, async: false alias ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapter import Mox @@ -13,12 +13,15 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do {:ok, path} = Briefly.create() File.write!(path, @web_identity_token) + System.put_env("AWS_REGION", "eu-west-1") System.put_env("AWS_WEB_IDENTITY_TOKEN_FILE", path) System.put_env("AWS_ROLE_ARN", @role_arn) on_exit(fn -> + System.delete_env("AWS_REGION") System.delete_env("AWS_WEB_IDENTITY_TOKEN_FILE") System.delete_env("AWS_ROLE_ARN") + System.delete_env("AWS_STS_REGIONAL_ENDPOINTS") end) end @@ -27,7 +30,6 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do expiration = 500 config = %{ - region: "us-east-1", role_arn: "1111111/test_role", role_session_name: "test", access_key_id: "dummy", @@ -35,11 +37,18 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do http_client: ExAws.Request.HttpMock } - body = %{ - access_key_id: "1", - secret_access_key: "secret", - session_token: "token" - } + access_key_id = "ASgeIAIOSFODNN7EXAMPLE" + secret_access_key = "AROACLKWSDQRAOEXAMPLE:test" + security_token = "AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE" + + sts_resp_xml = + sts_xml_response( + config.role_session_name, + config.role_arn, + security_token, + access_key_id, + secret_access_key + ) ExAws.Request.HttpMock |> expect(:request, fn _method, @@ -47,13 +56,13 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do "Action=AssumeRoleWithWebIdentity&DurationSeconds=900&RoleArn=1111111%2Ftest_role&RoleSessionName=test&Version=2011-06-15&WebIdentityToken=ey", _headers, _opts -> - {:ok, %{status_code: 200, body: body}} + {:ok, %{status_code: 200, body: sts_resp_xml}} end) expected = %{ - access_key_id: body.access_key_id, - secret_access_key: body.secret_access_key, - security_token: body.session_token, + access_key_id: access_key_id, + secret_access_key: secret_access_key, + security_token: security_token, role_arn: config.role_arn, role_session_name: config.role_session_name, expiration: expiration @@ -75,11 +84,18 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do http_client: ExAws.Request.HttpMock } - body = %{ - access_key_id: "1", - secret_access_key: "secret", - session_token: "token" - } + access_key_id = "ASgeIAIOSFODNN7EXAMPLE" + secret_access_key = "AROACLKWSDQRAOEXAMPLE:test" + security_token = "AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE" + + sts_resp_xml = + sts_xml_response( + @role_session_name, + @role_arn, + security_token, + access_key_id, + secret_access_key + ) ExAws.Request.HttpMock |> expect(:request, fn _method, @@ -87,13 +103,95 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do "Action=AssumeRoleWithWebIdentity&DurationSeconds=900&RoleArn=2222222%2Ftest_role&RoleSessionName=default_session&Version=2011-06-15&WebIdentityToken=yo", _headers, _opts -> - {:ok, %{status_code: 200, body: body}} + {:ok, %{status_code: 200, body: sts_resp_xml}} + end) + + expected = %{ + access_key_id: access_key_id, + secret_access_key: secret_access_key, + security_token: security_token, + role_arn: @role_arn, + role_session_name: @role_session_name, + expiration: @expiration + } + + assert expected == AssumeRoleWebIdentityAdapter.adapt_auth_config(config, nil, nil) + end + end + + describe "use of global and regional sts endpoint" do + test "regional endpoints" do + System.put_env("AWS_STS_REGIONAL_ENDPOINTS", "regional") + + config = %{ + http_client: ExAws.Request.HttpMock + } + + access_key_id = "ASgeIAIOSFODNN7EXAMPLE" + secret_access_key = "AROACLKWSDQRAOEXAMPLE:test" + security_token = "AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE" + + sts_resp_xml = + sts_xml_response( + @role_session_name, + @role_arn, + security_token, + access_key_id, + secret_access_key + ) + + ExAws.Request.HttpMock + |> expect(:request, fn _method, + "https://sts.eu-west-1.amazonaws.com/", + "Action=AssumeRoleWithWebIdentity&DurationSeconds=900&RoleArn=2222222%2Ftest_role&RoleSessionName=default_session&Version=2011-06-15&WebIdentityToken=yo", + _headers, + _opts -> + {:ok, %{status_code: 200, body: sts_resp_xml}} + end) + + expected = %{ + access_key_id: access_key_id, + secret_access_key: secret_access_key, + security_token: security_token, + role_arn: @role_arn, + role_session_name: @role_session_name, + expiration: @expiration + } + + assert expected == AssumeRoleWebIdentityAdapter.adapt_auth_config(config, nil, nil) + end + + test "global endpoint" do + config = %{ + http_client: ExAws.Request.HttpMock + } + + access_key_id = "ASgeIAIOSFODNN7EXAMPLE" + secret_access_key = "AROACLKWSDQRAOEXAMPLE:test" + security_token = "AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE" + + sts_resp_xml = + sts_xml_response( + @role_session_name, + @role_arn, + security_token, + access_key_id, + secret_access_key + ) + + ExAws.Request.HttpMock + |> expect(:request, fn _method, + "https://sts.amazonaws.com/", + "Action=AssumeRoleWithWebIdentity&DurationSeconds=900&RoleArn=2222222%2Ftest_role&RoleSessionName=default_session&Version=2011-06-15&WebIdentityToken=yo", + _headers, + _opts -> + {:ok, %{status_code: 200, body: sts_resp_xml}} end) expected = %{ - access_key_id: body.access_key_id, - secret_access_key: body.secret_access_key, - security_token: body.session_token, + access_key_id: access_key_id, + secret_access_key: secret_access_key, + security_token: security_token, role_arn: @role_arn, role_session_name: @role_session_name, expiration: @expiration @@ -101,6 +199,36 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do assert expected == AssumeRoleWebIdentityAdapter.adapt_auth_config(config, nil, nil) end + + test "when the region is not specified - fall back to default region" do + System.delete_env("AWS_REGION") + System.put_env("AWS_STS_REGIONAL_ENDPOINTS", "regional") + + config = %{ + region: "us-east-1", + http_client: ExAws.Request.HttpMock + } + + sts_resp_xml = + sts_xml_response( + "role_session_name", + "role_arn", + "security_token", + "access_key_id", + "secret_access_key" + ) + + ExAws.Request.HttpMock + |> expect(:request, fn _method, + "https://sts.us-east-1.amazonaws.com/", + "Action=AssumeRoleWithWebIdentity&DurationSeconds=900&RoleArn=2222222%2Ftest_role&RoleSessionName=default_session&Version=2011-06-15&WebIdentityToken=yo", + _headers, + _opts -> + {:ok, %{status_code: 200, body: sts_resp_xml}} + end) + + AssumeRoleWebIdentityAdapter.adapt_auth_config(config, nil, nil) + end end describe "when the specified file does not exist" do @@ -116,7 +244,40 @@ defmodule ExAws.STS.AuthCache.AssumeRoleWebIdentityAdapterTest do defp test_loader(_config) do %{ role_arn: "1111111/test_role", - web_identity_token: "ey" + web_identity_token: "ey", + use_regional_endpoints: false + } + end + + defp sts_xml_response(session_name, role_arn, security_token, access_key_id, secret_access_key) do + { + "AssumeRoleWithWebIdentityResponse", + [xmlns: "http://schemas.example.tld/1999"], + [ + { + "AssumeRoleWithWebIdentityResult", + nil, + [ + {"SubjectFromWebIdentityToken", nil, "amzn1.account.AF6RHO7KZU5XRVQJGXK6HB56KR2A"}, + {"Audience", nil, "client.5498841531868486423.1548@apps.example.com"}, + {"AssumedRoleUser", nil, + [ + {"Arn", nil, "#{role_arn}/#{session_name}"}, + {"AssumedRoleId", nil, "AROACLKWSDQRAOEXAMPLE:#{session_name}"} + ]}, + {"Credentials", nil, + [ + {"SessionToken", nil, security_token}, + {"SecretAccessKey", nil, secret_access_key}, + {"Expiration", nil, "2014-10-24T23:00:23Z"}, + {"AccessKeyId", nil, access_key_id} + ]}, + {"SourceIdentity", nil, "SourceIdentityValue"}, + {"Provider", nil, "www.amazon.com"} + ] + } + ] } + |> XmlBuilder.generate() end end