Skip to content

Commit 8eaac64

Browse files
authored
CDRIVER-4439 add AWS credential cache (#1207)
* add test-awsauth test-awsauth is intended to replace mongoc-ping in AWS tests. test-awsauth will include caching tests specific to AWS. * unconditionally define _mongoc_aws_credentials_cleanup There is no reason to condition on the presence of ENABLE_MONGODB_AWS_AUTH Removing reduces duplicate definitions. * add AWS credential cache add _mongoc_aws_credentials_copy_to add _mongoc_aws_credentials_cache_t * use AWS credential cache * use test-awsauth in Evergreen * remove outdated docs of optional variables * fix docs to note TESTCASE is an env var * remove unnecessary additions runtime paths test-awsauth statically links the C driver * use `mcd_timer` for expiration * remove unused vars * simplify bash scripts * fix comment for `expiration` * be more explicit about _mongoc_aws_credentials_cache_get behavior * rename helper to expiration_to_mcd_timer * compute in int64_t domain * remove unnecessary expiration vars * add MONGOC_AWS_CREDENTIALS_INIT macro * only initialize and cleanup AWS cache if AWS is enabled * remove unnecessary can_setenv * fix -Wmissing-braces warning * fix signature of test_aws_cache * do not support uninitialized creds in _mongoc_aws_credentials_cache_get * do not reuse creds after cleanup * fix -Wmissing-field-initializers warning
1 parent 822e78e commit 8eaac64

File tree

10 files changed

+956
-94
lines changed

10 files changed

+956
-94
lines changed

.evergreen/generated_configs/legacy-config.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,11 +1789,11 @@ tasks:
17891789
shell: bash
17901790
script: |-
17911791
set -o errexit
1792-
# Compile mongoc-ping. Disable unnecessary dependencies since mongoc-ping is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
1792+
# Compile test-awsauth. Disable unnecessary dependencies since test-awsauth is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
17931793
. .evergreen/scripts/find-cmake.sh
17941794
export CC='${CC}'
17951795
$CMAKE -DENABLE_SASL=OFF -DENABLE_SNAPPY=OFF -DENABLE_ZSTD=OFF -DENABLE_CLIENT_SIDE_ENCRYPTION=OFF .
1796-
$CMAKE --build . --target mongoc-ping
1796+
$CMAKE --build . --target test-awsauth
17971797
- func: upload-build
17981798
- name: test-aws-openssl-regular-latest
17991799
depends_on:

.evergreen/legacy_config_generator/evergreen_config_lib/tasks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,11 +815,11 @@ def _check_allowed(self):
815815
all_tasks = chain(all_tasks, IPTask.matrix())
816816

817817
aws_compile_task = NamedTask('debug-compile-aws', commands=[shell_mongoc('''
818-
# Compile mongoc-ping. Disable unnecessary dependencies since mongoc-ping is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
818+
# Compile test-awsauth. Disable unnecessary dependencies since test-awsauth is copied to a remote Ubuntu 18.04 ECS cluster for testing, which may not have all dependent libraries.
819819
. .evergreen/scripts/find-cmake.sh
820820
export CC='${CC}'
821821
$CMAKE -DENABLE_SASL=OFF -DENABLE_SNAPPY=OFF -DENABLE_ZSTD=OFF -DENABLE_CLIENT_SIDE_ENCRYPTION=OFF .
822-
$CMAKE --build . --target mongoc-ping
822+
$CMAKE --build . --target test-awsauth
823823
'''), func('upload-build')])
824824

825825
all_tasks = chain(all_tasks, [aws_compile_task])

.evergreen/scripts/run-aws-tests.sh

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,12 @@
33
# Test runner for AWS authentication.
44
#
55
# This script is meant to be run in parts (so to isolate the AWS tests).
6-
# Pass the desired test first argument (REGULAR, EC2, ECS, ASSUME_ROLE, LAMBDA)
6+
# Pass the desired test as the environment variable TESTCASE: (REGULAR, EC2, ECS, ASSUME_ROLE, LAMBDA)
77
#
88
# Example:
9-
# run-aws-tests.sh EC2
9+
# TESTCASE=EC2 run-aws-tests.sh
1010
#
1111
# Optional environment variables:
12-
#
13-
# drivers_tools_dir
14-
# The path to clone of https://github.com/mongodb-labs/drivers-evergreen-tools.
15-
# Defaults to $(pwd)../drivers-evergreen-tools
16-
# mongoc_dir
17-
# The path to the build of mongo-c-driver (e.g. mongo-c-driver/cmake-build).
18-
# Defaults to $(pwd)
19-
# mongoc_dir
20-
# The path to mongo-c-driver source (may be same as mongoc_dir).
21-
# Defaults to $(pwd)
22-
# mongodb_bin_dir
23-
# The path to mongodb binaries.
24-
# Defaults to $(pwd)/mongodb/bin
2512
# iam_auth_ecs_account and iam_auth_ecs_secret_access_key
2613
# Set to access key id/secret access key. Required for some tests.
2714

@@ -46,49 +33,20 @@ declare drivers_tools_dir
4633
drivers_tools_dir="$(to_absolute "${mongoc_dir}/../drivers-evergreen-tools")"
4734

4835
declare mongodb_bin_dir="${mongoc_dir}/mongodb/bin"
49-
declare mongoc_ping="${mongoc_dir}/src/libmongoc/mongoc-ping"
36+
declare test_awsauth="${mongoc_dir}/src/libmongoc/test-awsauth"
5037

51-
# Add libmongoc-1.0 and libbson-1.0 to library path, so mongoc-ping can find them at runtime.
5238
if [[ "${OSTYPE}" == "cygwin" ]]; then
53-
export PATH
54-
PATH+=":${mongoc_dir}/src/libmongoc/Debug"
55-
PATH+=":${mongoc_dir}/src/libbson/Debug"
56-
57-
chmod -f +x src/libmongoc/Debug/* src/libbson/Debug/* || true
58-
59-
mongoc_ping="${mongoc_dir}/src/libmongoc/Debug/mongoc-ping.exe"
60-
elif [[ "${OSTYPE}" == darwin* ]]; then
61-
export DYLD_LIBRARY_PATH
62-
DYLD_LIBRARY_PATH+=":${mongoc_dir}/src/libmongoc"
63-
DYLD_LIBRARY_PATH+=":${mongoc_dir}/src/libbson"
64-
else
65-
export LD_LIBRARY_PATH
66-
LD_LIBRARY_PATH+=":${mongoc_dir}/src/libmongoc"
67-
LD_LIBRARY_PATH+=":$mongoc_dir/src/libbson"
39+
test_awsauth="${mongoc_dir}/src/libmongoc/Debug/test-awsauth.exe"
6840
fi
6941

7042
expect_success() {
7143
echo "Should succeed:"
72-
if ! "${mongoc_ping}" "${1:?}"; then
73-
echo "Unexpected auth failure" 1>&2
74-
exit 1
75-
fi
44+
"${test_awsauth}" "${1:?}" "EXPECT_SUCCESS" || exit
7645
}
7746

7847
expect_failure() {
7948
echo "Should fail:"
80-
if "${mongoc_ping}" "${1:?}" >output.txt 2>&1; then
81-
echo "Unexpected - authed but it should not have" 1>&2
82-
exit 1
83-
else
84-
echo "auth failed as expected"
85-
fi
86-
87-
if ! grep "Authentication failed" output.txt >/dev/null; then
88-
echo "Unexpected, error was not an authentication failure:" 1>&2
89-
cat output.txt 1>&2
90-
exit 1
91-
fi
49+
"${test_awsauth}" "${1:?}" "EXPECT_FAILURE" || exit
9250
}
9351

9452
url_encode() {

.evergreen/scripts/run-mongodb-aws-ecs-test.sh

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,10 @@
44

55
echo "run-mongodb-aws-ecs-test.sh"
66

7-
# Set paths so mongoc-ping can find dependencies
8-
export LD_LIBRARY_PATH
9-
LD_LIBRARY_PATH+=":/root/mongoc/src/libmongoc"
10-
LD_LIBRARY_PATH+=":/root/mongoc/src/libbson"
117

128
expect_success() {
139
echo "Should succeed:"
14-
if ! /root/mongoc/src/libmongoc/mongoc-ping "${1:?}"; then
15-
echo "Unexpected auth failure" 1>&2
16-
exit 1
17-
fi
10+
/root/mongoc/src/libmongoc/test-awsauth "${1:?}" "EXPECT_SUCCESS"
1811
}
1912

2013
expect_success "${1:?}"

src/libmongoc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,7 @@ mongoc_add_test (test-mongoc-gssapi FALSE ${PROJECT_SOURCE_DIR}/tests/test-mongo
10631063
mongoc_add_test (test-mongoc-cache FALSE ${PROJECT_SOURCE_DIR}/tests/test-mongoc-cache.c)
10641064
mongoc_add_test (test-azurekms FALSE ${PROJECT_SOURCE_DIR}/tests/test-azurekms.c)
10651065
mongoc_add_test (test-gcpkms FALSE ${PROJECT_SOURCE_DIR}/tests/test-gcpkms.c)
1066+
mongoc_add_test (test-awsauth FALSE ${PROJECT_SOURCE_DIR}/tests/test-awsauth.c)
10661067

10671068
if (ENABLE_TESTS)
10681069
# "make test" doesn't compile tests, so we create "make check" which compiles

src/libmongoc/src/mongoc/mongoc-cluster-aws-private.h

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
#define MONGOC_CLUSTER_AWS_PRIVATE_H
2121

2222
#include "bson/bson.h"
23+
#include "mcd-time.h"
2324
#include "mongoc/mongoc-cluster-private.h"
25+
#include "common-thread-private.h" // bson_mutex_t
2426

2527
bool
2628
_mongoc_cluster_auth_node_aws (mongoc_cluster_t *cluster,
@@ -29,18 +31,104 @@ _mongoc_cluster_auth_node_aws (mongoc_cluster_t *cluster,
2931
bson_error_t *error);
3032

3133
/* The following are declared in the private header for testing. It is only used
32-
* in test-mongoc-aws.c and mongoc-cluster.aws.c */
34+
* in test-mongoc-aws.c, mongoc-cluster-aws.c, and test-awsauth.c */
3335
typedef struct {
3436
char *access_key_id;
3537
char *secret_access_key;
3638
char *session_token;
39+
// expiration is the time when these credentials expire.
40+
// If expiration.set is false, the credentials do not have a known
41+
// expiration.
42+
struct {
43+
mcd_timer value;
44+
bool set;
45+
} expiration;
3746
} _mongoc_aws_credentials_t;
3847

48+
#define MONGOC_AWS_CREDENTIALS_INIT \
49+
(_mongoc_aws_credentials_t) \
50+
{ \
51+
.access_key_id = NULL, .secret_access_key = NULL, .session_token = NULL, \
52+
.expiration = {.value = {.expire_at = {0}}, .set = false}, \
53+
}
54+
55+
#define MONGOC_AWS_CREDENTIALS_EXPIRATION_WINDOW_MS 60 * 5 * 1000
56+
57+
// _mongoc_aws_credentials_cache_t is a thread-safe global cache of AWS
58+
// credentials.
59+
typedef struct {
60+
struct {
61+
_mongoc_aws_credentials_t value;
62+
bool set;
63+
} cached;
64+
bson_mutex_t mutex; // guards cached.
65+
} _mongoc_aws_credentials_cache_t;
66+
67+
extern _mongoc_aws_credentials_cache_t mongoc_aws_credentials_cache;
68+
69+
// _mongoc_aws_credentials_cache_init initializes the global
70+
// `mongoc_aws_credentials_cache. It is expected to be called by mongoc_init.
71+
void
72+
_mongoc_aws_credentials_cache_init (void);
73+
74+
// _mongoc_aws_credentials_cache_lock exclusively locks the cache.
75+
void
76+
_mongoc_aws_credentials_cache_lock (void);
77+
78+
// _mongoc_aws_credentials_cache_unlock unlocks the cache.
79+
void
80+
_mongoc_aws_credentials_cache_unlock (void);
81+
82+
// _mongoc_aws_credentials_cache_put_nolock is a non-locking variant of
83+
// _mongoc_aws_credentials_cache_put.
84+
void
85+
_mongoc_aws_credentials_cache_put_nolock (
86+
const _mongoc_aws_credentials_t *creds);
87+
88+
// _mongoc_aws_credentials_cache_put adds credentials into the global cache.
89+
void
90+
_mongoc_aws_credentials_cache_put (const _mongoc_aws_credentials_t *creds);
91+
92+
// _mongoc_aws_credentials_cache_get_nolock is a non-locking variant of
93+
// _mongoc_aws_credentials_cache_get.
94+
bool
95+
_mongoc_aws_credentials_cache_get_nolock (_mongoc_aws_credentials_t *creds);
96+
97+
// _mongoc_aws_credentials_cache_get returns true if cached credentials were
98+
// retrieved.
99+
// The passed `creds` is expected to be initialized with
100+
// MONGOC_AWS_CREDENTIALS_INIT. Returns true if there are valid cached
101+
// credentials. Retrieved credentials are copied to `creds`. Callers are
102+
// expected to call
103+
// `_mongoc_aws_credentials_cleanup` on `creds`.
104+
// Returns false and zeroes `creds` if there are no valid cached credentials.
105+
bool
106+
_mongoc_aws_credentials_cache_get (_mongoc_aws_credentials_t *creds);
107+
108+
// _mongoc_aws_credentials_cache_clear_nolock is the non-locking variant of
109+
// _mongoc_aws_credentials_cache_clear
110+
void
111+
_mongoc_aws_credentials_cache_clear_nolock (void);
112+
113+
// _mongoc_aws_credentials_cache_clear clears credentials in the global cache
114+
void
115+
_mongoc_aws_credentials_cache_clear (void);
116+
117+
// _mongoc_aws_credentials_cache_cleanup frees data for the global cache.
118+
// It is expected to be called by mongoc_cleanup.
119+
void
120+
_mongoc_aws_credentials_cache_cleanup (void);
121+
122+
39123
bool
40124
_mongoc_aws_credentials_obtain (mongoc_uri_t *uri,
41125
_mongoc_aws_credentials_t *creds,
42126
bson_error_t *error);
43127

128+
void
129+
_mongoc_aws_credentials_copy_to (const _mongoc_aws_credentials_t *src,
130+
_mongoc_aws_credentials_t *dst);
131+
44132
void
45133
_mongoc_aws_credentials_cleanup (_mongoc_aws_credentials_t *creds);
46134

0 commit comments

Comments
 (0)