Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package aws-c-auth for openSUSE:Factory 
checked in at 2024-08-01 22:06:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/aws-c-auth (Old)
 and      /work/SRC/openSUSE:Factory/.aws-c-auth.new.7232 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "aws-c-auth"

Thu Aug  1 22:06:05 2024 rev:7 rq:1191008 version:0.7.23

Changes:
--------
--- /work/SRC/openSUSE:Factory/aws-c-auth/aws-c-auth.changes    2024-06-14 
19:07:22.487039173 +0200
+++ /work/SRC/openSUSE:Factory/.aws-c-auth.new.7232/aws-c-auth.changes  
2024-08-01 22:06:50.538438626 +0200
@@ -1,0 +2,10 @@
+Wed Jul 31 09:10:10 UTC 2024 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 0.7.23
+  * Ecforce ECS Credentials Provider IP Rules by @waahm7 in (#238)
+  * clang-format 18 by @graebm in (#242)
+  * Update MacOS to arm64 by @waahm7 in (#243)
+  * Support "external_id" in config file,
+    for STS AssumeRole by @graebm in (#244)
+
+-------------------------------------------------------------------

Old:
----
  v0.7.22.tar.gz

New:
----
  v0.7.23.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ aws-c-auth.spec ++++++
--- /var/tmp/diff_new_pack.IgR9PM/_old  2024-08-01 22:06:51.082461075 +0200
+++ /var/tmp/diff_new_pack.IgR9PM/_new  2024-08-01 22:06:51.086461240 +0200
@@ -20,7 +20,7 @@
 %define library_pkg 1_0_0
 %define library_soversion 1
 Name:           aws-c-auth
-Version:        0.7.22
+Version:        0.7.23
 Release:        0
 Summary:        AWS C99 library implementation of AWS client-side 
authentication
 License:        Apache-2.0

++++++ v0.7.22.tar.gz -> v0.7.23.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/.github/workflows/ci.yml 
new/aws-c-auth-0.7.23/.github/workflows/ci.yml
--- old/aws-c-auth-0.7.22/.github/workflows/ci.yml      2024-05-15 
20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/.github/workflows/ci.yml      2024-07-30 
22:21:36.000000000 +0200
@@ -6,7 +6,7 @@
       - 'main'
 
 env:
-  BUILDER_VERSION: v0.9.55
+  BUILDER_VERSION: v0.9.62
   BUILDER_SOURCE: releases
   BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net
   PACKAGE_NAME: aws-c-auth
@@ -20,6 +20,7 @@
   linux-compat:
     runs-on: ubuntu-20.04 # latest
     strategy:
+      fail-fast: false
       matrix:
         image:
           - manylinux1-x64
@@ -40,6 +41,7 @@
   linux-compiler-compat:
     runs-on: ubuntu-20.04 # latest
     strategy:
+      fail-fast: false
       matrix:
         compiler:
           - clang-3
@@ -80,6 +82,7 @@
   windows-vc14:
     runs-on: windows-2019 # windows-2019 is last env with Visual Studio 2015 
(v14.0)
     strategy:
+      fail-fast: false
       matrix:
         arch: [x86, x64]
     steps:
@@ -107,8 +110,17 @@
       run: |
         python 
.\aws-c-auth\build\deps\aws-c-common\scripts\appverifier_ctest.py 
--build_directory .\aws-c-auth\build\aws-c-auth
 
-  osx:
-    runs-on: macos-12 # latest
+  macos:
+    runs-on: macos-14 # latest
+    steps:
+    - name: Build ${{ env.PACKAGE_NAME }} + consumers
+      run: |
+        python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ 
env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION 
}}/builder.pyz?run=${{ env.RUN }}', 'builder')"
+        chmod a+x builder
+        ./builder build -p ${{ env.PACKAGE_NAME }}
+
+  macos-x64:
+    runs-on: macos-14-large # latest
     steps:
     - name: Build ${{ env.PACKAGE_NAME }} + consumers
       run: |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/.github/workflows/clang-format.yml 
new/aws-c-auth-0.7.23/.github/workflows/clang-format.yml
--- old/aws-c-auth-0.7.22/.github/workflows/clang-format.yml    2024-05-15 
20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/.github/workflows/clang-format.yml    2024-07-30 
22:21:36.000000000 +0200
@@ -5,14 +5,12 @@
 jobs:
   clang-format:
 
-    runs-on: ubuntu-20.04 # latest
+    runs-on: ubuntu-24.04 # latest
 
     steps:
     - name: Checkout Sources
-      uses: actions/checkout@v1
+      uses: actions/checkout@v4
 
     - name: clang-format lint
-      uses: DoozyX/[email protected]
-      with:
-        # List of extensions to check
-        extensions: c,h
+      run: |
+        ./format-check.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/format-check.py 
new/aws-c-auth-0.7.23/format-check.py
--- old/aws-c-auth-0.7.22/format-check.py       1970-01-01 01:00:00.000000000 
+0100
+++ new/aws-c-auth-0.7.23/format-check.py       2024-07-30 22:21:36.000000000 
+0200
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+import argparse
+import os
+from pathlib import Path
+import re
+from subprocess import list2cmdline, run
+from tempfile import NamedTemporaryFile
+
+CLANG_FORMAT_VERSION = '18.1.6'
+
+INCLUDE_REGEX = re.compile(
+    r'^(include|source|tests|verification)/.*\.(c|h|inl)$')
+EXCLUDE_REGEX = re.compile(r'^$')
+
+arg_parser = argparse.ArgumentParser(description="Check with clang-format")
+arg_parser.add_argument('-i', '--inplace-edit', action='store_true',
+                        help="Edit files inplace")
+args = arg_parser.parse_args()
+
+os.chdir(Path(__file__).parent)
+
+# create file containing list of all files to format
+filepaths_file = NamedTemporaryFile(delete=False)
+for dirpath, dirnames, filenames in os.walk('.'):
+    for filename in filenames:
+        # our regexes expect filepath to use forward slash
+        filepath = Path(dirpath, filename).as_posix()
+        if not INCLUDE_REGEX.match(filepath):
+            continue
+        if EXCLUDE_REGEX.match(filepath):
+            continue
+
+        filepaths_file.write(f"{filepath}\n".encode())
+filepaths_file.close()
+
+# use pipx to run clang-format from PyPI
+# this is a simple way to run the same clang-format version regardless of OS
+cmd = ['pipx', 'run', f'clang-format=={CLANG_FORMAT_VERSION}',
+       f'--files={filepaths_file.name}']
+if args.inplace_edit:
+    cmd += ['-i']
+else:
+    cmd += ['--Werror', '--dry-run']
+
+print(f"{Path.cwd()}$ {list2cmdline(cmd)}")
+if run(cmd).returncode:
+    exit(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/format-check.sh 
new/aws-c-auth-0.7.23/format-check.sh
--- old/aws-c-auth-0.7.22/format-check.sh       2024-05-15 20:46:22.000000000 
+0200
+++ new/aws-c-auth-0.7.23/format-check.sh       1970-01-01 01:00:00.000000000 
+0100
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-if [[ -z $CLANG_FORMAT ]] ; then
-    CLANG_FORMAT=clang-format
-fi
-
-if NOT type $CLANG_FORMAT 2> /dev/null ; then
-    echo "No appropriate clang-format found."
-    exit 1
-fi
-
-FAIL=0
-SOURCE_FILES=`find source include tests -type f \( -name '*.h' -o -name '*.c' 
\)`
-for i in $SOURCE_FILES
-do
-    $CLANG_FORMAT -output-replacements-xml $i | grep -c "<replacement " > 
/dev/null
-    if [ $? -ne 1 ]
-    then
-        echo "$i failed clang-format check."
-        FAIL=1
-    fi
-done
-
-exit $FAIL
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/include/aws/auth/auth.h 
new/aws-c-auth-0.7.23/include/aws/auth/auth.h
--- old/aws-c-auth-0.7.22/include/aws/auth/auth.h       2024-05-15 
20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/include/aws/auth/auth.h       2024-07-30 
22:21:36.000000000 +0200
@@ -52,6 +52,7 @@
     AWS_AUTH_IMDS_CLIENT_SOURCE_FAILURE,
     AWS_AUTH_PROFILE_STS_CREDENTIALS_PROVIDER_CYCLE_FAILURE,
     AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_TOKEN_FILE_PATH,
+    AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST,
 
     AWS_AUTH_ERROR_END_RANGE = AWS_ERROR_ENUM_END_RANGE(AWS_C_AUTH_PACKAGE_ID)
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/include/aws/auth/credentials.h 
new/aws-c-auth-0.7.23/include/aws/auth/credentials.h
--- old/aws-c-auth-0.7.22/include/aws/auth/credentials.h        2024-05-15 
20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/include/aws/auth/credentials.h        2024-07-30 
22:21:36.000000000 +0200
@@ -232,6 +232,11 @@
  * AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
  * AWS_CONTAINER_CREDENTIALS_FULL_URI
  *
+ *`AWS_CONTAINER_CREDENTIALS_FULL_URI` URL must satisfy one of the following:
+ *  1. The URL begins with `https`.
+ *  2. The resolved IP address is within the loopback CIDR (IPv4 127.0.0.0/8, 
IPv6 ::1/128), ECS container address
+ *     (169.254.170.2), or EKS Pod Identity address (169.254.170.23 or 
fd00:ec2::23).
+ *
  * For the Authorization token, there are two ways (in order of priority):
  * 1. AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE (an env var which contains the 
absolute path to the token file. The file
  * will be re-read for each call to get credentials.)
@@ -261,6 +266,11 @@
  * Configuration options for the provider that sources credentials from ECS 
container metadata.
  * This options struct doesn't read anything from the environment and requires 
everything to be explicitly passed in. If
  * you need to read properties from the environment, use the 
`aws_credentials_provider_ecs_environment_options`.
+ *
+ *`host` must satisfy one of the following:
+ *  1. tls_context is set
+ *  2. The resolved IP address is within the loopback CIDR (IPv4 127.0.0.0/8, 
IPv6 ::1/128), ECS container address
+ *     (169.254.170.2), or EKS Pod Identity address (169.254.170.23 or 
fd00:ec2::23).
  */
 struct aws_credentials_provider_ecs_options {
     struct aws_credentials_provider_shutdown_options shutdown_options;
@@ -500,6 +510,11 @@
     struct aws_byte_cursor session_name;
 
     /*
+     * (Optional) Unique identifier for assuming a role in another account
+     */
+    struct aws_byte_cursor external_id;
+
+    /*
      * How long sourced credentials should remain valid for, in seconds.  900 
is the minimum allowed value.
      */
     uint16_t duration_seconds;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/aws-c-auth-0.7.22/include/aws/auth/private/credentials_utils.h 
new/aws-c-auth-0.7.23/include/aws/auth/private/credentials_utils.h
--- old/aws-c-auth-0.7.22/include/aws/auth/private/credentials_utils.h  
2024-05-15 20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/include/aws/auth/private/credentials_utils.h  
2024-07-30 22:21:36.000000000 +0200
@@ -30,9 +30,9 @@
     void *user_data;
 };
 
-typedef struct aws_http_connection_manager 
*(aws_http_connection_manager_new_fn)(
-    struct aws_allocator *allocator,
-    const struct aws_http_connection_manager_options *options);
+typedef struct aws_http_connection_manager *(
+    aws_http_connection_manager_new_fn)(struct aws_allocator *allocator,
+                                        const struct 
aws_http_connection_manager_options *options);
 typedef void(aws_http_connection_manager_release_fn)(struct 
aws_http_connection_manager *manager);
 typedef void(aws_http_connection_manager_acquire_connection_fn)(
     struct aws_http_connection_manager *manager,
@@ -41,9 +41,9 @@
 typedef int(aws_http_connection_manager_release_connection_fn)(
     struct aws_http_connection_manager *manager,
     struct aws_http_connection *connection);
-typedef struct aws_http_stream *(aws_http_connection_make_request_fn)(
-    struct aws_http_connection *client_connection,
-    const struct aws_http_make_request_options *options);
+typedef struct aws_http_stream *(
+    aws_http_connection_make_request_fn)(struct aws_http_connection 
*client_connection,
+                                         const struct 
aws_http_make_request_options *options);
 typedef int(aws_http_stream_activate_fn)(struct aws_http_stream *stream);
 typedef struct aws_http_connection *(aws_http_stream_get_connection_fn)(const 
struct aws_http_stream *stream);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/source/auth.c 
new/aws-c-auth-0.7.23/source/auth.c
--- old/aws-c-auth-0.7.22/source/auth.c 2024-05-15 20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/source/auth.c 2024-07-30 22:21:36.000000000 +0200
@@ -112,6 +112,9 @@
         AWS_DEFINE_ERROR_INFO_AUTH(
     AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_TOKEN_FILE_PATH,
         "Failed to read the ECS token file specified in the 
AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE environment variable."),
+        AWS_DEFINE_ERROR_INFO_AUTH(
+    AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST,
+        "Failed to establish connection. The specified host is not allowed. It 
must be a loopback address, ECS/EKS container host, or use HTTPS."),
 };
 /* clang-format on */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/source/credentials_provider_ecs.c 
new/aws-c-auth-0.7.23/source/credentials_provider_ecs.c
--- old/aws-c-auth-0.7.22/source/credentials_provider_ecs.c     2024-05-15 
20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/source/credentials_provider_ecs.c     2024-07-30 
22:21:36.000000000 +0200
@@ -10,11 +10,14 @@
 #include <aws/common/clock.h>
 #include <aws/common/date_time.h>
 #include <aws/common/environment.h>
+#include <aws/common/host_utils.h>
 #include <aws/common/string.h>
 #include <aws/http/connection.h>
 #include <aws/http/connection_manager.h>
 #include <aws/http/request_response.h>
 #include <aws/http/status_code.h>
+#include <aws/io/channel_bootstrap.h>
+#include <aws/io/host_resolver.h>
 #include <aws/io/logging.h>
 #include <aws/io/socket.h>
 #include <aws/io/tls_channel_handler.h>
@@ -45,6 +48,8 @@
     struct aws_string *path_and_query;
     struct aws_string *auth_token_file_path;
     struct aws_string *auth_token;
+    struct aws_client_bootstrap *bootstrap;
+    bool is_https;
 };
 
 /*
@@ -459,6 +464,89 @@
     s_ecs_query_task_role_credentials(ecs_user_data);
 }
 
+/*
+ * The resolved IP address must satisfy one of the following:
+ * 1. within the loopback CIDR (IPv4 127.0.0.0/8, IPv6 ::1/128)
+ * 2. corresponds to the ECS container host 169.254.170.2
+ * 3. corresponds to the EKS container host IPs (IPv4 169.254.170.23, IPv6 
fd00:ec2::23)
+ */
+static bool s_is_valid_remote_host_ip(const struct aws_host_address 
*host_address) {
+    bool result = false;
+    struct aws_byte_cursor address = 
aws_byte_cursor_from_string(host_address->address);
+    if (host_address->record_type == AWS_ADDRESS_RECORD_TYPE_A) {
+        const struct aws_byte_cursor ipv4_loopback_address_prefix = 
aws_byte_cursor_from_c_str("127.");
+        const struct aws_byte_cursor ecs_container_host_address = 
aws_byte_cursor_from_c_str("169.254.170.2");
+        const struct aws_byte_cursor eks_container_host_address = 
aws_byte_cursor_from_c_str("169.254.170.23");
+
+        result |= aws_byte_cursor_starts_with(&address, 
&ipv4_loopback_address_prefix);
+        result |= aws_byte_cursor_eq(&address, &ecs_container_host_address);
+        result |= aws_byte_cursor_eq(&address, &eks_container_host_address);
+
+    } else if (host_address->record_type == AWS_ADDRESS_RECORD_TYPE_AAAA) {
+        /* Check for both the short form and long form of an IPv6 address to 
be safe. */
+        const struct aws_byte_cursor ipv6_loopback_address = 
aws_byte_cursor_from_c_str("::1");
+        const struct aws_byte_cursor ipv6_loopback_address_verbose = 
aws_byte_cursor_from_c_str("0:0:0:0:0:0:0:1");
+        const struct aws_byte_cursor eks_container_host_ipv6_address = 
aws_byte_cursor_from_c_str("fd00:ec2::23");
+        const struct aws_byte_cursor eks_container_host_ipv6_address_verbose =
+            aws_byte_cursor_from_c_str("fd00:ec2:0:0:0:0:0:23");
+
+        result |= aws_byte_cursor_eq(&address, &ipv6_loopback_address);
+        result |= aws_byte_cursor_eq(&address, &ipv6_loopback_address_verbose);
+        result |= aws_byte_cursor_eq(&address, 
&eks_container_host_ipv6_address);
+        result |= aws_byte_cursor_eq(&address, 
&eks_container_host_ipv6_address_verbose);
+    }
+
+    return result;
+}
+
+static void s_on_host_resolved(
+    struct aws_host_resolver *resolver,
+    const struct aws_string *host_name,
+    int error_code,
+    const struct aws_array_list *host_addresses,
+    void *user_data) {
+    (void)resolver;
+    (void)host_name;
+
+    struct aws_credentials_provider_ecs_user_data *ecs_user_data = user_data;
+    if (error_code) {
+        AWS_LOGF_WARN(
+            AWS_LS_AUTH_CREDENTIALS_PROVIDER,
+            "id=%p: ECS provider failed to resolve host, error code %d(%s)",
+            (void *)ecs_user_data->ecs_provider,
+            error_code,
+            aws_error_str(error_code));
+        ecs_user_data->error_code = error_code;
+        s_ecs_finalize_get_credentials_query(ecs_user_data);
+        return;
+    }
+    size_t host_addresses_len = aws_array_list_length(host_addresses);
+    if (!host_addresses_len) {
+        goto on_error;
+    }
+    for (size_t i = 0; i < host_addresses_len; ++i) {
+        struct aws_host_address *host_address_ptr = NULL;
+        aws_array_list_get_at_ptr(host_addresses, (void **)&host_address_ptr, 
i);
+        if (!s_is_valid_remote_host_ip(host_address_ptr)) {
+            goto on_error;
+        }
+    }
+    struct aws_credentials_provider_ecs_impl *impl = 
ecs_user_data->ecs_provider->impl;
+    impl->function_table->aws_http_connection_manager_acquire_connection(
+        impl->connection_manager, s_ecs_on_acquire_connection, ecs_user_data);
+
+    return;
+on_error:
+    AWS_LOGF_ERROR(
+        AWS_LS_AUTH_CREDENTIALS_PROVIDER,
+        "id=%p: ECS provider failed to resolve address to an allowed ip 
address with error %d(%s)",
+        (void *)ecs_user_data->ecs_provider,
+        AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST,
+        aws_error_str(AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST));
+    ecs_user_data->error_code = AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST;
+    s_ecs_finalize_get_credentials_query(ecs_user_data);
+}
+
 static int s_credentials_provider_ecs_get_credentials_async(
     struct aws_credentials_provider *provider,
     aws_on_get_credentials_callback_fn callback,
@@ -474,10 +562,19 @@
     if (wrapped_user_data == NULL) {
         goto error;
     }
-
-    impl->function_table->aws_http_connection_manager_acquire_connection(
-        impl->connection_manager, s_ecs_on_acquire_connection, 
wrapped_user_data);
-
+    /* No need to verify the host IP address if the connection is using HTTPS 
or the ECS container host (relative URI)
+     */
+    if (impl->is_https || aws_string_eq(impl->host, s_ecs_host)) {
+        impl->function_table->aws_http_connection_manager_acquire_connection(
+            impl->connection_manager, s_ecs_on_acquire_connection, 
wrapped_user_data);
+    } else if (aws_host_resolver_resolve_host(
+                   impl->bootstrap->host_resolver,
+                   impl->host,
+                   s_on_host_resolved,
+                   &impl->bootstrap->host_resolver_config,
+                   wrapped_user_data)) {
+        goto error;
+    }
     return AWS_OP_SUCCESS;
 
 error:
@@ -497,6 +594,7 @@
     aws_string_destroy(impl->auth_token);
     aws_string_destroy(impl->auth_token_file_path);
     aws_string_destroy(impl->host);
+    aws_client_bootstrap_release(impl->bootstrap);
 
     /* aws_http_connection_manager_release will eventually leads to call of 
s_on_connection_manager_shutdown,
      * which will do memory release for provider and impl. So We should be 
freeing impl
@@ -554,7 +652,7 @@
     AWS_ZERO_STRUCT(*impl);
 
     aws_credentials_provider_init_base(provider, allocator, 
&s_aws_credentials_provider_ecs_vtable, impl);
-
+    impl->bootstrap = aws_client_bootstrap_acquire(options->bootstrap);
     struct aws_tls_connection_options tls_connection_options;
     AWS_ZERO_STRUCT(tls_connection_options);
     if (options->tls_ctx) {
@@ -568,6 +666,7 @@
                 aws_error_debug_str(aws_last_error()));
             goto on_error;
         }
+        impl->is_https = true;
     }
 
     struct aws_socket_options socket_options;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/aws-c-auth-0.7.22/source/credentials_provider_profile.c 
new/aws-c-auth-0.7.23/source/credentials_provider_profile.c
--- old/aws-c-auth-0.7.22/source/credentials_provider_profile.c 2024-05-15 
20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/source/credentials_provider_profile.c 2024-07-30 
22:21:36.000000000 +0200
@@ -23,6 +23,7 @@
 
 AWS_STRING_FROM_LITERAL(s_role_arn_name, "role_arn");
 AWS_STRING_FROM_LITERAL(s_role_session_name_name, "role_session_name");
+AWS_STRING_FROM_LITERAL(s_external_id_name, "external_id");
 AWS_STRING_FROM_LITERAL(s_credential_source_name, "credential_source");
 AWS_STRING_FROM_LITERAL(s_source_profile_name, "source_profile");
 AWS_STRING_FROM_LITERAL(s_access_key_id_profile_var, "aws_access_key_id");
@@ -235,6 +236,7 @@
     struct aws_hash_table *source_profiles_table) {
     struct aws_credentials_provider *provider = NULL;
 
+    /* role_arn */
     AWS_LOGF_INFO(
         AWS_LS_AUTH_CREDENTIALS_PROVIDER,
         "static: profile %s has role_arn property is set to %s, attempting to "
@@ -247,6 +249,7 @@
     const struct aws_profile_property *credential_source_property =
         aws_profile_get_property(profile, s_credential_source_name);
 
+    /* role_session_name */
     const struct aws_profile_property *role_session_name = 
aws_profile_get_property(profile, s_role_session_name_name);
     char session_name_array[MAX_SESSION_NAME_LEN + 1];
     AWS_ZERO_ARRAY(session_name_array);
@@ -274,6 +277,13 @@
 
     AWS_LOGF_DEBUG(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "static: computed 
session_name as %s", session_name_array);
 
+    /* external_id */
+    struct aws_byte_cursor external_id = {0};
+    const struct aws_profile_property *external_id_property = 
aws_profile_get_property(profile, s_external_id_name);
+    if (external_id_property) {
+        external_id = 
aws_byte_cursor_from_string(aws_profile_property_get_value(external_id_property));
+    }
+
     /* Automatically create a TLS context if necessary. We'd prefer that users 
pass one in, but can't force
      * them to because aws_credentials_provider_profile_options didn't always 
have a tls_ctx member. */
     struct aws_tls_ctx *tls_ctx = NULL;
@@ -301,6 +311,7 @@
         .bootstrap = options->bootstrap,
         .tls_ctx = tls_ctx,
         .role_arn = 
aws_byte_cursor_from_string(aws_profile_property_get_value(role_arn_property)),
+        .external_id = external_id,
         .session_name = aws_byte_cursor_from_c_str(session_name_array),
         .profile_name_override = options->profile_name_override,
         .config_file_name_override = options->config_file_name_override,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/source/credentials_provider_sts.c 
new/aws-c-auth-0.7.23/source/credentials_provider_sts.c
--- old/aws-c-auth-0.7.22/source/credentials_provider_sts.c     2024-05-15 
20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/source/credentials_provider_sts.c     2024-07-30 
22:21:36.000000000 +0200
@@ -57,6 +57,7 @@
     struct aws_http_connection_manager *connection_manager;
     struct aws_string *assume_role_profile;
     struct aws_string *role_session_name;
+    struct aws_string *external_id;
     struct aws_string *endpoint;
     struct aws_string *region;
     uint16_t duration_seconds;
@@ -157,6 +158,18 @@
         return AWS_OP_ERR;
     }
 
+    if (provider_impl->external_id != NULL) {
+        working_cur = aws_byte_cursor_from_c_str("&ExternalId=");
+        if (aws_byte_buf_append_dynamic(body, &working_cur)) {
+            return AWS_OP_ERR;
+        }
+
+        struct aws_byte_cursor external_id_cur = 
aws_byte_cursor_from_string(provider_impl->external_id);
+        if (aws_byte_buf_append_encoding_uri_param(body, &external_id_cur)) {
+            return AWS_OP_ERR;
+        }
+    }
+
     working_cur = aws_byte_cursor_from_c_str("&DurationSeconds=");
     if (aws_byte_buf_append_dynamic(body, &working_cur)) {
         return AWS_OP_ERR;
@@ -652,6 +665,7 @@
 
     aws_string_destroy(impl->role_session_name);
     aws_string_destroy(impl->assume_role_profile);
+    aws_string_destroy(impl->external_id);
     aws_string_destroy(impl->endpoint);
     aws_string_destroy(impl->region);
     aws_mem_release(provider->allocator, provider);
@@ -739,6 +753,18 @@
         return NULL;
     }
 
+    if (options->role_arn.len == 0) {
+        AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "role_arn is 
necessary for querying STS");
+        aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+        return NULL;
+    }
+
+    if (options->session_name.len == 0) {
+        AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "role_session_name is 
necessary for querying STS");
+        aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+        return NULL;
+    }
+
     struct aws_credentials_provider *provider = NULL;
     struct aws_credentials_provider_sts_impl *impl = NULL;
     int result = AWS_OP_ERR;
@@ -780,29 +806,28 @@
 
     impl->role_session_name =
         aws_string_new_from_array(allocator, options->session_name.ptr, 
options->session_name.len);
-
-    if (!impl->role_session_name) {
-        goto on_done;
-    }
-
     AWS_LOGF_DEBUG(
         AWS_LS_AUTH_CREDENTIALS_PROVIDER,
-        "(id=%p): using session_name %s",
+        "(id=%p): using role_session_name '%s'",
         (void *)provider,
         aws_string_c_str(impl->role_session_name));
 
     impl->assume_role_profile = aws_string_new_from_array(allocator, 
options->role_arn.ptr, options->role_arn.len);
-
-    if (!impl->assume_role_profile) {
-        goto on_done;
-    }
-
     AWS_LOGF_DEBUG(
         AWS_LS_AUTH_CREDENTIALS_PROVIDER,
-        "(id=%p): using assume_role_arn %s",
+        "(id=%p): using role_arn '%s'",
         (void *)provider,
         aws_string_c_str(impl->assume_role_profile));
 
+    if (options->external_id.len > 0) {
+        impl->external_id = aws_string_new_from_cursor(allocator, 
&options->external_id);
+        AWS_LOGF_DEBUG(
+            AWS_LS_AUTH_CREDENTIALS_PROVIDER,
+            "(id=%p): using external_id '%s'",
+            (void *)provider,
+            aws_string_c_str(impl->external_id));
+    }
+
     impl->duration_seconds = options->duration_seconds;
 
     if (options->system_clock_fn != NULL) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/aws-c-auth-0.7.22/tests/CMakeLists.txt 
new/aws-c-auth-0.7.23/tests/CMakeLists.txt
--- old/aws-c-auth-0.7.22/tests/CMakeLists.txt  2024-05-15 20:46:22.000000000 
+0200
+++ new/aws-c-auth-0.7.23/tests/CMakeLists.txt  2024-07-30 22:21:36.000000000 
+0200
@@ -45,16 +45,17 @@
     add_test_case(credentials_provider_imds_real_success)
 endif()
 
-add_test_case(credentials_provider_ecs_new_destroy)
-add_test_case(credentials_provider_ecs_connect_failure)
-add_test_case(credentials_provider_ecs_request_failure)
-add_test_case(credentials_provider_ecs_bad_document_failure)
-add_test_case(credentials_provider_ecs_basic_success)
-add_test_case(credentials_provider_ecs_basic_success_token_file)
+add_net_test_case(credentials_provider_ecs_new_destroy)
+add_net_test_case(credentials_provider_ecs_connect_failure)
+add_net_test_case(credentials_provider_ecs_request_failure)
+add_net_test_case(credentials_provider_ecs_bad_document_failure)
+add_net_test_case(credentials_provider_ecs_bad_host_failure)
+add_net_test_case(credentials_provider_ecs_basic_success)
+add_net_test_case(credentials_provider_ecs_basic_success_token_file)
 add_net_test_case(credentials_provider_ecs_basic_success_uri_env)
-add_test_case(credentials_provider_ecs_no_auth_token_success)
-add_test_case(credentials_provider_ecs_success_multi_part_doc)
-add_test_case(credentials_provider_ecs_real_new_destroy)
+add_net_test_case(credentials_provider_ecs_no_auth_token_success)
+add_net_test_case(credentials_provider_ecs_success_multi_part_doc)
+add_net_test_case(credentials_provider_ecs_real_new_destroy)
 
 if(AWS_BUILDING_ON_ECS)
     add_test_case(credentials_provider_ecs_real_success)
@@ -84,6 +85,7 @@
 add_net_test_case(credentials_provider_sts_web_identity_real_new_destroy)
 
 add_net_test_case(credentials_provider_sts_direct_config_succeeds)
+add_net_test_case(credentials_provider_sts_direct_config_with_external_id_succeeds)
 add_net_test_case(credentials_provider_sts_direct_config_with_region_succeeds)
 
add_net_test_case(credentials_provider_sts_direct_config_with_default_region_succeeds)
 
add_net_test_case(credentials_provider_sts_direct_config_with_region_from_config_succeeds)
@@ -92,6 +94,7 @@
 add_net_test_case(credentials_provider_sts_direct_config_connection_failed)
 add_net_test_case(credentials_provider_sts_direct_config_service_fails)
 add_net_test_case(credentials_provider_sts_from_profile_config_succeeds)
+add_net_test_case(credentials_provider_sts_from_profile_config_with_external_id)
 add_net_test_case(credentials_provider_sts_from_profile_config_with_chain)
 
add_net_test_case(credentials_provider_sts_from_profile_config_with_ecs_credentials_source)
 
add_net_test_case(credentials_provider_sts_from_profile_config_with_chain_and_profile_creds)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/aws-c-auth-0.7.22/tests/credentials_provider_ecs_tests.c 
new/aws-c-auth-0.7.23/tests/credentials_provider_ecs_tests.c
--- old/aws-c-auth-0.7.22/tests/credentials_provider_ecs_tests.c        
2024-05-15 20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/tests/credentials_provider_ecs_tests.c        
2024-07-30 22:21:36.000000000 +0200
@@ -54,6 +54,7 @@
     struct aws_event_loop_group *el_group;
     struct aws_host_resolver *host_resolver;
     struct aws_client_bootstrap *bootstrap;
+    struct aws_tls_ctx *tls_ctx;
 };
 
 static struct aws_mock_ecs_tester s_tester;
@@ -259,6 +260,13 @@
     };
     s_tester.bootstrap = aws_client_bootstrap_new(allocator, 
&bootstrap_options);
 
+    struct aws_tls_ctx_options tls_options;
+    aws_tls_ctx_options_init_default_client(&tls_options, allocator);
+    struct aws_tls_ctx *tls_ctx = aws_tls_client_ctx_new(allocator, 
&tls_options);
+    ASSERT_NOT_NULL(tls_ctx);
+    s_tester.tls_ctx = tls_ctx;
+    aws_tls_ctx_options_clean_up(&tls_options);
+
     /* ensure pre-existing environment doesn't interfere with tests */
     aws_unset_environment_value(s_ecs_creds_env_relative_uri);
     aws_unset_environment_value(s_ecs_creds_env_full_uri);
@@ -279,6 +287,7 @@
     aws_client_bootstrap_release(s_tester.bootstrap);
     aws_host_resolver_release(s_tester.host_resolver);
     aws_event_loop_group_release(s_tester.el_group);
+    aws_tls_ctx_release(s_tester.tls_ctx);
     AWS_ZERO_STRUCT(s_tester);
 }
 
@@ -362,6 +371,7 @@
         .host = 
aws_byte_cursor_from_c_str("www.xxx123321testmocknonexsitingawsservice.com"),
         .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
         .auth_token = aws_byte_cursor_from_c_str("test-token-1234-abcd"),
+        .tls_ctx = s_tester.tls_ctx,
     };
 
     struct aws_credentials_provider *provider = 
aws_credentials_provider_new_ecs(allocator, &options);
@@ -373,7 +383,7 @@
     aws_mutex_lock(&s_tester.lock);
     ASSERT_TRUE(s_tester.has_received_credentials_callback == true);
     ASSERT_TRUE(s_tester.credentials == NULL);
-    ASSERT_UINT_EQUALS(80, s_tester.selected_port);
+    ASSERT_UINT_EQUALS(443, s_tester.selected_port);
     aws_mutex_unlock(&s_tester.lock);
 
     aws_credentials_provider_release(provider);
@@ -407,6 +417,7 @@
         .host = 
aws_byte_cursor_from_c_str("www.xxx123321testmocknonexsitingawsservice.com"),
         .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
         .auth_token = aws_byte_cursor_from_c_str("test-token-1234-abcd"),
+        .tls_ctx = s_tester.tls_ctx,
     };
 
     struct aws_credentials_provider *provider = 
aws_credentials_provider_new_ecs(allocator, &options);
@@ -419,7 +430,7 @@
     ASSERT_STR_EQUALS("/path/to/resource/?a=b&c=d", 
aws_string_c_str(s_tester.request_path_and_query));
     ASSERT_TRUE(s_tester.has_received_credentials_callback == true);
     ASSERT_TRUE(s_tester.credentials == NULL);
-    ASSERT_UINT_EQUALS(80, s_tester.selected_port);
+    ASSERT_UINT_EQUALS(443, s_tester.selected_port);
     aws_mutex_unlock(&s_tester.lock);
 
     aws_credentials_provider_release(provider);
@@ -457,7 +468,7 @@
         .host = 
aws_byte_cursor_from_c_str("www.xxx123321testmocknonexsitingawsservice.com"),
         .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
         .auth_token = aws_byte_cursor_from_c_str("test-token-1234-abcd"),
-        .port = 555,
+        .tls_ctx = s_tester.tls_ctx,
     };
 
     struct aws_credentials_provider *provider = 
aws_credentials_provider_new_ecs(allocator, &options);
@@ -471,7 +482,7 @@
 
     ASSERT_TRUE(s_tester.has_received_credentials_callback == true);
     ASSERT_TRUE(s_tester.credentials == NULL);
-    ASSERT_UINT_EQUALS(555, s_tester.selected_port);
+    ASSERT_UINT_EQUALS(443, s_tester.selected_port);
     aws_mutex_unlock(&s_tester.lock);
 
     aws_credentials_provider_release(provider);
@@ -488,6 +499,49 @@
 
 AWS_TEST_CASE(credentials_provider_ecs_bad_document_failure, 
s_credentials_provider_ecs_bad_document_failure);
 
+static int s_credentials_provider_ecs_bad_host_failure(struct aws_allocator 
*allocator, void *ctx) {
+    (void)ctx;
+
+    s_aws_ecs_tester_init(allocator);
+
+    struct aws_credentials_provider_ecs_options options = {
+        .bootstrap = s_tester.bootstrap,
+        .function_table = &s_mock_function_table,
+        .shutdown_options =
+            {
+                .shutdown_callback = s_on_shutdown_complete,
+                .shutdown_user_data = NULL,
+            },
+        .host = aws_byte_cursor_from_c_str("www.google.com"),
+        .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
+        .auth_token = aws_byte_cursor_from_c_str("test-token-1234-abcd"),
+    };
+
+    struct aws_credentials_provider *provider = 
aws_credentials_provider_new_ecs(allocator, &options);
+
+    aws_credentials_provider_get_credentials(provider, 
s_get_credentials_callback, NULL);
+
+    s_aws_wait_for_credentials_result();
+
+    aws_mutex_lock(&s_tester.lock);
+    ASSERT_NULL(s_tester.credentials);
+    ASSERT_INT_EQUALS(AWS_AUTH_CREDENTIALS_PROVIDER_ECS_INVALID_HOST, 
s_tester.error_code);
+    aws_mutex_unlock(&s_tester.lock);
+
+    aws_credentials_provider_release(provider);
+
+    s_aws_wait_for_provider_shutdown_callback();
+
+    /* Because we mock the http connection manager, we never get a callback 
back from it */
+    aws_mem_release(provider->allocator, provider);
+
+    s_aws_ecs_tester_cleanup();
+
+    return 0;
+}
+
+AWS_TEST_CASE(credentials_provider_ecs_bad_host_failure, 
s_credentials_provider_ecs_bad_host_failure);
+
 AWS_STATIC_STRING_FROM_LITERAL(
     s_good_response,
     "{\"AccessKeyId\":\"SuccessfulAccessKey\", \n  
\"SecretAccessKey\":\"SuccessfulSecret\", \n  "
@@ -655,12 +709,13 @@
         .host = 
aws_byte_cursor_from_c_str("www.xxx123321testmocknonexsitingawsservice.com"),
         .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
         .auth_token = aws_byte_cursor_from_c_str("test-token-1234-abcd"),
+        .tls_ctx = s_tester.tls_ctx,
     };
 
     ASSERT_SUCCESS(s_do_ecs_success_test(
         allocator,
         &options,
-        
"http://www.xxx123321testmocknonexsitingawsservice.com:80/path/to/resource/?a=b&c=d";
 /*expected_uri*/,
+        
"https://www.xxx123321testmocknonexsitingawsservice.com:443/path/to/resource/?a=b&c=d";
 /*expected_uri*/,
         "test-token-1234-abcd" /*expected_token*/));
 
     s_aws_ecs_tester_cleanup();
@@ -697,6 +752,7 @@
         .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
         .auth_token = aws_byte_cursor_from_string(auth_token),
         .auth_token_file_path = aws_byte_cursor_from_string(token_file_path),
+        .tls_ctx = s_tester.tls_ctx,
     };
 
     struct aws_credentials_provider *provider = 
aws_credentials_provider_new_ecs(allocator, &options);
@@ -707,7 +763,7 @@
 
     aws_mutex_lock(&s_tester.lock);
     ASSERT_SUCCESS(s_check_ecs_tester_request_uri_and_authorization(
-        
"http://www.xxx123321testmocknonexsitingawsservice.com:80/path/to/resource/?a=b&c=d";,
+        
"https://www.xxx123321testmocknonexsitingawsservice.com:443/path/to/resource/?a=b&c=d";,
         aws_string_c_str(auth_token)));
 
     aws_string_destroy(s_tester.request_path_and_query);
@@ -726,7 +782,7 @@
 
     aws_mutex_lock(&s_tester.lock);
     ASSERT_SUCCESS(s_check_ecs_tester_request_uri_and_authorization(
-        
"http://www.xxx123321testmocknonexsitingawsservice.com:80/path/to/resource/?a=b&c=d";,
+        
"https://www.xxx123321testmocknonexsitingawsservice.com:443/path/to/resource/?a=b&c=d";,
         aws_string_c_str(auth_token2)));
 
     aws_mutex_unlock(&s_tester.lock);
@@ -819,14 +875,33 @@
             .auth_token_file_content = "testToken",
             .expected_auth_token = "testToken",
         },
+        /* IPv4 loopback address */
+        {
+            .full_uri = "http://127.1.2.3:456/credentials";,
+            .expected_uri = "http://127.1.2.3:456/credentials";,
+        },
+        /* IPv4 EKS container host address */
+        {
+            .full_uri = "http://169.254.170.23:8080/credentials";,
+            .expected_uri = "http://169.254.170.23:8080/credentials";,
+        },
+        /* IPv4 ECS container host address */
+        {
+            .full_uri = "http://169.254.170.2:8080/credentials";,
+            .expected_uri = "http://169.254.170.2:8080/credentials";,
+        },
+        /* IPv6 loopback address */
+        {
+            .full_uri = "http://[::1]:8080/credentials";,
+            .expected_uri = "http://[::1]:8080/credentials";,
+        },
+        /* IPv6 EKS host */
+        {
+            .full_uri = "http://[fd00:ec2::23]:8080/credentials";,
+            .expected_uri = "http://[fd00:ec2::23]:8080/credentials";,
+        },
     };
 
-    /* Provide tls_ctx, in case FULL_URI scheme is "https://"; */
-    struct aws_tls_ctx_options tls_options;
-    aws_tls_ctx_options_init_default_client(&tls_options, allocator);
-    struct aws_tls_ctx *tls_ctx = aws_tls_client_ctx_new(allocator, 
&tls_options);
-    ASSERT_NOT_NULL(tls_ctx);
-
     for (size_t case_idx = 0; case_idx < AWS_ARRAY_SIZE(test_cases); 
++case_idx) {
         struct test_case case_i = test_cases[case_idx];
         printf(
@@ -852,7 +927,7 @@
                     .shutdown_callback = s_on_shutdown_complete,
                     .shutdown_user_data = NULL,
                 },
-            .tls_ctx = tls_ctx,
+            .tls_ctx = s_tester.tls_ctx,
         };
 
         ASSERT_SUCCESS(s_do_ecs_env_success_test(
@@ -868,8 +943,6 @@
         s_aws_ecs_tester_reset();
     }
 
-    aws_tls_ctx_release(tls_ctx);
-    aws_tls_ctx_options_clean_up(&tls_options);
     s_aws_ecs_tester_cleanup();
     return 0;
 }
@@ -893,12 +966,13 @@
             },
         .host = 
aws_byte_cursor_from_c_str("www.xxx123321testmocknonexsitingawsservice.com"),
         .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
+        .tls_ctx = s_tester.tls_ctx,
     };
 
     ASSERT_SUCCESS(s_do_ecs_success_test(
         allocator,
         &options,
-        
"http://www.xxx123321testmocknonexsitingawsservice.com:80/path/to/resource/?a=b&c=d";
 /*expected_uri*/,
+        
"https://www.xxx123321testmocknonexsitingawsservice.com:443/path/to/resource/?a=b&c=d";
 /*expected_uri*/,
         NULL /*expected_token*/));
 
     s_aws_ecs_tester_cleanup();
@@ -935,6 +1009,7 @@
         .host = 
aws_byte_cursor_from_c_str("www.xxx123321testmocknonexsitingawsservice.com"),
         .path_and_query = 
aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"),
         .auth_token = aws_byte_cursor_from_c_str("test-token-1234-abcd"),
+        .tls_ctx = s_tester.tls_ctx,
     };
 
     struct aws_credentials_provider *provider = 
aws_credentials_provider_new_ecs(allocator, &options);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/aws-c-auth-0.7.22/tests/credentials_provider_sts_tests.c 
new/aws-c-auth-0.7.23/tests/credentials_provider_sts_tests.c
--- old/aws-c-auth-0.7.22/tests/credentials_provider_sts_tests.c        
2024-05-15 20:46:22.000000000 +0200
+++ new/aws-c-auth-0.7.23/tests/credentials_provider_sts_tests.c        
2024-07-30 22:21:36.000000000 +0200
@@ -388,6 +388,7 @@
 static struct aws_byte_cursor s_role_arn_cur =
     AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("arn:aws:iam::67895:role/test_role");
 static struct aws_byte_cursor s_session_name_cur = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("test_session");
+static struct aws_byte_cursor s_external_id_cur = 
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("externalId123_+=,.@:\\/-");
 
 static struct aws_byte_cursor s_success_creds_doc =
     AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("<AssumeRoleResponse xmlns=\"who 
cares\">\n"
@@ -410,6 +411,14 @@
     
AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Version=2011-06-15&Action=AssumeRole&RoleArn=arn%3Aaws%3Aiam%3A%3A67895%"
                                           
"3Arole%2Ftest_role&RoleSessionName=test_session&DurationSeconds=900");
 
+static struct aws_byte_cursor s_expected_payload_with_external_id =
+    AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Version=2011-06-15"
+                                          "&Action=AssumeRole"
+                                          
"&RoleArn=arn%3Aaws%3Aiam%3A%3A67895%3Arole%2Ftest_role"
+                                          "&RoleSessionName=test_session"
+                                          
"&ExternalId=externalId123_%2B%3D%2C.%40%3A%5C%2F-"
+                                          "&DurationSeconds=900");
+
 AWS_STATIC_STRING_FROM_LITERAL(s_access_key_id_response, "accessKeyIdResp");
 AWS_STATIC_STRING_FROM_LITERAL(s_secret_access_key_response, "secretKeyResp");
 AWS_STATIC_STRING_FROM_LITERAL(s_session_token_response, "sessionTokenResp");
@@ -508,6 +517,61 @@
 
 AWS_TEST_CASE(credentials_provider_sts_direct_config_succeeds, 
s_credentials_provider_sts_direct_config_succeeds_fn)
 
+static int 
s_credentials_provider_sts_direct_config_with_external_id_succeeds_fn(
+    struct aws_allocator *allocator,
+    void *ctx) {
+    (void)ctx;
+
+    s_aws_sts_tester_init(allocator);
+
+    struct aws_credentials_provider_static_options static_options = {
+        .access_key_id = s_access_key_cur,
+        .secret_access_key = s_secret_key_cur,
+        .session_token = s_session_token_cur,
+    };
+    struct aws_credentials_provider *static_provider = 
aws_credentials_provider_new_static(allocator, &static_options);
+
+    struct aws_credentials_provider_sts_options options = {
+        .creds_provider = static_provider,
+        .bootstrap = s_tester.bootstrap,
+        .tls_ctx = s_tester.tls_ctx,
+        .role_arn = s_role_arn_cur,
+        .session_name = s_session_name_cur,
+        .external_id = s_external_id_cur,
+        .duration_seconds = 0,
+        .function_table = &s_mock_function_table,
+        .system_clock_fn = mock_aws_get_system_time,
+    };
+
+    mock_aws_set_system_time(0);
+
+    aws_array_list_push_back(&s_tester.response_data_callbacks, 
&s_success_creds_doc);
+    s_tester.mock_response_code = 200;
+
+    struct aws_credentials_provider *sts_provider = 
aws_credentials_provider_new_sts(allocator, &options);
+
+    aws_credentials_provider_get_credentials(sts_provider, 
s_get_credentials_callback, NULL);
+
+    s_aws_wait_for_credentials_result();
+
+    ASSERT_BIN_ARRAYS_EQUALS(
+        s_expected_payload_with_external_id.ptr,
+        s_expected_payload_with_external_id.len,
+        s_tester.mocked_requests[0].body.buffer,
+        s_tester.mocked_requests[0].body.len);
+
+    aws_credentials_provider_release(sts_provider);
+    s_aws_wait_for_provider_shutdown_callback();
+    aws_credentials_provider_release(static_provider);
+    ASSERT_SUCCESS(s_aws_sts_tester_cleanup());
+
+    return AWS_OP_SUCCESS;
+}
+
+AWS_TEST_CASE(
+    credentials_provider_sts_direct_config_with_external_id_succeeds,
+    s_credentials_provider_sts_direct_config_with_external_id_succeeds_fn)
+
 static int s_credentials_provider_sts_direct_config_with_region_succeeds_fn(
     struct aws_allocator *allocator,
     void *ctx) {
@@ -1043,31 +1107,41 @@
     credentials_provider_sts_direct_config_service_fails,
     s_credentials_provider_sts_direct_config_service_fails_fn)
 
-static const char *s_soure_profile_config_file = "[default]\n"
-                                                 "aws_access_key_id=BLAHBLAH\n"
-                                                 
"aws_secret_access_key=BLAHBLAHBLAH\n"
-                                                 "\n"
-                                                 "[roletest]\n"
-                                                 
"role_arn=arn:aws:iam::67895:role/test_role\n"
-                                                 "source_profile=default\n"
-                                                 
"role_session_name=test_session";
-
-static const char *s_soure_profile_chain_config_file = "[default]\n"
-                                                       
"aws_access_key_id=BLAHBLAH\n"
-                                                       
"aws_secret_access_key=BLAHBLAHBLAH\n"
-                                                       "\n"
-                                                       "[roletest]\n"
-                                                       
"role_arn=arn:aws:iam::67895:role/test_role\n"
-                                                       
"source_profile=roletest2\n"
-                                                       
"role_session_name=test_session\n"
-                                                       "[roletest2]\n"
-                                                       
"role_arn=arn:aws:iam::67896:role/test_role\n"
-                                                       
"source_profile=roletest3\n"
-                                                       
"role_session_name=test_session2\n"
-                                                       "[roletest3]\n"
-                                                       
"role_arn=arn:aws:iam::67897:role/test_role\n"
-                                                       
"source_profile=default\n"
-                                                       
"role_session_name=test_session3\n";
+static const char *s_source_profile_config_file = "[default]\n"
+                                                  
"aws_access_key_id=BLAHBLAH\n"
+                                                  
"aws_secret_access_key=BLAHBLAHBLAH\n"
+                                                  "\n"
+                                                  "[roletest]\n"
+                                                  
"role_arn=arn:aws:iam::67895:role/test_role\n"
+                                                  "source_profile=default\n"
+                                                  
"role_session_name=test_session";
+
+static const char *s_source_profile_external_id_config_file = "[default]\n"
+                                                              
"aws_access_key_id=BLAHBLAH\n"
+                                                              
"aws_secret_access_key=BLAHBLAHBLAH\n"
+                                                              "\n"
+                                                              "[roletest]\n"
+                                                              
"role_arn=arn:aws:iam::67895:role/test_role\n"
+                                                              
"source_profile=default\n"
+                                                              
"role_session_name=test_session\n"
+                                                              
"external_id=externalId123_+=,.@:\\/-\n";
+
+static const char *s_source_profile_chain_config_file = "[default]\n"
+                                                        
"aws_access_key_id=BLAHBLAH\n"
+                                                        
"aws_secret_access_key=BLAHBLAHBLAH\n"
+                                                        "\n"
+                                                        "[roletest]\n"
+                                                        
"role_arn=arn:aws:iam::67895:role/test_role\n"
+                                                        
"source_profile=roletest2\n"
+                                                        
"role_session_name=test_session\n"
+                                                        "[roletest2]\n"
+                                                        
"role_arn=arn:aws:iam::67896:role/test_role\n"
+                                                        
"source_profile=roletest3\n"
+                                                        
"role_session_name=test_session2\n"
+                                                        "[roletest3]\n"
+                                                        
"role_arn=arn:aws:iam::67897:role/test_role\n"
+                                                        
"source_profile=default\n"
+                                                        
"role_session_name=test_session3\n";
 
 static int s_credentials_provider_sts_from_profile_config_with_chain_fn(struct 
aws_allocator *allocator, void *ctx) {
     (void)ctx;
@@ -1078,7 +1152,7 @@
 
     s_aws_sts_tester_init(allocator);
     s_tester.expected_connection_manager_shutdown_callback_count = 3;
-    struct aws_string *config_contents = aws_string_new_from_c_str(allocator, 
s_soure_profile_chain_config_file);
+    struct aws_string *config_contents = aws_string_new_from_c_str(allocator, 
s_source_profile_chain_config_file);
 
     struct aws_string *config_file_str = 
aws_create_process_unique_file_name(allocator);
     struct aws_string *creds_file_str = 
aws_create_process_unique_file_name(allocator);
@@ -1676,7 +1750,7 @@
 
     s_aws_sts_tester_init(allocator);
 
-    struct aws_string *config_contents = aws_string_new_from_c_str(allocator, 
s_soure_profile_config_file);
+    struct aws_string *config_contents = aws_string_new_from_c_str(allocator, 
s_source_profile_config_file);
 
     struct aws_string *config_file_str = 
aws_create_process_unique_file_name(allocator);
     struct aws_string *creds_file_str = 
aws_create_process_unique_file_name(allocator);
@@ -1763,6 +1837,63 @@
     credentials_provider_sts_from_profile_config_manual_tls_succeeds,
     credentials_provider_sts_from_profile_config_manual_tls_succeeds_fn)
 
+static int s_credentials_provider_sts_from_profile_config_with_external_id_fn(
+    struct aws_allocator *allocator,
+    void *ctx) {
+    (void)ctx;
+
+    aws_unset_environment_value(s_default_profile_env_variable_name);
+    aws_unset_environment_value(s_default_config_path_env_variable_name);
+    aws_unset_environment_value(s_default_credentials_path_env_variable_name);
+
+    s_aws_sts_tester_init(allocator);
+
+    struct aws_string *config_contents = aws_string_new_from_c_str(allocator, 
s_source_profile_external_id_config_file);
+
+    struct aws_string *config_file_str = 
aws_create_process_unique_file_name(allocator);
+    struct aws_string *creds_file_str = 
aws_create_process_unique_file_name(allocator);
+
+    ASSERT_SUCCESS(aws_create_profile_file(creds_file_str, config_contents));
+    aws_string_destroy(config_contents);
+
+    struct aws_credentials_provider_profile_options options = {
+        .config_file_name_override = 
aws_byte_cursor_from_string(config_file_str),
+        .credentials_file_name_override = 
aws_byte_cursor_from_string(creds_file_str),
+        .profile_name_override = aws_byte_cursor_from_c_str("roletest"),
+        .bootstrap = s_tester.bootstrap,
+        .tls_ctx = s_tester.tls_ctx,
+        .function_table = &s_mock_function_table,
+    };
+
+    aws_array_list_push_back(&s_tester.response_data_callbacks, 
&s_success_creds_doc);
+    s_tester.mock_response_code = 200;
+
+    struct aws_credentials_provider *provider = 
aws_credentials_provider_new_profile(allocator, &options);
+    ASSERT_NOT_NULL(provider);
+
+    aws_string_destroy(config_file_str);
+    aws_string_destroy(creds_file_str);
+
+    aws_credentials_provider_get_credentials(provider, 
s_get_credentials_callback, NULL);
+
+    s_aws_wait_for_credentials_result();
+
+    ASSERT_BIN_ARRAYS_EQUALS(
+        s_expected_payload_with_external_id.ptr,
+        s_expected_payload_with_external_id.len,
+        s_tester.mocked_requests[0].body.buffer,
+        s_tester.mocked_requests[0].body.len);
+
+    aws_credentials_provider_release(provider);
+    s_aws_wait_for_provider_shutdown_callback();
+    ASSERT_SUCCESS(s_aws_sts_tester_cleanup());
+
+    return AWS_OP_SUCCESS;
+}
+AWS_TEST_CASE(
+    credentials_provider_sts_from_profile_config_with_external_id,
+    s_credentials_provider_sts_from_profile_config_with_external_id_fn)
+
 static const char *s_env_source_config_file = "[default]\n"
                                               "aws_access_key_id=BLAHBLAH\n"
                                               
"aws_secret_access_key=BLAHBLAHBLAH\n"

Reply via email to