diff --git a/NEWS.md b/NEWS.md index db93964..a1ae559 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,7 @@ # aws.signature 0.4.5 * Removed `locate_credentials()` call from internal `signature_v4()` function. (#33) -* +* `signature_v4_auth()` and `signature_v2_auth()` gain a `force_credentials` argument. If `force_credentials = TRUE`, user-supplied values are used and no call to `locate_credentials()` is made. (#33) # aws.signature 0.4.4 diff --git a/R/signature_v4.R b/R/signature_v4.R index 64f6921..9ec9784 100644 --- a/R/signature_v4.R +++ b/R/signature_v4.R @@ -1,11 +1,11 @@ #' @title Signature Version 4 #' @description Generates AWS Signature Version 4 -#' @param secret An AWS Secret Access Key. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}. +#' @template secret #' @param date A character string containing a date in the form of \dQuote{YYMMDD}. If missing, it is generated automatically using \code{\link[base]{Sys.time}}. -#' @param region A character string containing the AWS region for the request. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}} or \dQuote{us-east-1} is used. +#' @template region #' @param service A character string containing the AWS service (e.g., \dQuote{iam}, \dQuote{host}, \dQuote{ec2}). #' @param string_to_sign A character string containing the \dQuote{String To Sign}, possibly returned by \code{\link{string_to_sign}}. -#' @param verbose A logical indicating whether to be verbose. +#' @template verbose #' @details This function generates an AWS Signature Version 4 for authorizing API requests from its pre-formatted components. Users probably only need to use the \code{\link{signature_v4_auth}} function to generate signatures. #' @author Thomas J. Leeper #' @references @@ -49,12 +49,14 @@ #' @importFrom digest digest hmac #' @export signature_v4 <- -function(secret = NULL, - date = format(Sys.time(), "%Y%m%d"), - region = NULL, - service, - string_to_sign, - verbose = FALSE) { +function( + secret = NULL, + date = format(Sys.time(), "%Y%m%d"), + region = NULL, + service, + string_to_sign, + verbose = getOption("verbose", FALSE) +) { kDate <- digest::hmac(paste0("AWS4", secret), date, "sha256", raw = TRUE) kRegion <- digest::hmac(kDate, region, "sha256", raw = TRUE) kService <- digest::hmac(kRegion, service, "sha256", raw = TRUE) diff --git a/R/v2.R b/R/v2.R index 4d1ef11..bb97184 100644 --- a/R/v2.R +++ b/R/v2.R @@ -5,9 +5,11 @@ #' @param service A character string containing the full hostname of an AWS service (e.g., \dQuote{iam.amazonaws.com}, etc.) #' @param path A character string specify the path to the API endpoint. #' @param query_args A list containing named query arguments. -#' @param key An AWS Access Key ID. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}. -#' @param secret An AWS Secret Access Key. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}. -#' @param verbose A logical indicating whether to be verbose. +#' @template key +#' @template secret +#' @template region +#' @template force_credentials +#' @template verbose #' @details This function generates an AWS Signature Version 2 for authorizing API requests. The function returns both an updated set of query string parameters, containing the required signature-related entries, as well as a \code{Signature} field containing the Signature string itself. Version 2 is mostly deprecated and in most cases users should rely on \code{\link{signature_v4_auth}} for Version 4 signatures instead. #' @return A list. #' @author Thomas J. Leeper @@ -68,12 +70,34 @@ #' @importFrom base64enc base64encode #' @export signature_v2_auth <- -function(datetime = format(Sys.time(),"%Y-%m-%dT%H:%M:%S", tz = "UTC"), - verb, service, path, query_args = list(), - key = NULL, - secret = NULL, - verbose = FALSE) { - credentials <- locate_credentials(key = key, secret = secret, region = "us-east-1", verbose = verbose) +function( + datetime = format(Sys.time(),"%Y-%m-%dT%H:%M:%S", tz = "UTC"), + verb, + service, + path, + query_args = list(), + key = NULL, + secret = NULL, + region = NULL, + force_credentials = FALSE, + verbose = getOption("verbose", FALSE) +) { + if (isTRUE(force_credentials)) { + credentials <- list(key = key, secret = secret, region = region) + if (isTRUE(verbose)) { + if (!is.null(key)) { + message("Using user-supplied value for AWS Access Key ID") + } + if (!is.null(secret)) { + message("Using user-supplied value for AWS Secret Access Key") + } + if (!is.null(region)) { + message(sprintf("Using user-supplied value for AWS Region ('%s')", region)) + } + } + } else { + credentials <- locate_credentials(key = key, secret = secret, region = region, verbose = verbose) + } # set sort locale lc <- Sys.getlocale(category = "LC_COLLATE") @@ -117,5 +141,6 @@ function(datetime = format(Sys.time(),"%Y-%m-%dT%H:%M:%S", tz = "UTC"), AccessKeyId = credentials[["key"]], SecretAccessKey = credentials[["secret"]], SessionToken = credentials[["session_token"]], - Region = credentials[["region"]]), class = "aws_signature_v2") + Region = credentials[["region"]]), + class = "aws_signature_v2") } diff --git a/R/v4.R b/R/v4.R index 3c2b2c0..e6dbd69 100644 --- a/R/v4.R +++ b/R/v4.R @@ -1,19 +1,20 @@ #' @title Signature Version 4 #' @description AWS Signature Version 4 for use in query or header authorization #' @param datetime A character string containing a datetime in the form of \dQuote{YYYYMMDDTHHMMSSZ}. If missing, it is generated automatically using \code{\link[base]{Sys.time}}. -#' @param region A character string containing the AWS region for the request. See \code{\link{locate_credentials}}. +#' @template region #' @param service A character string containing the AWS service (e.g., \dQuote{iam}, \dQuote{host}, \dQuote{ec2}). #' @param verb A character string containing the HTTP verb being used in the request. #' @param action A character string containing the API endpoint used in the request. #' @param query_args A named list of character strings containing the query string values (if any) used in the API request, passed to \code{\link{canonical_request}}. #' @param canonical_headers A named list of character strings containing the headers used in the request. #' @param request_body The body of the HTTP request. -#' @param key An AWS Access Key ID. See \code{\link{locate_credentials}}. -#' @param secret An AWS Secret Access Key. See \code{\link{locate_credentials}}. +#' @template key +#' @template secret #' @param session_token Optionally, an AWS Security Token Service (STS) temporary Session Token. This is added automatically as a header to \code{canonical_headers}. See \code{\link{locate_credentials}}. #' @param query A logical. Currently ignored. #' @param algorithm A character string containing the hashing algorithm used in the request. Should only be \dQuote{SHA256}. -#' @param verbose A logical indicating whether to be verbose. +#' @template force_credentials +#' @template verbose #' @details This function generates an AWS Signature Version 4 for authorizing API requests. #' @return A list of class \dQuote{aws_signature_v4}, containing the information needed to sign an AWS API request using either query string authentication or request header authentication. Specifically, the list contains: #' @@ -62,25 +63,45 @@ #' @seealso \code{\link{signature_v2_auth}}, \code{\link{locate_credentials}} #' @export signature_v4_auth <- -function(datetime = format(Sys.time(),"%Y%m%dT%H%M%SZ", tz = "UTC"), - region = NULL, - service, - verb, - action, - query_args = list(), - canonical_headers, # named list - request_body, - key = NULL, - secret = NULL, - session_token = NULL, - query = FALSE, - algorithm = "AWS4-HMAC-SHA256", - verbose = FALSE){ - credentials <- locate_credentials(key = key, secret = secret, session_token = session_token, region = region, verbose = verbose) - key <- credentials[["key"]] - secret <- credentials[["secret"]] - session_token <- credentials[["session_token"]] - region <- credentials[["region"]] +function( + datetime = format(Sys.time(),"%Y%m%dT%H%M%SZ", tz = "UTC"), + region = NULL, + service, + verb, + action, + query_args = list(), + canonical_headers, # named list + request_body, + key = NULL, + secret = NULL, + session_token = NULL, + query = FALSE, + algorithm = "AWS4-HMAC-SHA256", + force_credentials = FALSE, + verbose = getOption("verbose", FALSE) +){ + if (isTRUE(force_credentials)) { + if (isTRUE(verbose)) { + if (!is.null(key)) { + message("Using user-supplied value for AWS Access Key ID") + } + if (!is.null(secret)) { + message("Using user-supplied value for AWS Secret Access Key") + } + if (!is.null(session_token)) { + message("Using user-supplied value for AWS Secret Access Key") + } + if (!is.null(region)) { + message(sprintf("Using user-supplied value for AWS Region ('%s')", region)) + } + } + } else { + credentials <- locate_credentials(key = key, secret = secret, session_token = session_token, region = region, verbose = verbose) + key <- credentials[["key"]] + secret <- credentials[["secret"]] + session_token <- credentials[["session_token"]] + region <- credentials[["region"]] + } date <- substring(datetime,1,8) diff --git a/man-roxygen/force_credentials.R b/man-roxygen/force_credentials.R new file mode 100644 index 0000000..5c4787e --- /dev/null +++ b/man-roxygen/force_credentials.R @@ -0,0 +1 @@ +#' @param force_credentials A logical indicating whether to force use of user-supplied credentials. If \code{FALSE} (the default), \code{\link{locate_credentials}} is used to find credentials. If \code{TRUE}, user-supplied values are used regardless of their validity. diff --git a/man-roxygen/key.R b/man-roxygen/key.R new file mode 100644 index 0000000..74d1a9a --- /dev/null +++ b/man-roxygen/key.R @@ -0,0 +1 @@ +#' @param key An AWS Access Key ID. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}. diff --git a/man-roxygen/region.R b/man-roxygen/region.R new file mode 100644 index 0000000..eba60c6 --- /dev/null +++ b/man-roxygen/region.R @@ -0,0 +1 @@ +#' @param region A character string containing the AWS region for the request. If missing, \dQuote{us-east-1} is assumed. diff --git a/man-roxygen/secret.R b/man-roxygen/secret.R new file mode 100644 index 0000000..90d2ceb --- /dev/null +++ b/man-roxygen/secret.R @@ -0,0 +1 @@ +#' @param secret An AWS Secret Access Key. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}. diff --git a/man-roxygen/verbose.R b/man-roxygen/verbose.R new file mode 100644 index 0000000..7e1bebf --- /dev/null +++ b/man-roxygen/verbose.R @@ -0,0 +1 @@ +#' @param verbose A logical indicating whether to be verbose. diff --git a/man/credentials.Rd b/man/credentials.Rd index e0b16c4..b099728 100644 --- a/man/credentials.Rd +++ b/man/credentials.Rd @@ -7,7 +7,7 @@ locate_credentials(key = NULL, secret = NULL, session_token = NULL, region = NULL, file = Sys.getenv("AWS_SHARED_CREDENTIALS_FILE", default_credentials_file()), profile = Sys.getenv("AWS_PROFILE", "default"), - default_region = "us-east-1", verbose = FALSE) + default_region = "us-east-1", verbose = getOption("verbose", FALSE)) } \arguments{ \item{key}{An AWS Access Key ID} diff --git a/man/signature_v2_auth.Rd b/man/signature_v2_auth.Rd index 609a5d2..31c3652 100644 --- a/man/signature_v2_auth.Rd +++ b/man/signature_v2_auth.Rd @@ -6,7 +6,8 @@ \usage{ signature_v2_auth(datetime = format(Sys.time(), "\%Y-\%m-\%dT\%H:\%M:\%S", tz = "UTC"), verb, service, path, query_args = list(), key = NULL, - secret = NULL, verbose = FALSE) + secret = NULL, region = NULL, force_credentials = FALSE, + verbose = getOption("verbose", FALSE)) } \arguments{ \item{datetime}{A character string containing a date in the form of \dQuote{YYYY-MM-DDTH:M:S}. If missing, it is generated automatically using \code{\link[base]{Sys.time}}.} @@ -23,6 +24,10 @@ signature_v2_auth(datetime = format(Sys.time(), "\%Y-\%m-\%dT\%H:\%M:\%S", tz \item{secret}{An AWS Secret Access Key. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}.} +\item{region}{A character string containing the AWS region for the request. If missing, \dQuote{us-east-1} is assumed.} + +\item{force_credentials}{A logical indicating whether to force use of user-supplied credentials. If \code{FALSE} (the default), \code{\link{locate_credentials}} is used to find credentials. If \code{TRUE}, user-supplied values are used regardless of their validity.} + \item{verbose}{A logical indicating whether to be verbose.} } \value{ diff --git a/man/signature_v4.Rd b/man/signature_v4.Rd index 9cba237..d7c92fa 100644 --- a/man/signature_v4.Rd +++ b/man/signature_v4.Rd @@ -5,14 +5,15 @@ \title{Signature Version 4} \usage{ signature_v4(secret = NULL, date = format(Sys.time(), "\%Y\%m\%d"), - region = NULL, service, string_to_sign, verbose = FALSE) + region = NULL, service, string_to_sign, verbose = getOption("verbose", + FALSE)) } \arguments{ \item{secret}{An AWS Secret Access Key. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}.} \item{date}{A character string containing a date in the form of \dQuote{YYMMDD}. If missing, it is generated automatically using \code{\link[base]{Sys.time}}.} -\item{region}{A character string containing the AWS region for the request. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}} or \dQuote{us-east-1} is used.} +\item{region}{A character string containing the AWS region for the request. If missing, \dQuote{us-east-1} is assumed.} \item{service}{A character string containing the AWS service (e.g., \dQuote{iam}, \dQuote{host}, \dQuote{ec2}).} diff --git a/man/signature_v4_auth.Rd b/man/signature_v4_auth.Rd index a497891..7a84e09 100644 --- a/man/signature_v4_auth.Rd +++ b/man/signature_v4_auth.Rd @@ -8,12 +8,12 @@ signature_v4_auth(datetime = format(Sys.time(), "\%Y\%m\%dT\%H\%M\%SZ", tz = "UTC"), region = NULL, service, verb, action, query_args = list(), canonical_headers, request_body, key = NULL, secret = NULL, session_token = NULL, query = FALSE, algorithm = "AWS4-HMAC-SHA256", - verbose = FALSE) + force_credentials = FALSE, verbose = getOption("verbose", FALSE)) } \arguments{ \item{datetime}{A character string containing a datetime in the form of \dQuote{YYYYMMDDTHHMMSSZ}. If missing, it is generated automatically using \code{\link[base]{Sys.time}}.} -\item{region}{A character string containing the AWS region for the request. See \code{\link{locate_credentials}}.} +\item{region}{A character string containing the AWS region for the request. If missing, \dQuote{us-east-1} is assumed.} \item{service}{A character string containing the AWS service (e.g., \dQuote{iam}, \dQuote{host}, \dQuote{ec2}).} @@ -27,9 +27,9 @@ signature_v4_auth(datetime = format(Sys.time(), "\%Y\%m\%dT\%H\%M\%SZ", tz = \item{request_body}{The body of the HTTP request.} -\item{key}{An AWS Access Key ID. See \code{\link{locate_credentials}}.} +\item{key}{An AWS Access Key ID. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}.} -\item{secret}{An AWS Secret Access Key. See \code{\link{locate_credentials}}.} +\item{secret}{An AWS Secret Access Key. If \code{NULL}, it is retrieved using \code{\link{locate_credentials}}.} \item{session_token}{Optionally, an AWS Security Token Service (STS) temporary Session Token. This is added automatically as a header to \code{canonical_headers}. See \code{\link{locate_credentials}}.} @@ -37,6 +37,8 @@ signature_v4_auth(datetime = format(Sys.time(), "\%Y\%m\%dT\%H\%M\%SZ", tz = \item{algorithm}{A character string containing the hashing algorithm used in the request. Should only be \dQuote{SHA256}.} +\item{force_credentials}{A logical indicating whether to force use of user-supplied credentials. If \code{FALSE} (the default), \code{\link{locate_credentials}} is used to find credentials. If \code{TRUE}, user-supplied values are used regardless of their validity.} + \item{verbose}{A logical indicating whether to be verbose.} } \value{