Merge pull request #5 from cloudyr/token-revamp

Token revamp
This commit is contained in:
Hong Ooi 2019-01-11 07:21:28 +11:00 коммит произвёл GitHub
Родитель 40eb4cc896 03bda29635
Коммит b029bfc253
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 204 добавлений и 78 удалений

Просмотреть файл

@ -3,15 +3,18 @@
## Significant interface changes ## 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. * 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 ## Other changes
* Don't print empty fields for ARM objects. * Don't print empty fields for ARM objects.
* Add optional `etag` field to resource object definition. * 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 `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. * 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`. * Export `is_azure_token`.
# AzureRMR 1.0.0 # AzureRMR 1.0.0

Просмотреть файл

@ -20,22 +20,27 @@ AzureToken <- R6::R6Class("AzureToken", inherit=httr::Token2.0,
public=list( public=list(
# need to do hacky init to support explicit re-authentication instead of using a refresh token # 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 private$az_use_device <- use_device
params <- list(scope=NULL, user_params=user_params, type=NULL, use_oob=FALSE, as_header=TRUE, 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) if(use_device)
private$init_with_device(endpoint, app, user_params) private$init_with_device(user_params)
else private$init_with_username(user_params)
# ensure password is never NULL (important for renewing)
if(is_empty(self$app$secret))
self$app$secret <- ""
}, },
# overrides httr::Token2.0 method # overrides httr::Token2.0 method
@ -62,8 +67,9 @@ public=list(
return(super$refresh()) return(super$refresh())
# re-authenticate if no refresh token # re-authenticate if no refresh token
self$initialize(self$endpoint, self$app, self$params$user_params, use_device=private$az_use_device) self$initialize(self$endpoint, self$app, self$params$user_params, use_device=private$az_use_device,
NULL 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 # device code authentication: after sending initial request, loop until server indicates code has been received
# after init_oauth2.0, oauth2.0_access_token # 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) 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) interval <- as.numeric(creds$interval)
ntries <- as.numeric(self$credentials$expires_in) %/% interval ntries <- as.numeric(creds$expires_in) %/% interval
for(i in seq_len(ntries)) for(i in seq_len(ntries))
{ {
Sys.sleep(interval) 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) body=req_params)
status <- httr::status_code(res) status <- httr::status_code(res)
@ -103,10 +112,26 @@ private=list(
if(status >= 300) if(status >= 300)
stop("Unable to authenticate") stop("Unable to authenticate")
# replace original fields with authenticated fields
self$endpoint <- endpoint
self$credentials <- cont self$credentials <- cont
NULL 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 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 tenant Your tenant ID.
#' @param app Your client/app ID which you registered in AAD. #' @param app The client/app ID to use to authenticate with Azure Active Directory (AAD).
#' @param password Your password. Required for `auth_type == "client_credentials"`, ignored for `auth_type == "device_code"`. #' @param password The password, either for the app, or your username if supplied. See 'Details' below.
#' @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 username Your AAD username, if using the resource owner grant. See 'Details' below.
#' @param aad_host URL for your Azure Active Directory host. For the public Azure cloud, this is `https://login.microsoftonline.com/`. #' @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 #' @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 #' @seealso
#' [AzureToken], [httr::oauth2.0_token], [httr::Token], #' [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), #' [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 #' @examples
#' \dontrun{ #' \dontrun{
#' #'
#' token <- get_azure_token( #' arm_token <- get_azure_token(
#' aad_host="https://login.microsoftonline.com/", #' 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", #' tenant="myaadtenant.onmicrosoft.com",
#' app="app_id", #' app="app_id",
#' password="password", #' password="password")
#' resource_host="https://management.azure.com/")
#' #'
#' } #' }
#' @export #' @export
get_azure_token=function(resource_host, tenant, app, password=NULL, get_azure_token <- function(resource_host, tenant, app, password=NULL, username=NULL, auth_type=NULL,
auth_type=if(is.null(password)) "device_code" else "client_credentials", aad_host="https://login.microsoftonline.com/")
aad_host="https://login.microsoftonline.com/")
{ {
tenant <- normalize_tenant(tenant) tenant <- normalize_tenant(tenant)
base_url <- construct_path(aad_host, tenant) base_url <- construct_path(aad_host, tenant)
if(auth_type == "client_credentials")
auth_with_creds(base_url, app, password, resource_host) if(is.null(auth_type))
else auth_with_device(base_url, app, resource_host) 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") endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/token")
app <- httr::oauth_app("azure", key=app, secret=password) 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) auth_with_device <- function(base_url, app, resource)
{ {
endp <- httr::oauth_endpoint(base_url=base_url, authorize="oauth2/authorize", access="oauth2/devicecode") 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)
}

Просмотреть файл

@ -15,9 +15,10 @@
#' #'
#' To authenticate with the `az_rm` class directly, provide the following arguments to the `new` method: #' To authenticate with the `az_rm` class directly, provide the following arguments to the `new` method:
#' - `tenant`: Your tenant ID. #' - `tenant`: Your tenant ID.
#' - `app`: Your client/app ID which you registered in Azure Active Directory. #' - `app`: The client/app ID to use to authenticate with Azure Active Directory.
#' - `password`: if `auth_type == "client_credentials"`, your password. #' - `password`: if `auth_type == "client_credentials"`, the app secret; if `auth_type == "resource_owner"`, your account password.
#' - `auth_type`: Either `"client_credentials"` or `"device_code"`. Defaults to the latter if no password is provided, otherwise the former. #' - `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. #' - `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. #' - `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. #' - `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, token=NULL,
# authenticate and get subscriptions # authenticate and get subscriptions
initialize=function(tenant, app, password=NULL, initialize=function(tenant, app, password=NULL, username=NULL, auth_type=NULL,
auth_type=if(is.null(password)) "device_code" else "client_credentials",
host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/", host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/",
config_file=NULL, token=NULL) config_file=NULL, token=NULL)
{ {
@ -82,7 +82,7 @@ public=list(
} }
self$host <- host self$host <- host
self$tenant <- normalize_tenant(tenant) 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 NULL
}, },

Просмотреть файл

@ -7,9 +7,10 @@ config_dir <- function()
#' Functions to login to Azure Resource Manager #' 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 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 app The client/app ID to use to authenticate with Azure Active Directory.
#' @param password If `auth_type == "client_credentials"`, your password. #' @param password If `auth_type == "client_credentials"`, the app secret; if `auth_type == "resource_owner"`, your account 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 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 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 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. #' @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 #' @rdname azure_login
#' @export #' @export
create_azure_login <- function(tenant, app, password=NULL, create_azure_login <- function(tenant, app, password=NULL, username=NULL, auth_type=NULL,
auth_type=if(is.null(password)) "device_code" else "client_credentials",
host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/", host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/",
config_file=NULL, ...) config_file=NULL, ...)
{ {
@ -71,7 +71,7 @@ create_azure_login <- function(tenant, app, password=NULL,
tenant <- normalize_tenant(tenant) tenant <- normalize_tenant(tenant)
message("Creating Azure Active Directory login for 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) save_client(client, tenant)
client client
} }

Просмотреть файл

@ -4,7 +4,7 @@
![Downloads](https://cranlogs.r-pkg.org/badges/AzureRMR) ![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) [![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")`. You can install the development version from GitHub, via `devtools::install_github("cloudyr/AzureRMR")`.

Просмотреть файл

@ -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: To authenticate with the \code{az_rm} class directly, provide the following arguments to the \code{new} method:
\itemize{ \itemize{
\item \code{tenant}: Your tenant ID. \item \code{tenant}: Your tenant ID.
\item \code{app}: Your client/app ID which you registered in Azure Active Directory. \item \code{app}: The client/app ID to use to authenticate with Azure Active Directory.
\item \code{password}: if \code{auth_type == "client_credentials"}, your password. \item \code{password}: if \code{auth_type == "client_credentials"}, the app secret; if \code{auth_type == "resource_owner"}, your account 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{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{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{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. \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.

Просмотреть файл

@ -8,9 +8,8 @@
\alias{refresh_azure_logins} \alias{refresh_azure_logins}
\title{Functions to login to Azure Resource Manager} \title{Functions to login to Azure Resource Manager}
\usage{ \usage{
create_azure_login(tenant, app, password = NULL, auth_type = if create_azure_login(tenant, app, password = NULL, username = NULL,
(is.null(password)) "device_code" else "client_credentials", auth_type = NULL, host = "https://management.azure.com/",
host = "https://management.azure.com/",
aad_host = "https://login.microsoftonline.com/", config_file = NULL, aad_host = "https://login.microsoftonline.com/", config_file = NULL,
...) ...)
@ -25,11 +24,13 @@ refresh_azure_logins()
\arguments{ \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{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.} \item{host}{Your ARM host. Defaults to \code{https://management.azure.com/}. Change this if you are using a government or private cloud.}

Просмотреть файл

@ -5,42 +5,64 @@
\title{Generate an Azure OAuth token} \title{Generate an Azure OAuth token}
\usage{ \usage{
get_azure_token(resource_host, tenant, app, password = NULL, get_azure_token(resource_host, tenant, app, password = NULL,
auth_type = if (is.null(password)) "device_code" else username = NULL, auth_type = NULL,
"client_credentials", aad_host = "https://login.microsoftonline.com/") aad_host = "https://login.microsoftonline.com/")
} }
\arguments{ \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{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{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{ \description{
This extends the OAuth functionality in httr to allow for device code authentication. This extends the OAuth functionality in httr to allow for device code authentication.
} }
\details{ \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{ \examples{
\dontrun{ \dontrun{
token <- get_azure_token( arm_token <- get_azure_token(
aad_host="https://login.microsoftonline.com/", 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", tenant="myaadtenant.onmicrosoft.com",
app="app_id", app="app_id",
password="password", password="password")
resource_host="https://management.azure.com/")
} }
} }
\seealso{ \seealso{
\link{AzureToken}, \link[httr:oauth2.0_token]{httr::oauth2.0_token}, \link[httr:Token]{httr::Token}, \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://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
} }

Просмотреть файл

@ -32,7 +32,7 @@ test_that("Authentication works",
test_that("Persistent 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)) expect_true(all(names(list_azure_logins()) != tenant))
login_dirs <- rappdirs::user_config_dir("AzureRMR", "AzureR", roaming=FALSE) login_dirs <- rappdirs::user_config_dir("AzureRMR", "AzureR", roaming=FALSE)