Skip to content

Commit

Permalink
Merge pull request #114 from generable/use-keyring
Browse files Browse the repository at this point in the history
Use keyring
  • Loading branch information
jburos authored Oct 5, 2023
2 parents 08710fe + 15c9601 commit 85481e2
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 8 deletions.
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ Imports:
reticulate,
boot,
cli,
httpcache
httpcache,
keyring
Suggests:
testthat,
knitr,
Expand All @@ -44,5 +45,5 @@ Suggests:
scales,
tidyverse,
utils
RoxygenNote: 7.2.0
RoxygenNote: 7.2.3
VignetteBuilder: knitr
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by roxygen2: do not edit by hand

export(configure)
export(extract_subsample_info)
export(fetch_association_state)
export(fetch_biomarker_params)
Expand Down Expand Up @@ -37,6 +38,7 @@ export(sample_groups)
import(checkmate)
import(cli)
import(httr)
import(keyring)
importFrom(RJSONIO,fromJSON)
importFrom(boot,inv.logit)
importFrom(broom,tidy)
Expand All @@ -49,6 +51,8 @@ importFrom(dplyr,select)
importFrom(dplyr,semi_join)
importFrom(futile.logger,flog.logger)
importFrom(glue,glue_safe)
importFrom(httpcache,GET)
importFrom(httpcache,POST)
importFrom(httr,modify_url)
importFrom(lubridate,ymd_hms)
importFrom(magrittr,"%>%")
Expand Down
99 changes: 94 additions & 5 deletions R/geco_api.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,108 @@ geco_api_url <- function(..., project = NULL, project_version_id = NULL, run_id=
#' @param password User password. If not provided, will read the `GECO_API_PASSWORD` environment variable.
#' @return The OAuth 2.0 Bearer Token for the Generable API
#' @export
login <- function(user, password) {
if (missing(user)) {
user <- Sys.getenv('GECO_API_USER')
}
login <- function(user, password, host) {
url <- .get_url(host)
if (missing(password)) {
password <- Sys.getenv('GECO_API_PASSWORD')
# get credentials from keyring
creds <- .get_credentials(host = host, user = user)
user = creds[1]
password = creds[2]
}
if (is.null(user)) {
cli::cli_inform('Note: credential storage has changed; please run `configure()` to migrate to the new storage.')
}
body <- list(email = user, password = password)
resp <- geco_api(LOGIN, body = body, encode = 'json', method = 'POST')
ENV$.GECO_AUTH <- resp$content
invisible(resp$content)
}

#' Configure Geco credentials, saving in keyring
#' @param user Geco user name (email address). Defaults to GECO_API_USER environment variable
#' @param password Geco password (will prompt if not provided). Defaults to GECO_API_PASSWORD environment variable
#' @param host (optional) alternate host for API, only used for testing
#' @import keyring
#' @export
configure <- function(user, password, host) {
cli::cli_inform('Configuring credentials for Geco API')
url <- .get_url(host)
if (missing(user)) {
cli::cli_inform('Reading username from environment variable: GECO_API_USER')
user <- Sys.getenv('GECO_API_USER', unset = '')
if (user == '') {
stop('Username not provided.')
}
}
if (missing(password)) {
cli::cli_inform('Reading password from environment variable: GECO_API_PASSWORD')
password <- Sys.getenv('GECO_API_PASSWORD', unset = '')
if (password == '' && interactive()) {
password <- rstudioapi::askForPassword()
}
}
cli::cli_inform('Attempting to log in ...')
res <- tryCatch(login(user=user, password = password))
if (inherits(res, 'try-error')) {
cli::cli_alert_warning('Failed to authenticate.')
} else {
cli::cli_alert_success('Success!')
if (keyring::has_keyring_support() && interactive() && askYesNo("Do you want to save credentials in your keyring?")) {
keyring::key_set_with_value(service = .get_keyring_service(),
username = user, password = password)
cli::cli_alert_success('Credentials saved.')
} else {
cli::cli_inform('Populating credentials in environment variables.')
Sys.setenv('GECO_API_USER'=user)
Sys.setenv('GECO_API_PASSWORD'=password)
}
}
}

.get_keyring_service <- function(host) {
url <- .get_url(host)
stringr::str_c('R-GECO_API', url, sep = '-')
}
.get_url <- function(host) {
if (missing(host)) {
url <- Sys.getenv('GECO_API_URL', unset = 'https://geco.generable.com')
} else {
url <- glue::glue('https://{host}.generable.com')
Sys.setenv('GECO_API_URL' = url)
}
url
}

# returns vector as username, password
.get_credentials <- function(host, user) {
if (!keyring::has_keyring_support()) {
if (missing(user)) {
user <- Sys.getenv('GECO_API_USER')
}
password <- Sys.getenv('GECO_API_PASSWORD')
return(c(user, password))
}
# get user & reconcile with keychain
service <- .get_keyring_service(host)
keys <- key_list(service)
if (missing(user)) {
if (nrow(keys) == 1) {
user <- unique(keys$username)
} else {
user <- Sys.getenv('GECO_API_USER', unset = 'null')
if (is.null(user)) {
stop("Multiple users configured; please set default user with GECO_API_USER environment variable")
}
}
} else if (user %in% keys$username) {
Sys.setenv('GECO_API_USER' = user)
} else {
stop('User does not exist in keyring; please run `configure()`')
}
# get password
password <- key_get(service, username = user)
return(c(user, password))
}

get_auth <- function() {
if (!exists(envir = ENV, '.GECO_AUTH')) {
Expand Down
18 changes: 18 additions & 0 deletions man/configure.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/login.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/testthat/setup_test_environment.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ test_login <- function() {
}
futile.logger::flog.info('Logging in as test user ...')
Sys.setenv(GECO_API_URL=Sys.getenv('GECO_API_TEST_URL'))
configure()
a <- login(Sys.getenv('GECO_API_TEST_USER'), password = Sys.getenv('GECO_API_TEST_PASSWORD'))
}

Expand Down

0 comments on commit 85481e2

Please sign in to comment.