diff --git a/NEWS.md b/NEWS.md index bc90ef9..6545519 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,15 +3,18 @@ ## Significant interface changes * New `create_azure_login`, `get_azure_login` and `delete_azure_login` functions to handle ARM authentication. These will persist the login object across sessions, removing the need to re-authenticate each time. While directly calling `az_rm$new()` will still work, it's recommended to use `create_azure_login` and `get_azure_login` going forward. +* `get_azure_token` revamped, now supports four authentication methods for obtaining AAD tokens: + - Client credentials (what you would use with a "web app" registered service principal) + - Authorization code (for a "native" service principal) + - Device code + - With a username and password (resource owner grant) ## Other changes * Don't print empty fields for ARM objects. * Add optional `etag` field to resource object definition. -* Fix `AzureToken` object to never have a `NULL` password field (important to allow devicecode refreshing). * Add `location` argument to `az_resource_group$create_resource` method, rather than hardcoding it to the resgroup location. * Add `wait` argument when creating a new resource, similar to deploying a template, since some resources will return before provisioning is complete. Defaults to `FALSE` for backward compatibility. -* Initialise AzureToken objects with an empty string as password instead of `NULL` when using device code flow; required by httr 1.4.0's stricter input checking. * Export `is_azure_token`. # AzureRMR 1.0.0 diff --git a/R/AzureToken.R b/R/AzureToken.R index d1fcf40..75e8bb3 100644 --- a/R/AzureToken.R +++ b/R/AzureToken.R @@ -20,22 +20,27 @@ AzureToken <- R6::R6Class("AzureToken", inherit=httr::Token2.0, public=list( # need to do hacky init to support explicit re-authentication instead of using a refresh token - initialize=function(endpoint, app, user_params, use_device=FALSE) + initialize=function(endpoint, app, user_params, use_device=FALSE, client_credentials=TRUE) { private$az_use_device <- use_device params <- list(scope=NULL, user_params=user_params, type=NULL, use_oob=FALSE, as_header=TRUE, - use_basic_auth=use_device, config_init=list(), client_credentials=TRUE) + use_basic_auth=FALSE, config_init=list(), client_credentials=client_credentials) - super$initialize(app=app, endpoint=endpoint, params=params, credentials=NULL, cache_path=FALSE) + # use httr initialize for authorization_code, client_credentials methods + if(!use_device && is.null(user_params$username)) + return(super$initialize(app=app, endpoint=endpoint, params=params, cache_path=FALSE)) - # if auth is via device, token now contains initial server response; call devicecode handler to get actual token + self$app <- app + self$endpoint <- endpoint + self$params <- params + self$cache_path <- NULL + self$private_key <- NULL + + # use our own init functions for device_code, resource_owner methods if(use_device) - private$init_with_device(endpoint, app, user_params) - - # ensure password is never NULL (important for renewing) - if(is_empty(self$app$secret)) - self$app$secret <- "" + private$init_with_device(user_params) + else private$init_with_username(user_params) }, # overrides httr::Token2.0 method @@ -62,8 +67,9 @@ public=list( return(super$refresh()) # re-authenticate if no refresh token - self$initialize(self$endpoint, self$app, self$params$user_params, use_device=private$az_use_device) - NULL + self$initialize(self$endpoint, self$app, self$params$user_params, use_device=private$az_use_device, + client_credentials=self$params$client_credentials) + self } ), @@ -72,21 +78,24 @@ private=list( # 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) + init_with_device=function(user_params) { - cat(self$credentials$message, "\n") # tell user to enter the code + creds <- httr::oauth2.0_access_token(self$endpoint, self$app, code=NULL, user_params=user_params, + redirect_uri=NULL) - req_params <- list(client_id=app$key, grant_type="device_code", code=self$credentials$device_code) + cat(creds$message, "\n") # tell user to enter the code + + req_params <- list(client_id=self$app$key, grant_type="device_code", code=creds$device_code) req_params <- utils::modifyList(user_params, req_params) - endpoint$access <- sub("devicecode", "token", endpoint$access) + self$endpoint$access <- sub("devicecode$", "token", self$endpoint$access) - interval <- as.numeric(self$credentials$interval) - ntries <- as.numeric(self$credentials$expires_in) %/% interval + interval <- as.numeric(creds$interval) + ntries <- as.numeric(creds$expires_in) %/% interval for(i in seq_len(ntries)) { Sys.sleep(interval) - res <- httr::POST(endpoint$access, httr::add_headers(`Cache-Control`="no-cache"), encode="form", + res <- httr::POST(self$endpoint$access, httr::add_headers(`Cache-Control`="no-cache"), encode="form", body=req_params) status <- httr::status_code(res) @@ -103,10 +112,26 @@ private=list( if(status >= 300) stop("Unable to authenticate") - # replace original fields with authenticated fields - self$endpoint <- endpoint self$credentials <- cont NULL + }, + + # resource owner authentication: send username/password + init_with_username=function(user_params) + { + body <- list( + resource=user_params$resource, + client_id=self$app$key, + grant_type="password", + username=user_params$username, + password=user_params$password) + + res <- httr::POST(self$endpoint$access, httr::add_headers(`Cache-Control`="no-cache"), encode="form", + body=body) + + httr::stop_for_status(res, task="get an access token") + self$credentials <- httr::content(res) + NULL } )) @@ -117,58 +142,132 @@ private=list( #' #' @param resource_host URL for your resource host. For Resource Manager in the public Azure cloud, this is `https://management.azure.com/`. #' @param tenant Your tenant ID. -#' @param app Your client/app ID which you registered in AAD. -#' @param password Your password. Required for `auth_type == "client_credentials"`, ignored for `auth_type == "device_code"`. -#' @param auth_type The authentication type, either `"client_credentials"` or `"device_code"`. Defaults to the latter if no password is provided, otherwise the former. -#' @param aad_host URL for your Azure Active Directory host. For the public Azure cloud, this is `https://login.microsoftonline.com/`. +#' @param app The client/app ID to use to authenticate with Azure Active Directory (AAD). +#' @param password The password, either for the app, or your username if supplied. See 'Details' below. +#' @param username Your AAD username, if using the resource owner grant. See 'Details' below. +#' @param auth_type The authentication type. See 'Details' below. +#' @param aad_host URL for your AAD host. For the public Azure cloud, this is `https://login.microsoftonline.com/`. #' #' @details -#' This function does much the same thing as [httr::oauth2.0_token()], but with support for device authentication and with unnecessary options removed. Device authentication removes the need to save a password on your machine. Instead, the server provides you with a code, along with a URL. You then visit the URL in your browser and enter the code, which completes the authentication process. +#' This function does much the same thing as [httr::oauth2.0_token()], but customised for Azure. +#' +#' The OAuth authentication type can be one of four possible values: "authorization_code", "client_credentials", "device_code", or "resource_owner". The first two are provided by the [httr::Token2.0] token class, while the last two are provided by the AzureToken class which extends httr::Token2.0. +#' +#' If the authentication method is not specified, the value is chosen based on the presence or absence of the `password` and `username` arguments: +#' +#' - Password and username present: "resource_owner". In this +#' - Password and username absent: "authorization_code" if the httpuv package is installed, "device_code" otherwise +#' - Password present, username absent: "client_credentials" +#' - Password absent, username present: error +#' +#' The httpuv package must be installed to use the "authorization_code" method, as this requires a web server to listen on the (local) redirect URI. See [httr::oauth2.0_token] for more information; note that Azure does not support the `use_oob` feature of the httr OAuth 2.0 token class. +#' +#' Similarly, since the "authorization_code" method requires you to browse to a URL, your machine should have an Internet browser installed that can be run from inside R. In particular, if you are using a Linux [Data Science Virtual Machine](https://azure.microsoft.com/en-us/services/virtual-machines/data-science-virtual-machines/) in Azure, you may run into difficulties; use one of the other methods instead. #' #' @seealso #' [AzureToken], [httr::oauth2.0_token], [httr::Token], +#' #' [OAuth authentication for Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code), -#' [Device code flow on OAuth.com](https://www.oauth.com/oauth2-servers/device-flow/token-request/) +#' [Device code flow on OAuth.com](https://www.oauth.com/oauth2-servers/device-flow/token-request/), +#' [OAuth 2.0 RFC](https://tools.ietf.org/html/rfc6749) for the gory details on how OAuth works #' #' @examples #' \dontrun{ #' -#' token <- get_azure_token( -#' aad_host="https://login.microsoftonline.com/", +#' arm_token <- get_azure_token( +#' resource_host="https://management.azure.com/", # authenticate with Azure Resource Manager +#' tenant="myaadtenant.onmicrosoft.com", +#' app="app_id") +#' +#' storage_token <- get_azure_token( +#' resource_host="https://storage.azure.com/", # authenticate with Azure storage #' tenant="myaadtenant.onmicrosoft.com", #' app="app_id", -#' password="password", -#' resource_host="https://management.azure.com/") +#' password="password") #' #' } #' @export -get_azure_token=function(resource_host, tenant, app, password=NULL, - auth_type=if(is.null(password)) "device_code" else "client_credentials", - aad_host="https://login.microsoftonline.com/") +get_azure_token <- function(resource_host, tenant, app, password=NULL, username=NULL, auth_type=NULL, + aad_host="https://login.microsoftonline.com/") { tenant <- normalize_tenant(tenant) - base_url <- construct_path(aad_host, tenant) - if(auth_type == "client_credentials") - auth_with_creds(base_url, app, password, resource_host) - else auth_with_device(base_url, app, resource_host) + + if(is.null(auth_type)) + auth_type <- select_auth_type(password, username) + + # fail if authorization_code selected but httpuv not available + if(auth_type == "authorization_code" && system.file(package="httpuv") == "") + stop("httpuv package must be installed to use authorization_code method", call.=FALSE) + + switch(auth_type, + client_credentials= + auth_with_client_creds(base_url, app, password, resource_host), + device_code= + auth_with_device(base_url, app, resource_host), + authorization_code= + auth_with_code(base_url, app, resource_host), + resource_owner= + auth_with_username(base_url, app, password, username, resource_host), + stop("Invalid auth_type argument", call.=FALSE)) } -auth_with_creds <- function(base_url, app, password, resource) +auth_with_client_creds <- function(base_url, app, password, resource) { endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/token") app <- httr::oauth_app("azure", key=app, secret=password) - AzureToken$new(endp, app, user_params=list(resource=resource)) + AzureToken$new(endp, app, user_params=list(resource=resource), use_device=FALSE, client_credentials=TRUE) } auth_with_device <- function(base_url, app, resource) { endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/devicecode") - app <- httr::oauth_app("azure", key=app, secret="") + app <- httr::oauth_app("azure", key=app, secret=NULL) - AzureToken$new(endp, app, user_params=list(resource=resource), use_device=TRUE) + AzureToken$new(endp, app, user_params=list(resource=resource), use_device=TRUE, client_credentials=FALSE) } + +auth_with_code <- function(base_url, app, resource) +{ + endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/token") + app <- httr::oauth_app("azure", key=app, secret=NULL) + + AzureToken$new(endp, app, user_params=list(resource=resource), use_device=FALSE, client_credentials=FALSE) +} + + +auth_with_username <- function(base_url, app, password, username, resource) +{ + endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/token") + app <- httr::oauth_app("azure", key=app, secret=NULL) + + AzureToken$new(endp, app, user_params=list(resource=resource, username=username, password=password), + use_device=FALSE, client_credentials=FALSE) +} + + +# select authentication method based on input arguments and presence of httpuv +select_auth_type <- function(password, username) +{ + got_pwd <- !is.null(password) + got_user <- !is.null(username) + + if(got_pwd && got_user) + "resource_owner" + else if(!got_pwd && !got_user) + { + if(system.file(package="httpuv") == "") + { + message("httpuv not installed, defaulting to device code authentication") + "device_code" + } + else "authorization_code" + } + else if(got_pwd && !got_user) + "client_credentials" + else stop("Can't select authentication method", call.=FALSE) +} diff --git a/R/az_auth.R b/R/az_auth.R index 5ccb5ae..76d381a 100644 --- a/R/az_auth.R +++ b/R/az_auth.R @@ -15,9 +15,10 @@ #' #' To authenticate with the `az_rm` class directly, provide the following arguments to the `new` method: #' - `tenant`: Your tenant ID. -#' - `app`: Your client/app ID which you registered in Azure Active Directory. -#' - `password`: if `auth_type == "client_credentials"`, your password. -#' - `auth_type`: Either `"client_credentials"` or `"device_code"`. Defaults to the latter if no password is provided, otherwise the former. +#' - `app`: The client/app ID to use to authenticate with Azure Active Directory. +#' - `password`: if `auth_type == "client_credentials"`, the app secret; if `auth_type == "resource_owner"`, your account password. +#' - `username`: if `auth_type == "resource_owner"`, your username. +#' - `auth_type`: The OAuth authentication method to use, one of "client_credentials", "authorization_code", "device_code" or "resource_owner". See [get_azure_token] for how the default method is chosen, along with some caveats. #' - `host`: your ARM host. Defaults to `https://management.azure.com/`. Change this if you are using a government or private cloud. #' - `aad_host`: Azure Active Directory host for authentication. Defaults to `https://login.microsoftonline.com/`. Change this if you are using a government or private cloud. #' - `config_file`: Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI `az ad sp create-for-rbac` command. @@ -57,8 +58,7 @@ public=list( token=NULL, # authenticate and get subscriptions - initialize=function(tenant, app, password=NULL, - auth_type=if(is.null(password)) "device_code" else "client_credentials", + initialize=function(tenant, app, password=NULL, username=NULL, auth_type=NULL, host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/", config_file=NULL, token=NULL) { @@ -82,7 +82,7 @@ public=list( } self$host <- host self$tenant <- normalize_tenant(tenant) - self$token <- get_azure_token(self$host, self$tenant, app, password, auth_type, aad_host) + self$token <- get_azure_token(self$host, self$tenant, app, password, username, auth_type, aad_host) NULL }, diff --git a/R/az_login.R b/R/az_login.R index 529d81a..381853d 100644 --- a/R/az_login.R +++ b/R/az_login.R @@ -7,9 +7,10 @@ config_dir <- function() #' Functions to login to Azure Resource Manager #' #' @param tenant The Azure Active Directory tenant for which to obtain a login client. Can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a GUID. -#' @param app The app ID to authenticate with. -#' @param password If `auth_type == "client_credentials"`, your password. -#' @param auth_type The type of authentication to use, either "device_code" or "client_credentials". Defaults to the latter if no password is provided, otherwise the former. +#' @param app The client/app ID to use to authenticate with Azure Active Directory. +#' @param password If `auth_type == "client_credentials"`, the app secret; if `auth_type == "resource_owner"`, your account password. +#' @param username If `auth_type == "resource_owner"`, your username. +#' @param auth_type The OAuth authentication method to use, one of "client_credentials", "authorization_code", "device_code" or "resource_owner". See [get_azure_token] for how the default method is chosen. #' @param host Your ARM host. Defaults to `https://management.azure.com/`. Change this if you are using a government or private cloud. #' @param aad_host Azure Active Directory host for authentication. Defaults to `https://login.microsoftonline.com/`. Change this if you are using a government or private cloud. #' @param config_file Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI `az ad sp create-for-rbac` command. @@ -53,8 +54,7 @@ config_dir <- function() #' } #' @rdname azure_login #' @export -create_azure_login <- function(tenant, app, password=NULL, - auth_type=if(is.null(password)) "device_code" else "client_credentials", +create_azure_login <- function(tenant, app, password=NULL, username=NULL, auth_type=NULL, host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/", config_file=NULL, ...) { @@ -71,7 +71,7 @@ create_azure_login <- function(tenant, app, password=NULL, tenant <- normalize_tenant(tenant) message("Creating Azure Active Directory login for tenant '", tenant, "'") - client <- az_rm$new(tenant, app, password, auth_type, host, aad_host, config_file, ...) + client <- az_rm$new(tenant, app, password, username, auth_type, host, aad_host, config_file, ...) save_client(client, tenant) client } diff --git a/README.md b/README.md index b8009cd..28e297e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![Downloads](https://cranlogs.r-pkg.org/badges/AzureRMR) [![Travis Build Status](https://travis-ci.org/cloudyr/AzureRMR.png?branch=master)](https://travis-ci.org/cloudyr/AzureRMR) -AzureRMR is a package for interacting with Azure Resource Manager: authenticate, list subscriptions, manage resource groups, deploy and delete templates and resources. It calls the Resource Manager [REST API](https://docs.microsoft.com/en-us/rest/api/resources) directly, so you don't need to have PowerShell or Python installed. +AzureRMR is a package for interacting with Azure Active Directory and Azure Resource Manager: obtain AAD authentication tokens, list subscriptions, manage resource groups, deploy and delete templates and resources. It calls the Resource Manager [REST API](https://docs.microsoft.com/en-us/rest/api/resources) directly, so you don't need to have PowerShell or Python installed. You can install the development version from GitHub, via `devtools::install_github("cloudyr/AzureRMR")`. diff --git a/man/az_rm.Rd b/man/az_rm.Rd index 7664ac8..fb8f8a6 100644 --- a/man/az_rm.Rd +++ b/man/az_rm.Rd @@ -27,9 +27,10 @@ The best way to authenticate with ARM is probably via the \link{create_azure_log To authenticate with the \code{az_rm} class directly, provide the following arguments to the \code{new} method: \itemize{ \item \code{tenant}: Your tenant ID. -\item \code{app}: Your client/app ID which you registered in Azure Active Directory. -\item \code{password}: if \code{auth_type == "client_credentials"}, your password. -\item \code{auth_type}: Either \code{"client_credentials"} or \code{"device_code"}. Defaults to the latter if no password is provided, otherwise the former. +\item \code{app}: The client/app ID to use to authenticate with Azure Active Directory. +\item \code{password}: if \code{auth_type == "client_credentials"}, the app secret; if \code{auth_type == "resource_owner"}, your account password. +\item \code{username}: if \code{auth_type == "resource_owner"}, your username. +\item \code{auth_type}: The OAuth authentication method to use, one of "client_credentials", "authorization_code", "device_code" or "resource_owner". See \link{get_azure_token} for how the default method is chosen, along with some caveats. \item \code{host}: your ARM host. Defaults to \code{https://management.azure.com/}. Change this if you are using a government or private cloud. \item \code{aad_host}: Azure Active Directory host for authentication. Defaults to \code{https://login.microsoftonline.com/}. Change this if you are using a government or private cloud. \item \code{config_file}: Optionally, a JSON file containing any of the arguments listed above. Arguments supplied in this file take priority over those supplied on the command line. You can also use the output from the Azure CLI \code{az ad sp create-for-rbac} command. diff --git a/man/azure_login.Rd b/man/azure_login.Rd index 8399908..a21756e 100644 --- a/man/azure_login.Rd +++ b/man/azure_login.Rd @@ -8,9 +8,8 @@ \alias{refresh_azure_logins} \title{Functions to login to Azure Resource Manager} \usage{ -create_azure_login(tenant, app, password = NULL, auth_type = if - (is.null(password)) "device_code" else "client_credentials", - host = "https://management.azure.com/", +create_azure_login(tenant, app, password = NULL, username = NULL, + auth_type = NULL, host = "https://management.azure.com/", aad_host = "https://login.microsoftonline.com/", config_file = NULL, ...) @@ -25,11 +24,13 @@ refresh_azure_logins() \arguments{ \item{tenant}{The Azure Active Directory tenant for which to obtain a login client. Can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a GUID.} -\item{app}{The app ID to authenticate with.} +\item{app}{The client/app ID to use to authenticate with Azure Active Directory.} -\item{password}{If \code{auth_type == "client_credentials"}, your password.} +\item{password}{If \code{auth_type == "client_credentials"}, the app secret; if \code{auth_type == "resource_owner"}, your account password.} -\item{auth_type}{The type of authentication to use, either "device_code" or "client_credentials". Defaults to the latter if no password is provided, otherwise the former.} +\item{username}{If \code{auth_type == "resource_owner"}, your username.} + +\item{auth_type}{The OAuth authentication method to use, one of "client_credentials", "authorization_code", "device_code" or "resource_owner". See \link{get_azure_token} for how the default method is chosen.} \item{host}{Your ARM host. Defaults to \code{https://management.azure.com/}. Change this if you are using a government or private cloud.} diff --git a/man/get_azure_token.Rd b/man/get_azure_token.Rd index 6323278..349cace 100644 --- a/man/get_azure_token.Rd +++ b/man/get_azure_token.Rd @@ -5,42 +5,64 @@ \title{Generate an Azure OAuth token} \usage{ get_azure_token(resource_host, tenant, app, password = NULL, - auth_type = if (is.null(password)) "device_code" else - "client_credentials", aad_host = "https://login.microsoftonline.com/") + username = NULL, auth_type = NULL, + aad_host = "https://login.microsoftonline.com/") } \arguments{ \item{resource_host}{URL for your resource host. For Resource Manager in the public Azure cloud, this is \code{https://management.azure.com/}.} \item{tenant}{Your tenant ID.} -\item{app}{Your client/app ID which you registered in AAD.} +\item{app}{The client/app ID to use to authenticate with Azure Active Directory (AAD).} -\item{password}{Your password. Required for \code{auth_type == "client_credentials"}, ignored for \code{auth_type == "device_code"}.} +\item{password}{The password, either for the app, or your username if supplied. See 'Details' below.} -\item{auth_type}{The authentication type, either \code{"client_credentials"} or \code{"device_code"}. Defaults to the latter if no password is provided, otherwise the former.} +\item{username}{Your AAD username, if using the resource owner grant. See 'Details' below.} -\item{aad_host}{URL for your Azure Active Directory host. For the public Azure cloud, this is \code{https://login.microsoftonline.com/}.} +\item{auth_type}{The authentication type. See 'Details' below.} + +\item{aad_host}{URL for your AAD host. For the public Azure cloud, this is \code{https://login.microsoftonline.com/}.} } \description{ This extends the OAuth functionality in httr to allow for device code authentication. } \details{ -This function does much the same thing as \code{\link[httr:oauth2.0_token]{httr::oauth2.0_token()}}, but with support for device authentication and with unnecessary options removed. Device authentication removes the need to save a password on your machine. Instead, the server provides you with a code, along with a URL. You then visit the URL in your browser and enter the code, which completes the authentication process. +This function does much the same thing as \code{\link[httr:oauth2.0_token]{httr::oauth2.0_token()}}, but customised for Azure. + +The OAuth authentication type can be one of four possible values: "authorization_code", "client_credentials", "device_code", or "resource_owner". The first two are provided by the \link[httr:Token2.0]{httr::Token2.0} token class, while the last two are provided by the AzureToken class which extends httr::Token2.0. + +If the authentication method is not specified, the value is chosen based on the presence or absence of the \code{password} and \code{username} arguments: +\itemize{ +\item Password and username present: "resource_owner". In this +\item Password and username absent: "authorization_code" if the httpuv package is installed, "device_code" otherwise +\item Password present, username absent: "client_credentials" +\item Password absent, username present: error +} + +The httpuv package must be installed to use the "authorization_code" method, as this requires a web server to listen on the (local) redirect URI. See \link[httr:oauth2.0_token]{httr::oauth2.0_token} for more information; note that Azure does not support the \code{use_oob} feature of the httr OAuth 2.0 token class. + +Similarly, since the "authorization_code" method requires you to browse to a URL, your machine should have an Internet browser installed that can be run from inside R. In particular, if you are using a Linux \href{https://azure.microsoft.com/en-us/services/virtual-machines/data-science-virtual-machines/}{Data Science Virtual Machine} in Azure, you may run into difficulties; use one of the other methods instead. } \examples{ \dontrun{ -token <- get_azure_token( - aad_host="https://login.microsoftonline.com/", +arm_token <- get_azure_token( + resource_host="https://management.azure.com/", # authenticate with Azure Resource Manager + tenant="myaadtenant.onmicrosoft.com", + app="app_id") + +storage_token <- get_azure_token( + resource_host="https://storage.azure.com/", # authenticate with Azure storage tenant="myaadtenant.onmicrosoft.com", app="app_id", - password="password", - resource_host="https://management.azure.com/") + password="password") } } \seealso{ \link{AzureToken}, \link[httr:oauth2.0_token]{httr::oauth2.0_token}, \link[httr:Token]{httr::Token}, + \href{https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code}{OAuth authentication for Azure Active Directory}, -\href{https://www.oauth.com/oauth2-servers/device-flow/token-request/}{Device code flow on OAuth.com} +\href{https://www.oauth.com/oauth2-servers/device-flow/token-request/}{Device code flow on OAuth.com}, +\href{https://tools.ietf.org/html/rfc6749}{OAuth 2.0 RFC} for the gory details on how OAuth works } diff --git a/tests/testthat/test01_auth.R b/tests/testthat/test01_auth.R index ca4097a..fc71c03 100644 --- a/tests/testthat/test01_auth.R +++ b/tests/testthat/test01_auth.R @@ -32,7 +32,7 @@ test_that("Authentication works", test_that("Persistent authentication works", { - expect_true(is.null(delete_azure_login(tenant, confirm=FALSE))) + expect_true(suppressWarnings(is.null(delete_azure_login(tenant, confirm=FALSE)))) expect_true(all(names(list_azure_logins()) != tenant)) login_dirs <- rappdirs::user_config_dir("AzureRMR", "AzureR", roaming=FALSE)