R/users.R

Defines functions aws_user aws_users user_list_tidy

Documented in aws_user aws_users

#' User list cleanup
#'
#' @noRd
#' @param x (list) a nested list, from a call to
#' [list_users](https://www.paws-r-sdk.com/docs/iam_list_users/)
#' @autoglobal
#' @keywords internal
user_list_tidy <- function(x) {
  if (rlang::is_empty(x)) {
    return(tibble())
  }
  vars <- c(
    "UserName",
    "UserId",
    "Path",
    "Arn",
    "CreateDate",
    "PasswordLastUsed"
  )
  tidy_generator(vars)(x) %>%
    mutate(
      PasswordLastUsed = .as_datetime(PasswordLastUsed),
      Arn = ifelse(env64$redacted, env64$redact_str, Arn)
    )
}

#' List Users
#'
#' @export
#' @param ... parameters passed on to the `paws`
#' [list_users](https://www.paws-r-sdk.com/docs/iam_list_users/) method
#' @family users
#' @returns A tibble with information about user accounts, with columns:
#' - UserName
#' - UserId
#' - Path
#' - Arn
#' - CreateDate
#' - PasswordLastUsed
#' @examplesIf interactive() && aws_has_creds()
#' aws_users()
aws_users <- function(...) {
  users <- paginate_aws_marker("list_users", "Users", ...) %>%
    user_list_tidy()
  if (is_empty(users)) {
    return(tibble())
  }
  purrr::map(users$UserName, \(x) con_iam()$get_user(x)) %>%
    purrr::map(purrr::pluck, "User") %>%
    user_list_tidy()
}

#' Get a user
#'
#' Gets user information, including policies, groups, and attached policies
#'
#' @export
#' @inheritParams aws_user_create
#' @return a named list with slots for:
#' - user (tibble)
#' - policies (list)
#' - attached_policies (list)
#' - groups (list)
#' @details See the following docs links for details
#' - <https://www.paws-r-sdk.com/docs/iam_get_user/>
#' - <https://www.paws-r-sdk.com/docs/iam_list_user_policies/>
#' - <https://www.paws-r-sdk.com/docs/iam_list_groups_for_user/>
#' - <https://www.paws-r-sdk.com/docs/iam_list_attached_user_policies/>
#' @note if username not supplied, gets logged in user
#' @family users
#' @examples \dontrun{
#' # if username not supplied, gets the logged in user
#' aws_user()
#' }
#'
#' @examplesIf aws_has_creds()
#' if (aws_user_exists("testBlueBird")) {
#'   aws_user_delete("testBlueBird")
#' }
#' aws_user_create("testBlueBird")
#' aws_user("testBlueBird")
#'
#' # cleanup
#' aws_user_delete("testBlueBird")
aws_user <- function(username = NULL) {
  x <- con_iam()$get_user(username)$User %>%
    list(.) %>%
    user_list_tidy()
  if (is.null(username)) username <- x$UserName
  list(
    user = x,
    policies = policies("user", username),
    attached_policies = policies_attached("user", username),
    groups = groups_for_user(username)
  )
}

groups_for_user <- function(username) {
  groups <- con_iam()$list_groups_for_user(username)
  group_list_tidy(groups$Groups)
}

check_aws_user <- purrr::safely(aws_user, otherwise = FALSE)

#' Check if a user exists
#'
#' @export
#' @param username (character) the user name
#' @return a single boolean
#' @details uses [aws_user()] internally. see docs
#' <https://www.paws-r-sdk.com/docs/iam_get_user/>
#' @family users
#' @examplesIf interactive() && aws_has_creds()
#' aws_user_exists(aws_user_current())
#' aws_user_exists("doesnotexist")
aws_user_exists <- function(username) {
  is.null(check_aws_user(username)$error)
}

#' Get the current logged-in username as a string
#' @export
#' @family users
#' @return username as character, scalar
aws_user_current <- function() {
  x <- aws_user()
  x$user$UserName
}

#' Create a user
#'
#' @export
#' @param username (character) A user name. required
#' @param path (character) The path for the user name. optional.
#' If it is not included, it defaults to a slash (/).
#' @param permission_boundary (character) The ARN of the managed policy
#' that is used to set the permissions boundary for the user. optional
#' @param tags (list) A list of tags that you want to attach to the new user.
#' optional
#' @return A tibble with information about the user created
#' @details See <https://www.paws-r-sdk.com/docs/iam_create_user/>
#' docs for details on the parameters
#' @family users
#' @examplesIf interactive() && aws_has_creds()
#' user1 <- random_user()
#' if (aws_user_exists(user1)) {
#'   aws_user_delete(user1)
#' }
#' aws_user_create(user1)
#'
#' # cleanup
#' aws_user_delete(user1)
aws_user_create <- function(
  username,
  path = NULL,
  permission_boundary = NULL,
  tags = NULL
) {
  con_iam()$create_user(
    Path = path,
    UserName = username,
    PermissionsBoundary = permission_boundary,
    Tags = tags
  ) %>%
    user_list_tidy()
}

#' Create a user, magically
#'
#' @export
#' @inheritParams aws_user_create
#' @inheritParams six_user_creds
#' @details See [aws_user_create()] for more details.
#' This function creates a user, adds policies so the
#' user can access their own account, and grants them an access
#' key. Add more policies using `aws_polic*` functions
#' @section What is magical:
#' - Adds a `UserInfo` policy to your account if doesn't exist yet
#' - Attaches `UserInfo` policy to the user created
#' - Grants an access key, copying an email template to your clipboard
#' @family users
#' @family magicians
#' @return NULL invisibly. A draft email is copied to your clipboard
#' @examplesIf interactive() && aws_has_creds()
#' name <- random_user()
#' six_user_create(name)
#'
#' # cleanup
#' six_user_delete(name)
six_user_create <- function(
  username,
  path = NULL,
  permission_boundary = NULL,
  tags = NULL,
  copy_to_cb = TRUE
) {
  aws_user_create(
    path = path,
    username = username,
    permission_boundary = permission_boundary,
    tags = tags
  )
  policy_name <- "UserInfo"
  if (!aws_policy_exists(policy_name)) {
    actions <- c(
      "iam:GetUser",
      "iam:ListUserPolicies",
      "iam:ListAttachedUserPolicies",
      "iam:ListGroupsForUser"
    )
    policy_doc <- aws_policy_document_create(
      aws_policy_statement(actions, "*")
    )
    aws_policy_create(policy_name, policy_doc)
    cli_info("Added policy {.strong {policy_name}} to your account")
  }
  user_obj <- aws_user(username)
  if (!has_policy(user_obj, policy_name)) {
    aws_policy_attach(user_obj, policy_name)
    cli_info(
      "Added policy {.strong {policy_name}} to {.strong {username}}"
    )
  }
  six_user_creds(username, copy_to_cb = copy_to_cb)
}

#' Delete a user
#'
#' @export
#' @inheritParams aws_user_create
#' @return NULL invisibly
#' @details See <https://www.paws-r-sdk.com/docs/iam_delete_user/>
#' docs for more details
#' @family users
#' @examplesIf interactive() && aws_has_creds()
#' user_name <- random_user()
#' aws_user_create(user_name)
#' aws_user_delete(user_name)
#' aws_user_exists(user_name)
aws_user_delete <- function(username) {
  con_iam()$delete_user(username)
  invisible()
}

#' Delete a user
#'
#' @export
#' @inheritParams aws_user_create
#' @return an empty list
#' @details See <https://www.paws-r-sdk.com/docs/iam_delete_user/>
#' docs for more details
#' @section What is magical:
#' - Detaches any attached policies
#' - Deletes any access keys
#' - Then deletes the user
#' @family users
#' @family magicians
#' @examplesIf interactive() && aws_has_creds()
#' name <- random_user()
#' six_user_create(name)
#' six_user_delete(name)
six_user_delete <- function(username) {
  user_obj <- aws_user(username)

  # remove policies
  attpols <- user_obj$attached_policies
  if (!rlang::is_empty(attpols)) {
    policies <- attpols$PolicyName
    map(policies, \(policy) aws_policy_detach(user_obj, policy))
    cli_info("Polic{?y/ies} {.strong {policies}} detached")
  }

  # remove access keys
  keys <- aws_user_access_key(username)
  if (!is.null(keys)) {
    map(keys$AccessKeyId, aws_user_access_key_delete, username = username)
  }

  # remove groups
  if (!rlang::is_empty(user_obj$groups)) {
    groups <- user_obj$groups
    map(groups$GroupName, \(g) aws_user_remove_from_group(username, g))
    cli_info("Group{?s} {.strong {groups$GroupName}} detached")
  }

  aws_user_delete(username)
  cli_info("{.strong {username}} deleted")
}

#' Get AWS Access Key for a user
#'
#' IMPORTANT: the secret access key is only accessible during key
#' and user creation
#'
#' @export
#' @inheritParams aws_user_create
#' @param ... further named args passed on to
#' [list_access_keys](https://www.paws-r-sdk.com/docs/iam_list_access_keys/)
#' @return a tibble with key details
#' @details See <https://www.paws-r-sdk.com/docs/iam_list_access_keys/>
#' docs for more details
#' @family users
aws_user_access_key <- function(username = NULL, ...) {
  out <- con_iam()$list_access_keys(username, ...)
  if (length(out$AccessKeyMetadata) == 0) {
    cli_warning("No access keys found for {.strong {username}}")
    return(invisible())
  }
  bind_rows(out$AccessKeyMetadata)
}

#' Delete current user's AWS Access Key
#'
#' @export
#' @param access_key_id (character) The access key ID for the access key ID
#' and secret access key you want to delete. required.
#' @param username (character) A user name. optional. however, if you do
#' not supply a username, `paws` will likely use the current user, and so
#' may not be the user the access key id is associated - and then you'll get
#' an error like `NoSuchEntity (HTTP 404). The Access Key with id
#' xx cannot be found`
#' @return NULL, invisibly
#' @details See <https://www.paws-r-sdk.com/docs/iam_delete_access_key/>
#' docs for more details
#' @family users
aws_user_access_key_delete <- function(access_key_id, username = NULL) {
  con_iam()$delete_access_key(UserName = username, AccessKeyId = access_key_id)
  key <- ifelse(env64$redacted, env64$redact_str, access_key_id) # nolint
  cli_success("Access Key ID {.strong {key}} deleted")
  invisible()
}

#' Add or remove a user to/from a group
#'
#' @export
#' @inheritParams aws_user_create
#' @param groupname (character) a group name. required
#' @inherit aws_user return
#' @details See <https://www.paws-r-sdk.com/docs/iam_add_user_to_group/>
#' <https://www.paws-r-sdk.com/docs/iam_remove_user_from_group/>
#' docs for more details
#' @family users
#' @examplesIf interactive() && aws_has_creds()
#' group1 <- random_string("group")
#' if (!aws_group_exists(group1)) {
#'   aws_group_create(group1)
#' }
#' name1 <- random_user()
#' if (!aws_user_exists(name1)) {
#'   aws_user_create(name1)
#' }
#' aws_user_add_to_group(name1, group1)
#' aws_group(group1) # has user name1
#' aws_user_remove_from_group(name1, group1)
#' aws_group(group1) # does not have user name1
aws_user_add_to_group <- function(username, groupname) {
  con_iam()$add_user_to_group(groupname, username)
  aws_user(username)
}

#' @export
#' @rdname aws_user_add_to_group
aws_user_remove_from_group <- function(username, groupname) {
  con_iam()$remove_user_from_group(groupname, username)
  aws_user(username)
}

Try the sixtyfour package in your browser

Any scripts or data that you put into this service are public.

sixtyfour documentation built on April 3, 2025, 8:22 p.m.