зеркало из https://github.com/Azure/AzureAuth.git
tighten up testing
This commit is contained in:
Родитель
61698f49a4
Коммит
33b7275777
|
@ -45,7 +45,7 @@ public=list(
|
|||
|
||||
if(self$version == 1)
|
||||
self$resource <- resource
|
||||
else self$scope <- paste0(resource, collapse=" ")
|
||||
else self$scope <- sapply(resource, verify_v2_scope, USE.NAMES=FALSE)
|
||||
|
||||
private$initfunc <- switch(self$auth_type,
|
||||
authorization_code=init_authcode,
|
||||
|
@ -73,7 +73,12 @@ public=list(
|
|||
|
||||
# notify user if interactive auth and no refresh token
|
||||
if(self$auth_type %in% c("authorization_code", "device_code") && is.null(self$credentials$refresh_token))
|
||||
message("Server did not provide a refresh token. To refresh, you will have to reauthenticate.")
|
||||
{
|
||||
if(self$version == 1)
|
||||
message("Server did not provide a refresh token: please reauthenticate to refresh.")
|
||||
else message("Server did not provide a refresh token: you will have to reauthenticate to refresh.\n",
|
||||
"Add the 'offline_access' scope to obtain a refresh token.")
|
||||
}
|
||||
|
||||
self$cache()
|
||||
self
|
||||
|
@ -157,7 +162,7 @@ private=list(
|
|||
stopifnot(is.list(self$token_args))
|
||||
body <- if(self$version == 1)
|
||||
c(body, self$authorize_args, resource=self$resource)
|
||||
else c(body, self$authorize_args, scope=self$scope)
|
||||
else c(body, self$authorize_args, scope=paste(self$scope, collapse=" "))
|
||||
},
|
||||
|
||||
# member function to be filled in by initialize()
|
||||
|
|
|
@ -12,7 +12,7 @@ format_auth_header <- function(token)
|
|||
|
||||
res <- if(token$version == 1)
|
||||
paste("resource", token$resource)
|
||||
else paste("scope", token$scope)
|
||||
else paste("scope", paste(token$scope, collapse=" "))
|
||||
|
||||
version <- if(token$version == 1) "v1.0" else "v2.0"
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ init_authcode <- function()
|
|||
response_type="code",
|
||||
redirect_uri="http://localhost:1410/",
|
||||
resource=self$resource,
|
||||
scope=self$scope,
|
||||
scope=paste(self$scope, collapse=" "),
|
||||
client_secret=self$client$client_secret,
|
||||
login_hint=self$client$login_hint,
|
||||
state=paste0(sample(letters, 20), collapse="") # random nonce
|
||||
|
|
|
@ -233,7 +233,8 @@ token_hash <- function(resource, tenant, app, password=NULL, username=NULL, cert
|
|||
scope <- NULL
|
||||
else
|
||||
{
|
||||
scope <- paste0(resource, collapse=" ")
|
||||
# ignore warnings about invalid scopes when computing hash
|
||||
scope <- suppressWarnings(sapply(resource, verify_v2_scope, USE.NAMES=FALSE))
|
||||
resource <- NULL
|
||||
}
|
||||
|
||||
|
|
10
R/utils.R
10
R/utils.R
|
@ -81,6 +81,8 @@ process_aad_response <- function(res)
|
|||
}
|
||||
|
||||
|
||||
# need to capture bad scopes before requesting auth code
|
||||
# v2.0 endpoint will show error page rather than redirecting, causing get_azure_token to wait forever
|
||||
verify_v2_scope <- function(scope)
|
||||
{
|
||||
# some OpenID scopes get a pass
|
||||
|
@ -95,7 +97,7 @@ verify_v2_scope <- function(scope)
|
|||
|
||||
# is it a URI or GUID?
|
||||
valid_uri <- grepl("^https?://", scope)
|
||||
valid_guid <- is_guid(sub("/.+$", "", scope))
|
||||
valid_guid <- is_guid(sub("/.*$", "", scope))
|
||||
if(!valid_uri && !valid_guid)
|
||||
stop("Invalid scope (must be a URI or GUID): ", scope, call.=FALSE)
|
||||
|
||||
|
@ -105,17 +107,17 @@ verify_v2_scope <- function(scope)
|
|||
uri <- httr::parse_url(scope)
|
||||
if(uri$path == "")
|
||||
{
|
||||
warning("No path supplied for scope ", scope, "; setting to /.default")
|
||||
warning("No path supplied for scope ", scope, "; setting to /.default", call.=FALSE)
|
||||
uri$path <- ".default"
|
||||
scope <- httr::build_url(uri)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
path <- sub("^[^/]+/", "", scope)
|
||||
path <- sub("^[^/]+/?", "", scope)
|
||||
if(path == "")
|
||||
{
|
||||
warning("No path supplied for scope ", scope, "; setting to /.default")
|
||||
warning("No path supplied for scope ", scope, "; setting to /.default", call.=FALSE)
|
||||
scope <- sub("//", "/", paste0(scope, "/.default"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,3 +24,31 @@ test_that("normalize_tenant, normalize_guid work",
|
|||
expect_identical(normalize_tenant(normalize_tenant("mytenant")), "mytenant.onmicrosoft.com")
|
||||
})
|
||||
|
||||
|
||||
test_that("verify_v2_scope works",
|
||||
{
|
||||
expect_silent(AzureAuth:::verify_v2_scope("https://resource.com/.default"))
|
||||
|
||||
# supported OpenID scope
|
||||
expect_silent(AzureAuth:::verify_v2_scope("offline_access"))
|
||||
|
||||
# unsupported OpenID scope
|
||||
expect_error(AzureAuth:::verify_v2_scope("address"))
|
||||
|
||||
# no scope path
|
||||
expect_warning(newscope <- AzureAuth:::verify_v2_scope("https://resource"))
|
||||
expect_equal(newscope, "https://resource/.default")
|
||||
expect_warning(newscope <- AzureAuth:::verify_v2_scope("https://resource/"))
|
||||
expect_equal(newscope, "https://resource/.default")
|
||||
|
||||
# GUIDs
|
||||
expect_silent(AzureAuth:::verify_v2_scope("12345678901234567890123456789012/.default"))
|
||||
expect_warning(newscope <- AzureAuth:::verify_v2_scope("12345678901234567890123456789012"))
|
||||
expect_equal(newscope, "12345678901234567890123456789012/.default")
|
||||
expect_warning(newscope <- AzureAuth:::verify_v2_scope("12345678901234567890123456789012/"))
|
||||
expect_equal(newscope, "12345678901234567890123456789012/.default")
|
||||
|
||||
# not a URI or GUID
|
||||
expect_error(AzureAuth:::verify_v2_scope("resource"))
|
||||
expect_error(AzureAuth:::verify_v2_scope("resource/.default"))
|
||||
})
|
||||
|
|
|
@ -16,6 +16,7 @@ if(system.file(package="httpuv") == "")
|
|||
if(!interactive())
|
||||
skip("Authentication tests skipped: must be an interactive session")
|
||||
|
||||
# should get 2 authcode and 2 devcode prompts here
|
||||
test_that("v2.0 simple authentication works",
|
||||
{
|
||||
suppressWarnings(file.remove(dir(AzureR_dir(), full.names=TRUE)))
|
||||
|
@ -54,25 +55,13 @@ test_that("v2.0 simple authentication works",
|
|||
expect_true(as.numeric(ccd_tok$credentials$expires_on) > ccd_expire)
|
||||
expect_true(as.numeric(dev_tok$credentials$expires_on) > dev_expire)
|
||||
|
||||
# load cached tokens: should not get repeated login prompts/screens
|
||||
aut_tok2 <- get_azure_token(res, tenant, native_app, auth_type="authorization_code", version=2)
|
||||
expect_true(is_azure_token(aut_tok2))
|
||||
expect_identical(aut_tok2$hash(), aut_hash)
|
||||
|
||||
ccd_tok2 <- get_azure_token(res, tenant, app, password=password, version=2)
|
||||
expect_true(is_azure_token(ccd_tok2))
|
||||
expect_identical(ccd_tok2$hash(), ccd_hash)
|
||||
|
||||
dev_tok2 <- get_azure_token(res, tenant, native_app, auth_type="device_code", version=2)
|
||||
expect_true(is_azure_token(dev_tok2))
|
||||
expect_identical(dev_tok2$hash(), dev_hash)
|
||||
|
||||
expect_null(delete_azure_token(res, tenant, native_app, auth_type="authorization_code", version=2, confirm=FALSE))
|
||||
expect_null(delete_azure_token(res, tenant, app, password=password, version=2, confirm=FALSE))
|
||||
expect_null(delete_azure_token(res, tenant, native_app, auth_type="device_code", version=2, confirm=FALSE))
|
||||
})
|
||||
|
||||
|
||||
# should only get 1 authcode and 1 devcode prompt here
|
||||
test_that("v2.0 refresh with offline scope works",
|
||||
{
|
||||
res <- "https://management.azure.com/.default"
|
||||
|
@ -96,12 +85,20 @@ test_that("v2.0 refresh with offline scope works",
|
|||
expect_true(as.numeric(aut_tok$credentials$expires_on) > aut_expire)
|
||||
expect_true(as.numeric(dev_tok$credentials$expires_on) > dev_expire)
|
||||
|
||||
# load cached tokens: should not get repeated login prompts/screens
|
||||
aut_tok2 <- get_azure_token(c(res, res2), tenant, native_app, auth_type="authorization_code", version=2)
|
||||
expect_true(is_azure_token(aut_tok2))
|
||||
|
||||
dev_tok2 <- get_azure_token(c(res, res2), tenant, native_app, auth_type="device_code", version=2)
|
||||
expect_true(is_azure_token(dev_tok2))
|
||||
|
||||
expect_null(
|
||||
delete_azure_token(c(res, res2), tenant, native_app, auth_type="authorization_code", version=2, confirm=FALSE))
|
||||
expect_null(delete_azure_token(c(res, res2), tenant, native_app, auth_type="device_code", version=2, confirm=FALSE))
|
||||
})
|
||||
|
||||
|
||||
# should get 1 authcode screen here
|
||||
test_that("Providing optional args works",
|
||||
{
|
||||
res <- "https://management.azure.com/.default"
|
||||
|
@ -119,3 +116,13 @@ test_that("Providing optional args works",
|
|||
confirm=FALSE))
|
||||
})
|
||||
|
||||
|
||||
test_that("Dubious requests handled gracefully",
|
||||
{
|
||||
badres <- "resource"
|
||||
expect_error(get_azure_token(badres, tenant, app, password=password, version=2))
|
||||
|
||||
nopath <- "https://management.azure.com"
|
||||
expect_warning(tok <- get_azure_token(nopath, tenant, app, password=password, version=2))
|
||||
expect_equal(tok$scope, "https://management.azure.com/.default")
|
||||
})
|
||||
|
|
Загрузка…
Ссылка в новой задаче