AzureRMR/R/AzureToken.R

127 строки
4.1 KiB
R
Исходник Обычный вид История

2018-05-01 23:24:41 +03:00
#' @export
AzureToken <- R6::R6Class("AzureToken", inherit=httr::Token2.0,
public=list(
2018-05-02 23:01:58 +03:00
2018-05-01 23:24:41 +03:00
# need to do hacky init to support explicit re-authentication instead of using a refresh token
2018-05-02 23:01:58 +03:00
initialize=function(endpoint, app, user_params, use_device=FALSE)
2018-05-01 23:24:41 +03:00
{
2018-05-02 23:01:58 +03:00
private$az_use_device <- use_device
2018-05-01 23:24:41 +03:00
params <- list(scope=NULL, user_params=user_params, type=NULL, use_oob=FALSE, as_header=TRUE,
2018-05-03 03:39:18 +03:00
use_basic_auth=use_device, config_init=list(), client_credentials=TRUE)
2018-05-01 23:24:41 +03:00
super$initialize(app=app, endpoint=endpoint, params=params, credentials=NULL, cache_path=FALSE)
2018-05-02 23:01:58 +03:00
# if auth is via device, token now contains initial server response; call devicecode handler to get actual token
if(use_device)
private$init_with_device(endpoint, app, user_params)
},
# overrides httr::Token2.0 method
can_refresh=function()
{
TRUE # always can refresh
2018-05-01 23:24:41 +03:00
},
# overrides httr::Token2.0 method
validate=function()
{
2018-05-03 05:10:10 +03:00
if(!is.null(self$endpoint$validate))
2018-05-01 23:24:41 +03:00
return(super$validate())
expdate <- as.POSIXct(as.numeric(self$credentials$expires_on), origin="1970-01-01")
curdate <- Sys.time()
curdate < expdate
},
# overrides httr::Token2.0 method
refresh=function()
{
if(!is.null(self$credentials$refresh_token))
return(super$refresh())
# re-authenticate if no refresh token
2018-05-02 23:01:58 +03:00
self$initialize(self$endpoint, self$app, self$params$user_params, use_device=private$az_use_device)
2018-05-01 23:24:41 +03:00
NULL
}
),
private=list(
2018-05-02 23:01:58 +03:00
az_use_device=NULL,
# device code authentication: after sending initial request, loop until server indicates code has been received
# after init_oauth2.0, oauth2.0_access_token
init_with_device=function(endpoint, app, user_params)
{
2018-05-02 23:16:09 +03:00
cat(self$credentials$message, "\n") # tell user to enter the code
2018-05-02 23:01:58 +03:00
req_params <- list(client_id=app$key, grant_type="device_code", code=self$credentials$device_code)
req_params <- utils::modifyList(user_params, req_params)
2018-05-03 03:39:18 +03:00
endpoint$access <- sub("devicecode", "token", endpoint$access)
2018-05-02 23:47:15 +03:00
2018-05-02 23:01:58 +03:00
interval <- as.numeric(self$credentials$interval)
2018-05-02 23:16:09 +03:00
ntries <- as.numeric(self$credentials$expires_in) %/% interval
for(i in seq_len(ntries))
2018-05-02 23:01:58 +03:00
{
Sys.sleep(interval)
2018-05-03 03:39:18 +03:00
res <- httr::POST(endpoint$access, httr::add_headers(`Cache-Control`="no-cache"), encode="form",
body=req_params)
2018-05-02 23:01:58 +03:00
status <- httr::status_code(res)
2018-05-02 23:47:15 +03:00
cont <- httr::content(res)
if(status == 400 && cont$error == "authorization_pending")
2018-05-02 23:01:58 +03:00
{
2018-05-02 23:47:15 +03:00
msg <- sub("[\r\n].*", "", cont$error_description)
2018-05-02 23:01:58 +03:00
cat(msg, "\n")
}
else if(status >= 300)
httr::stop_for_status(res)
else break
}
if(status >= 300)
stop("Unable to authenticate")
# replace original fields with authenticated fields
self$endpoint <- endpoint
2018-05-02 23:47:15 +03:00
self$credentials <- cont
2018-05-02 23:01:58 +03:00
NULL
}
2018-05-01 23:24:41 +03:00
))
#' @export
2018-05-09 09:02:38 +03:00
get_azure_token=function(aad_host, tenant, app, auth_type=c("client_credentials", "device_code"), secret, arm_host)
2018-05-01 23:24:41 +03:00
{
2018-05-07 05:33:29 +03:00
auth_type <- match.arg(auth_type)
2018-05-01 23:24:41 +03:00
base_url <- file.path(aad_host, tenant, fsep="/")
2018-05-09 09:02:38 +03:00
if(auth_type == "client_credentials")
2018-05-01 23:24:41 +03:00
auth_with_creds(base_url, app, secret, arm_host)
else auth_with_device(base_url, app, arm_host)
}
auth_with_creds <- function(base_url, app, secret, resource)
{
endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/token")
app <- httr::oauth_app("azure", key=app, secret=secret)
2018-05-02 23:01:58 +03:00
AzureToken$new(endp, app, user_params=list(resource=resource))
2018-05-01 23:24:41 +03:00
}
auth_with_device <- function(base_url, app, resource)
{
endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/devicecode")
2018-05-03 03:39:18 +03:00
app <- httr::oauth_app("azure", key=app, secret=NULL)
2018-05-01 23:24:41 +03:00
2018-05-02 23:01:58 +03:00
AzureToken$new(endp, app, user_params=list(resource=resource), use_device=TRUE)
2018-05-01 23:24:41 +03:00
}
2018-05-09 09:02:38 +03:00
is_token <- function(object)
{
R6::is.R6(object) && inherits(object, "AzureToken")
}