diff --git a/DESCRIPTION b/DESCRIPTION index 7f94fd8..dd545ae 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: sbtools Title: USGS ScienceBase Tools Maintainer: David Blodgett -Version: 1.3.0 +Version: 1.3.1 Authors@R: c(person("David", "Blodgett", role=c("cre"), email = "dblodgett@usgs.gov"), person("Luke", "Winslow", role = c("aut"), diff --git a/NAMESPACE b/NAMESPACE index b683049..999fafa 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -63,6 +63,7 @@ import(jsonlite) importFrom(curl,curl_version) importFrom(methods,is) importFrom(mime,guess_type) +importFrom(tools,R_user_dir) importFrom(utils,globalVariables) importFrom(utils,packageVersion) importFrom(utils,setTxtProgressBar) diff --git a/NEWS.md b/NEWS.md index 690f4cb..b4c5ce7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# version 1.3.1 + +Improved handling of cached token. + # version 1.3.0 In this release, sbtools underwent a significant migration from `josso` login to `keycloak`-based two factor authentication. See #314 for details of the changes. diff --git a/R/AAA.R b/R/AAA.R index 1ed9dd8..707ff69 100644 --- a/R/AAA.R +++ b/R/AAA.R @@ -3,8 +3,6 @@ pkg.env <- new.env() pkg.env$username = "" -pkg.env$token_stache <- file.path(tools::R_user_dir(package = "sbtools"), "token") - .onLoad = function(libname, pkgname){ set_endpoint() } diff --git a/R/authenticate_sb.R b/R/authenticate_sb.R index 746b3c5..61b0534 100644 --- a/R/authenticate_sb.R +++ b/R/authenticate_sb.R @@ -158,11 +158,12 @@ initialize_sciencebase_session <- function(username = NULL, token_text = NULL) { if(token != "") { check_current <- try( initialize_keycloack_env( - token), silent = TRUE) + token, warn_on_fail = FALSE), + silent = TRUE) if(isTRUE(check_current)) { pkg.env$username <- username - return(TRUE) + return(invisible(TRUE)) } } @@ -180,18 +181,18 @@ initialize_sciencebase_session <- function(username = NULL, token_text = NULL) { if(!inherits(worked, "try-error")) { stache_token(token_text) - TRUE + return(invisible(TRUE)) } else { - FALSE + return(invisible(FALSE)) } } -initialize_keycloack_env <- function(token_text) { +initialize_keycloack_env <- function(token_text, warn_on_fail = TRUE) { pkg.env$keycloak_token <- jsonlite::fromJSON(token_text) pkg.env$keycloak_expire <- Sys.time() - token_refresh() + token_refresh(warn_on_fail = warn_on_fail) } # utility to clean environment for testing @@ -207,15 +208,46 @@ clean_session <- function() { pkg.env$uid <- NULL } +#' Get or set token stache data directory +#' @description if left unset, will return the user data dir +#' as returned by `tools::R_user_dir` for this package. +#' @param dir path of desired token stache file +#' @return character path of data directory (silent when setting) +#' @importFrom tools R_user_dir +#' @noRd +#' +token_stache_path <- function(dir = NULL) { + + if(is.null(dir)) { + token_stache <- try(get("token_stache", envir = pkg.env), silent = TRUE) + + if(inherits(token_stache, "try-error")) { + assign("token_stache", + file.path(tools::R_user_dir(package = "sbtools"), "token"), + envir = pkg.env) + } + + return(get("token_stache", envir = pkg.env)) + } else { + assign("token_stache", + dir, + envir = pkg.env) + return(invisible(get("token_stache", envir = pkg.env))) + } + + +} + stache_token <- function(token_text) { - dir.create(dirname(pkg.env$token_stache), recursive = TRUE, showWarnings = FALSE) + dir.create(dirname(token_stache_path()), recursive = TRUE, showWarnings = FALSE) - write(token_text, file = pkg.env$token_stache) + write(token_text, file = token_stache_path()) } grab_token <- function() { - if(file.exists(pkg.env$token_stache)) { - readChar(pkg.env$token_stache, file.info(pkg.env$token_stache)$size) + + if(file.exists(token_stache_path())) { + readChar(token_stache_path(), file.info(token_stache_path())$size) } else { "" } @@ -232,7 +264,9 @@ readPassword <- function(prompt) { if (exists(".rs.askForPassword", mode = "function")) { pass <- .rs.askForPassword(prompt) } else { - pass <- readline(prompt) + message("paste your token - expecting up to four lines") + pass <- readLines(n = 4) + pass <- paste(token, collapse = "") } return (pass) } diff --git a/R/current_session.R b/R/current_session.R index f4df02f..cec4d06 100644 --- a/R/current_session.R +++ b/R/current_session.R @@ -161,14 +161,14 @@ refresh_token_before_expired <- function(refresh_amount_seconds = 600) { return(invisible(FALSE)) } -token_refresh <- function(client_id = pkg.env$keycloak_client_id) { +token_refresh <- function(client_id = pkg.env$keycloak_client_id, warn_on_fail = TRUE) { data = list( client_id = client_id, grant_type = "refresh_token", refresh_token = get_refresh_token()) - token <- RETRY("POST", pkg.env$token_url, body = data, encode = "form") + token <- RETRY("POST", pkg.env$token_url, body = data, encode = "form", quiet = TRUE) if(!token$status_code == 200) { warning('Unable to refresh SB cloud token. Some functionality may not work.') diff --git a/tests/testthat/test-auth.R b/tests/testthat/test-auth.R index 65afe2d..492d752 100644 --- a/tests/testthat/test-auth.R +++ b/tests/testthat/test-auth.R @@ -72,7 +72,7 @@ test_that("login results in valid session and renew works (new)", { skip("Authenticated tests skipped due to lack of login info") } - unlink(sbtools:::pkg.env$token_stache, force = TRUE) + unlink(sbtools:::token_stache_path(), force = TRUE) if(!initialize_sciencebase_session(Sys.getenv("sb_user"), token)) { sbtools:::clean_session() @@ -83,7 +83,7 @@ test_that("login results in valid session and renew works (new)", { on.exit(sbtools:::clean_session()) - expect_true(file.exists(sbtools:::pkg.env$token_stache)) + expect_true(file.exists(sbtools:::token_stache_path())) expect_true(initialize_sciencebase_session()) diff --git a/vignettes/sbtools.Rmd b/vignettes/sbtools.Rmd index 40536ac..011940e 100644 --- a/vignettes/sbtools.Rmd +++ b/vignettes/sbtools.Rmd @@ -61,7 +61,9 @@ Much of `sbtools` is intended to be used after authentication. This part of `sbt The old way used `authenticate_sb()` with a username and password. The password could be cached using the `keyring` package. -```{r} +NOTE: This method no longer works and is shown here for reference with regard to old code and workflows. + +```{r, eval=FALSE} authenticate_sb(Sys.getenv("sb_user")) my_home_item <- user_id()