From f9cd43b6840227abcc6d871312ae225178c913a7 Mon Sep 17 00:00:00 2001 From: Michal Lula Date: Sun, 14 Apr 2019 18:19:34 +0200 Subject: [PATCH] add session token support --- doc/man/s3fs.1 | 2 +- src/curl.cpp | 26 ++++++++++++++++++++++++-- src/curl.h | 3 +++ src/s3fs.cpp | 40 +++++++++++++++++++++++++++++++++++++--- src/s3fs_util.cpp | 5 +++++ 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/doc/man/s3fs.1 b/doc/man/s3fs.1 index 3a6aaac..5058ee6 100644 --- a/doc/man/s3fs.1 +++ b/doc/man/s3fs.1 @@ -23,7 +23,7 @@ For unprivileged user. s3fs is a FUSE filesystem that allows you to mount an Amazon S3 bucket as a local filesystem. It stores files natively and transparently in S3 (i.e., you can use other programs to access the same files). .SH AUTHENTICATION s3fs supports the standard AWS credentials (filehttps://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html) stored in `${HOME}/.aws/credentials`. -Alternatively, s3fs supports a custom passwd file. +Alternatively, s3fs supports a custom passwd file. Only AWS credentials file format can be used when AWS session token is required. The s3fs password file has this format (use this format if you have only one set of credentials): .RS 4 \fBaccessKeyId\fP:\fBsecretAccessKey\fP diff --git a/src/curl.cpp b/src/curl.cpp index eb8102c..ff43434 100644 --- a/src/curl.cpp +++ b/src/curl.cpp @@ -384,6 +384,7 @@ int S3fsCurl::max_multireq = 20; // default off_t S3fsCurl::multipart_size = MULTIPART_SIZE; // default bool S3fsCurl::is_sigv4 = true; // default bool S3fsCurl::is_ua = true; // default +bool S3fsCurl::is_use_session_token = false; // default //------------------------------------------------------------------- // Class methods for S3fsCurl @@ -1193,6 +1194,20 @@ bool S3fsCurl::SetAccessKey(const char* AccessKeyId, const char* SecretAccessKey return true; } +bool S3fsCurl::SetAccessKeyWithSessionToken(const char* AccessKeyId, const char* SecretAccessKey, const char* SessionToken) +{ + bool access_key_is_empty = !AccessKeyId || '\0' == AccessKeyId[0]; + bool secret_access_key_is_empty = !SecretAccessKey || '\0' == SecretAccessKey[0]; + bool session_token_is_empty = !SessionToken || '\0' == SessionToken[0]; + if((!S3fsCurl::is_ibm_iam_auth && access_key_is_empty) || secret_access_key_is_empty || session_token_is_empty){ + return false; + } + AWSAccessKeyId = AccessKeyId; + AWSSecretAccessKey = SecretAccessKey; + AWSAccessToken = SessionToken; + return true; +} + long S3fsCurl::SetSslVerifyHostname(long value) { if(0 != value && 1 != value){ @@ -1210,6 +1225,13 @@ bool S3fsCurl::SetIsIBMIAMAuth(bool flag) return old; } +bool S3fsCurl::SetIsUseSessionToken(bool flag) +{ + bool old = S3fsCurl::is_use_session_token; + S3fsCurl::is_use_session_token = flag; + return old; +} + bool S3fsCurl::SetIsECS(bool flag) { bool old = S3fsCurl::is_ecs; @@ -2407,7 +2429,7 @@ string S3fsCurl::CalcSignatureV2(const string& method, const string& strMD5, con string Signature; string StringToSign; - if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs){ + if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs || S3fsCurl::is_use_session_token){ requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-security-token", S3fsCurl::AWSAccessToken.c_str()); } @@ -2445,7 +2467,7 @@ string S3fsCurl::CalcSignature(const string& method, const string& canonical_uri string Signature, StringCQ, StringToSign; string uriencode; - if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs){ + if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs || S3fsCurl::is_use_session_token){ requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-security-token", S3fsCurl::AWSAccessToken.c_str()); } diff --git a/src/curl.h b/src/curl.h index 10c6937..7901897 100644 --- a/src/curl.h +++ b/src/curl.h @@ -270,6 +270,7 @@ class S3fsCurl static std::string AWSAccessToken; static time_t AWSAccessTokenExpire; static bool is_ecs; + static bool is_use_session_token; static bool is_ibm_iam_auth; static std::string IAM_cred_url; static size_t IAM_field_count; @@ -428,6 +429,7 @@ class S3fsCurl static bool SetVerbose(bool flag); static bool GetVerbose(void) { return S3fsCurl::is_verbose; } static bool SetAccessKey(const char* AccessKeyId, const char* SecretAccessKey); + static bool SetAccessKeyWithSessionToken(const char* AccessKeyId, const char* SecretAccessKey, const char * SessionToken); static bool IsSetAccessKeyID(void){ return (0 < S3fsCurl::AWSAccessKeyId.size()); } @@ -443,6 +445,7 @@ class S3fsCurl static int SetMaxMultiRequest(int max); static int GetMaxMultiRequest(void) { return S3fsCurl::max_multireq; } static bool SetIsECS(bool flag); + static bool SetIsUseSessionToken(bool flag); static bool SetIsIBMIAMAuth(bool flag); static size_t SetIAMFieldCount(size_t field_count); static std::string SetIAMCredentialsURL(const char* url); diff --git a/src/s3fs.cpp b/src/s3fs.cpp index 277c273..4bce5a5 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -141,6 +141,7 @@ static bool is_remove_cache = false; static bool is_ecs = false; static bool is_ibm_iam_auth = false; static bool is_use_xattr = false; +static bool is_use_session_token = false; static bool create_bucket = false; static int64_t singlepart_copy_limit = 512 * 1024 * 1024; static bool is_specified_endpoint = false; @@ -4087,6 +4088,7 @@ static int read_aws_credentials_file(const std::string &filename) string profile; string accesskey; string secret; + string session_token; // read each line string line; @@ -4106,6 +4108,7 @@ static int read_aws_credentials_file(const std::string &filename) profile = line.substr(1, line.size() - 2); accesskey.clear(); secret.clear(); + session_token.clear(); } size_t pos = line.find_first_of('='); @@ -4118,16 +4121,26 @@ static int read_aws_credentials_file(const std::string &filename) accesskey = value; }else if(key == "aws_secret_access_key"){ secret = value; + }else if(key == "aws_session_token"){ + session_token = value; } } if(profile != aws_profile){ return EXIT_FAILURE; } - if(!S3fsCurl::SetAccessKey(accesskey.c_str(), secret.c_str())){ - S3FS_PRN_EXIT("failed to set internal data for access key/secret key from aws credential file."); - return EXIT_FAILURE; + if (session_token.empty()) { + if(!S3fsCurl::SetAccessKey(accesskey.c_str(), secret.c_str())){ + S3FS_PRN_EXIT("failed to set internal data for access key/secret key from aws credential file."); + return EXIT_FAILURE; + } + } else { + if (!S3fsCurl::SetAccessKeyWithSessionToken(accesskey.c_str(), secret.c_str(), session_token.c_str())) { + S3FS_PRN_EXIT("session token is invalid."); + return EXIT_FAILURE; + } } + return EXIT_SUCCESS; } @@ -4251,12 +4264,29 @@ static int get_access_keys() // 3 - environment variables char* AWSACCESSKEYID = getenv("AWSACCESSKEYID"); char* AWSSECRETACCESSKEY = getenv("AWSSECRETACCESSKEY"); + char* AWSSESSIONTOKEN = getenv("AWSSESSIONTOKEN"); if(AWSACCESSKEYID != NULL || AWSSECRETACCESSKEY != NULL){ if( (AWSACCESSKEYID == NULL && AWSSECRETACCESSKEY != NULL) || (AWSACCESSKEYID != NULL && AWSSECRETACCESSKEY == NULL) ){ S3FS_PRN_EXIT("if environment variable AWSACCESSKEYID is set then AWSSECRETACCESSKEY must be set too."); return EXIT_FAILURE; } + S3FS_PRN_INFO2("access key from env variables"); + if (AWSSESSIONTOKEN != NULL) { + S3FS_PRN_INFO2("session token is available"); + is_use_session_token = true; + S3fsCurl::SetIsUseSessionToken(true); + if (!S3fsCurl::SetAccessKeyWithSessionToken(AWSACCESSKEYID, AWSSECRETACCESSKEY, AWSSESSIONTOKEN)) { + S3FS_PRN_EXIT("session token is invalid."); + return EXIT_FAILURE; + } + } else { + S3FS_PRN_INFO2("session token is not available"); + if (is_use_session_token) { + S3FS_PRN_EXIT("environment variable AWSSESSIONTOKEN is expected to be set."); + return EXIT_FAILURE; + } + } if(!S3fsCurl::SetAccessKey(AWSACCESSKEYID, AWSSECRETACCESSKEY)){ S3FS_PRN_EXIT("if one access key is specified, both keys need to be specified."); return EXIT_FAILURE; @@ -4682,6 +4712,10 @@ static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_ar is_ibm_iam_auth = true; return 0; } + if (0 == STR2NCMP(arg, "use_session_token")) { + S3fsCurl::SetIsUseSessionToken(true); + is_use_session_token = true; + } if(0 == STR2NCMP(arg, "ibm_iam_endpoint=")){ std::string endpoint_url; std::string iam_endpoint = strchr(arg, '=') + sizeof(char); diff --git a/src/s3fs_util.cpp b/src/s3fs_util.cpp index 30ced77..6aa5be4 100644 --- a/src/s3fs_util.cpp +++ b/src/s3fs_util.cpp @@ -1329,6 +1329,11 @@ void show_help () " Unicode set.\n" " Useful on clients not using utf-8 as their file system encoding.\n" "\n" + " use_session_token - indicate that session token should be provided.\n" + " If credentials are provided by environment variables this switch\n" + " forces presence check of AWSSESSIONTOKEN variable.\n" + " Otherwise an error is returned." + "\n" " dbglevel (default=\"crit\")\n" " Set the debug message level. set value as crit (critical), err\n" " (error), warn (warning), info (information) to debug level.\n"