This commit is contained in:
hong-revo 2019-01-14 08:28:26 +11:00
Родитель dd698633f3
Коммит 24018e92fd
11 изменённых файлов: 377 добавлений и 99 удалений

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

@ -10,20 +10,25 @@ export(call_azure_rm)
export(call_azure_url)
export(create_azure_login)
export(delete_azure_login)
export(delete_azure_token)
export(format_auth_header)
export(format_public_fields)
export(format_public_methods)
export(get_azure_login)
export(get_azure_token)
export(is_azure_login)
export(is_azure_token)
export(is_empty)
export(is_guid)
export(is_resource)
export(is_resource_group)
export(is_subscription)
export(is_template)
export(is_url)
export(list_azure_logins)
export(list_azure_tokens)
export(named_list)
export(normalize_guid)
export(normalize_tenant)
export(refresh_azure_logins)
importFrom(utils,modifyList)

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

@ -8,7 +8,7 @@
#' - `validate`: Checks if the token is still valid. For Azure tokens using client credentials, this just checks if the current time is less than the token's expiry time.
#'
#' @section Caching:
#' This class never caches its tokens, unlike httr::Token2.0.
#' Unlike httr::Token2.0, caching for Azure tokens is handled outside the class. Tokens are automatically cached by the `get_azure_token` function, and can be (manually) deleted with the `delete_azure_token` function. Calling `AzureToken$new()` directly will always acquire a new token from the server.
#'
#' @seealso
#' [get_azure_token], [httr::Token]
@ -46,7 +46,7 @@ public=list(
# overrides httr::Token method: caching done outside class
hash=function()
{
NULL
stop("Caching not handled by AzureToken class")
},
# overrides httr::Token2.0 method
@ -142,9 +142,9 @@ private=list(
))
#' Generate an Azure OAuth token
#' Manage Azure Active Directory OAuth 2.0 tokens
#'
#' This extends the OAuth functionality in httr for use with Azure Active Directory (AAD).
#' These functions extend the OAuth functionality in httr for use with Azure Active Directory (AAD).
#'
#' @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. This can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a GUID.
@ -155,17 +155,18 @@ private=list(
#' @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 customised for Azure.
#' `get_azure_token` does much the same thing as [httr::oauth2.0_token()], but customised for Azure. It obtains an OAuth token, first by checking if a cached value exists on disk, and if not, acquiring it from the AAD server. `delete_azure_token` deletes a cached token, and `list_azure_tokens` lists currently cached tokens.
#'
#' @section Authentication methods:
#' 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. Here is a short description of these methods.
#'
#' - Using the authorization_code method is a 3-step process. First, `get_azure_token` contacts the AAD authorization endpoint to obtain a temporary access code. It then contacts the AAD access endpoint, passing it the code. The access endpoint sends back a login URL which `get_azure_token` opens in your browser, where you can enter your credentials. Once this is completed, the endpoint returns the OAuth token via a HTTP redirect URI.
#' 1. Using the authorization_code method is a 3-step process. First, `get_azure_token` contacts the AAD authorization endpoint to obtain a temporary access code. It then contacts the AAD access endpoint, passing it the code. The access endpoint sends back a login URL which `get_azure_token` opens in your browser, where you can enter your credentials. Once this is completed, the endpoint returns the OAuth token via a HTTP redirect URI.
#'
#' - The device_code method is similar in concept to authorization_code, but is meant for situations where you are unable to browse the Internet -- for example if you don't have a browser installed or your computer has input constraints. First, `get_azure_token` contacts the AAD devicecode endpoint, which responds with a login URL and an access code. You then visit the URL and enter the code, possibly using a different computer. Meanwhile, `get_azure_token` polls the AAD access endpoint for a token, which is provided once you have successfully entered the code.
#' 2. The device_code method is similar in concept to authorization_code, but is meant for situations where you are unable to browse the Internet -- for example if you don't have a browser installed or your computer has input constraints. First, `get_azure_token` contacts the AAD devicecode endpoint, which responds with a login URL and an access code. You then visit the URL and enter the code, possibly using a different computer. Meanwhile, `get_azure_token` polls the AAD access endpoint for a token, which is provided once you have successfully entered the code.
#'
#' - The client_credentials method is much simpler than the above methods, requiring only one step. `get_azure_token` contacts the access endpoint, passing it the app secret (which you supplied in the `password` argument). Assuming the secret is valid, the endpoint then returns the OAuth token.
#' 3. The client_credentials method is much simpler than the above methods, requiring only one step. `get_azure_token` contacts the access endpoint, passing it the app secret (which you supplied in the `password` argument). Assuming the secret is valid, the endpoint then returns the OAuth token.
#'
#' - The resource_owner method also requires only one step. In this method, `get_azure_token` passes your (personal) username and password to the AAD access endpoint, which validates your credentials and returns the token.
#' 4. The resource_owner method also requires only one step. In this method, `get_azure_token` passes your (personal) username and password to the AAD access endpoint, which validates your credentials and returns the token.
#'
#' If the authentication method is not specified, it is chosen based on the presence or absence of the `password` and `username` arguments:
#'
@ -178,6 +179,20 @@ private=list(
#'
#' Similarly, since the authorization_code method opens a browser to load the AAD authorization page, your machine must 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.
#'
#' @section Caching:
#' AzureRMR differs from httr in its handling of token caching in a number of ways.
#'
#' - It moves caching of OAuth tokens out of the token class, and into the `get_azure_token` function. Caching is based on all the inputs to `get_azure_token` as listed above. Directly calling the AzureToken class constructor will always acquire a new token from the server.
#'
#' - It defines its own directory for caching tokens, using the rappdirs package. On recent Windows versions, this will usually be in the location `C:\\Users\\(username)\\AppData\\Local\\AzureR\\AzureRMR`. On Linux, it will be in `~/.config/AzureRMR`, and on MacOS, it will be in `~/Library/Application Support/AzureRMR`. Note that a single directory is used for all tokens, unlike httr, and the working directory is not touched (which lessens the risk of accidentally introducing cached tokens into source control).
#'
#' To list all cached tokens on disk, use `list_azure_tokens`. This returns a list of token objects, named according to their MD5 hashes.
#'
#' To delete a cached token, use `delete_azure_token`. This takes the same inputs as `get_azure_token`, or you can specify the MD5 hash directly in the `hash` argument.
#'
#' @section Value:
#' For `get_azure_token`, an object of class `AzureToken` representing the AAD token. For `list_azure_tokens`, a list of such objects retrieved from disk.
#'
#' @seealso
#' [AzureToken], [httr::oauth2.0_token], [httr::Token],
#'
@ -220,15 +235,32 @@ private=list(
#' owner_token <- get_azure_token(
#' resource_host="https://myresource/",
#' tenant="myaadtenant",
#' app="app_id",
#' username="user",
#' password="abcdefg")
#'
#' # list saved tokens
#' list_azure_tokens()
#'
#' # delete a saved token from disk
#' delete_azure_token(
#' resource_host="https://myresource/",
#' tenant="myaadtenant",
#' app="app_id",
#' username="user",
#' password="abcdefg")
#'
#' # delete a saved token by specifying its MD5 hash
#' delete_azure_token(hash="7ea491716e5b10a77a673106f3f53bfd")
#'
#' }
#' @export
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)
if(is_guid(app))
app <- normalize_guid(app)
base_url <- construct_path(aad_host, tenant)
if(is.null(auth_type))
@ -241,8 +273,10 @@ get_azure_token <- function(resource_host, tenant, app, password=NULL, username=
# load saved token if available
tokenfile <- file.path(config_dir(),
token_hash(resource_host, tenant, app, password, username, auth_type, aad_host))
if(file.exists(tokenfile))
{
message("Loading saved token")
token <- readRDS(tokenfile)
token$refresh()
}
@ -324,6 +358,57 @@ select_auth_type <- function(password, username)
}
#' @param hash The MD5 hash of this token, computed from the above inputs. Used by `delete_azure_token` for identification purposes.
#' @param confirm For `delete_azure_token`, whether to prompt for confirmation before deleting a token.
#' @rdname get_azure_token
#' @export
delete_azure_token <- function(resource_host, tenant, app, password=NULL, username=NULL, auth_type=NULL,
aad_host="https://login.microsoftonline.com/",
hash=NULL,
confirm=TRUE)
{
if(is.null(hash))
{
tenant <- normalize_tenant(tenant)
if(is_guid(app))
app <- normalize_guid(app)
base_url <- construct_path(aad_host, tenant)
if(is.null(auth_type))
auth_type <- select_auth_type(password, username)
hash <- token_hash(resource_host, tenant, app, password, username, auth_type, aad_host)
}
if(confirm && interactive())
{
yn <- readline(
paste0("Do you really want to delete this Azure Active Directory token? (y/N) "))
if(tolower(substr(yn, 1, 1)) != "y")
return(invisible(NULL))
}
file.remove(file.path(config_dir(), hash))
invisible(NULL)
}
#' @rdname get_azure_token
#' @export
list_azure_tokens <- function()
{
tokens <- dir(config_dir(), full.names=TRUE)
lst <- lapply(tokens, function(fname)
{
x <- readRDS(fname)
if(is_azure_token(x))
x
else NULL
})
names(lst) <- basename(tokens)
lst[!sapply(lst, is.null)]
}
token_hash <- function(resource_host, tenant, app, password, username, auth_type, aad_host)
{
msg <- serialize(list(resource_host, tenant, app, password, username, auth_type, aad_host), NULL, version=2)
@ -331,52 +416,3 @@ token_hash <- function(resource_host, tenant, app, password, username, auth_type
}
#' Normalizes a tenant
#'
#' @param tenant An Azure Active Directory tenant. This can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a valid GUID.
#'
#' @details
#' This function is used by `get_azure_token` to recognise a tenant input. A tenant can be identified either by a GUID, or its name, or a fully-qualified domain name (FQDN). The rules for normalizing a tenant are:
#' 1. If `tenant` is a valid GUID, return its canonically formatted value
#' 2. Otherwise, if it is a FQDN, return it
#' 3. Otherwise, if it is not the string "common", append ".onmicrosoft.com" to it
#' 4. Otherwise, return the value of `tenant`
#'
#' @return
#' The normalized ID or name of the tenant.
#' @seealso
#' [get_azure_token],
#'
#' [Parsing rules for GUIDs in .NET](https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse]). `normalize_tenant` recognises the "N", "D", "B" and "P" formats for GUIDs.
#' @export
normalize_tenant <- function(tenant)
{
# see https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse
# for possible input formats for GUIDs
is_guid <- function(x)
{
grepl("^[0-9a-f]{32}$", x) ||
grepl("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", x) ||
grepl("^\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}$", x) ||
grepl("^\\([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\)$", x)
}
# check if supplied a guid; if not, check if a fqdn;
# if not, check if 'common'; if not, append '.onmicrosoft.com'
if(is_guid(tenant))
{
tenant <- sub("^[({]?([-0-9a-f]+)[})]$", "\\1", tenant)
tenant <- gsub("-", "", tenant)
return(paste(
substr(tenant, 1, 8),
substr(tenant, 9, 12),
substr(tenant, 13, 16),
substr(tenant, 17, 20),
substr(tenant, 21, 32), sep="-"))
}
if(!grepl("\\.", tenant) && tenant != "common")
tenant <- paste(tenant, "onmicrosoft.com", sep=".")
tenant
}

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

@ -55,8 +55,8 @@ config_dir <- function()
#' @rdname azure_login
#' @export
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, ...)
host="https://management.azure.com/", aad_host="https://login.microsoftonline.com/",
config_file=NULL, ...)
{
if(!is.null(config_file))
{
@ -70,6 +70,8 @@ create_azure_login <- function(tenant, app, password=NULL, username=NULL, auth_t
}
tenant <- normalize_tenant(tenant)
if(is_guid(app))
app <- normalize_guid(app)
message("Creating Azure Resource Manager login for tenant '", tenant, "'")
client <- az_rm$new(tenant, app, password, username, auth_type, host, aad_host, config_file, ...)
save_client(client, tenant)
@ -123,9 +125,15 @@ delete_azure_login <- function(tenant, confirm=TRUE)
list_azure_logins <- function()
{
tenants <- dir(config_dir(), full.names=TRUE)
lst <- lapply(tenants, readRDS)
lst <- lapply(tenants, function(fname)
{
x <- readRDS(fname)
if(is_azure_login(x))
x
else NULL
})
names(lst) <- basename(tenants)
lst
lst[!sapply(lst, is.null)]
}

8
R/is.R
Просмотреть файл

@ -6,6 +6,14 @@
#'
#' @return
#' A boolean.
#' @rdname is
#' @export
is_azure_login <- function(object)
{
R6::is.R6(object) && inherits(object, "az_rm")
}
#' @rdname is
#' @export
is_subscription <- function(object)

96
R/normalize.R Normal file
Просмотреть файл

@ -0,0 +1,96 @@
#' Normalize GUID and tenant values
#'
#' These functions are used by `get_azure_token` to recognise and properly format tenant and app IDs.
#'
#' @param tenant For `normalize_tenant`, a string containing an Azure Active Directory tenant. This can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a valid GUID.
#' @param x For `is_guid`, a character string; for `normalize_guid`, a string containing a _validly formatted_ GUID.
#'
#' @details
#' A tenant can be identified either by a GUID, or its name, or a fully-qualified domain name (FQDN). The rules for normalizing a tenant are:
#' 1. If `tenant` is recognised as a valid GUID, return its canonically formatted value
#' 2. Otherwise, if it is a FQDN, return it
#' 3. Otherwise, if it is not the string "common", append ".onmicrosoft.com" to it
#' 4. Otherwise, return the value of `tenant`
#'
#' See the link below for GUID formats recognised by these functions.
#'
#' @return
#' For `normalize_guid`, the canonically formatted GUID. Note that if `normalize_guid` is given an improperly formatted GUID, its output is undefined; you should always test a string with `is_guid` before passing it to `normalize_guid`.
#'
#' For `normalize_tenant`, the normalized ID or name of the tenant.
#'
#' @seealso
#' [get_azure_token]
#'
#' [Parsing rules for GUIDs in .NET](https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse]). `is_guid` and `normalize_guid` recognise the "N", "D", "B" and "P" formats.
#'
#' @examples
#'
#' is_guid("72f988bf-86f1-41af-91ab-2d7cd011db47") # TRUE
#' is_guid("{72f988bf-86f1-41af-91ab-2d7cd011db47}") # TRUE
#' is_guid("72f988bf-86f1-41af-91ab-2d7cd011db47}") # FALSE (unmatched brace)
#' is_guid("microsoft") # FALSE
#'
#' # all of these return the same value
#' normalize_guid("72f988bf-86f1-41af-91ab-2d7cd011db47")
#' normalize_guid("{72f988bf-86f1-41af-91ab-2d7cd011db47}")
#' normalize_guid("(72f988bf-86f1-41af-91ab-2d7cd011db47)")
#' normalize_guid("72f988bf86f141af91ab2d7cd011db47")
#'
#' normalize_tenant("microsoft") # returns 'microsoft.onmicrosoft.com'
#' normalize_tenant("microsoft.com") # returns 'microsoft.com'
#' normalize_tenant("72f988bf-86f1-41af-91ab-2d7cd011db47") # returns the GUID
#'
#' @export
#' @rdname guid
normalize_tenant <- function(tenant)
{
# see https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse
# for possible input formats for GUIDs
is_guid <- function(x)
{
grepl("^[0-9a-f]{32}$", x) ||
grepl("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", x) ||
grepl("^\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}$", x) ||
grepl("^\\([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\)$", x)
}
# check if supplied a guid; if not, check if a fqdn;
# if not, check if 'common'; if not, append '.onmicrosoft.com'
if(is_guid(tenant))
{
tenant <- sub("^[({]?([-0-9a-f]+)[})]$", "\\1", tenant)
tenant <- gsub("-", "", tenant)
return(normalize_guid(tenant))
}
if(!grepl("\\.", tenant) && tenant != "common")
tenant <- paste(tenant, "onmicrosoft.com", sep=".")
tenant
}
#' @export
#' @rdname guid
normalize_guid <- function(x)
{
x <- sub("^[({]?([-0-9a-f]+)[})]$", "\\1", x)
x <- gsub("-", "", x)
return(paste(
substr(x, 1, 8),
substr(x, 9, 12),
substr(x, 13, 16),
substr(x, 17, 20),
substr(x, 21, 32), sep="-"))
}
#' @export
#' @rdname guid
is_guid <- function(x)
{
grepl("^[0-9a-f]{32}$", x) ||
grepl("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", x) ||
grepl("^\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}$", x) ||
grepl("^\\([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\)$", x)
}

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

@ -21,7 +21,7 @@ Azure OAuth 2.0 token class, inheriting from the \link[httr:Token2.0]{Token2.0 c
\section{Caching}{
This class never caches its tokens, unlike httr::Token2.0.
Unlike httr::Token2.0, caching for Azure tokens is handled outside the class. Tokens are automatically cached by the \code{get_azure_token} function, and can be (manually) deleted with the \code{delete_azure_token} function. Calling \code{AzureToken$new()} directly will always acquire a new token from the server.
}
\seealso{

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

@ -2,11 +2,20 @@
% Please edit documentation in R/AzureToken.R
\name{get_azure_token}
\alias{get_azure_token}
\title{Generate an Azure OAuth token}
\alias{delete_azure_token}
\alias{list_azure_tokens}
\title{Manage Azure Active Directory OAuth 2.0 tokens}
\usage{
get_azure_token(resource_host, tenant, app, password = NULL,
username = NULL, auth_type = NULL,
aad_host = "https://login.microsoftonline.com/")
delete_azure_token(resource_host, tenant, app, password = NULL,
username = NULL, auth_type = NULL,
aad_host = "https://login.microsoftonline.com/", hash = NULL,
confirm = TRUE)
list_azure_tokens()
}
\arguments{
\item{resource_host}{URL for your resource host. For Resource Manager in the public Azure cloud, this is \code{https://management.azure.com/}.}
@ -22,15 +31,21 @@ get_azure_token(resource_host, tenant, app, password = NULL,
\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/}.}
\item{hash}{The MD5 hash of this token, computed from the above inputs. Used by \code{delete_azure_token} for identification purposes.}
\item{confirm}{For \code{delete_azure_token}, whether to prompt for confirmation before deleting a token.}
}
\description{
This extends the OAuth functionality in httr for use with Azure Active Directory (AAD).
These functions extend the OAuth functionality in httr for use with Azure Active Directory (AAD).
}
\details{
This function does much the same thing as \code{\link[httr:oauth2.0_token]{httr::oauth2.0_token()}}, but customised for Azure.
\code{get_azure_token} does much the same thing as \code{\link[httr:oauth2.0_token]{httr::oauth2.0_token()}}, but customised for Azure. It obtains an OAuth token, first by checking if a cached value exists on disk, and if not, acquiring it from the AAD server. \code{delete_azure_token} deletes a cached token, and \code{list_azure_tokens} lists currently cached tokens.
}
\section{Authentication methods}{
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. Here is a short description of these methods.
\itemize{
\enumerate{
\item Using the authorization_code method is a 3-step process. First, \code{get_azure_token} contacts the AAD authorization endpoint to obtain a temporary access code. It then contacts the AAD access endpoint, passing it the code. The access endpoint sends back a login URL which \code{get_azure_token} opens in your browser, where you can enter your credentials. Once this is completed, the endpoint returns the OAuth token via a HTTP redirect URI.
\item The device_code method is similar in concept to authorization_code, but is meant for situations where you are unable to browse the Internet -- for example if you don't have a browser installed or your computer has input constraints. First, \code{get_azure_token} contacts the AAD devicecode endpoint, which responds with a login URL and an access code. You then visit the URL and enter the code, possibly using a different computer. Meanwhile, \code{get_azure_token} polls the AAD access endpoint for a token, which is provided once you have successfully entered the code.
\item The client_credentials method is much simpler than the above methods, requiring only one step. \code{get_azure_token} contacts the access endpoint, passing it the app secret (which you supplied in the \code{password} argument). Assuming the secret is valid, the endpoint then returns the OAuth token.
@ -49,6 +64,25 @@ The httpuv package must be installed to use the authorization_code method, as th
Similarly, since the authorization_code method opens a browser to load the AAD authorization page, your machine must 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.
}
\section{Caching}{
AzureRMR differs from httr in its handling of token caching in a number of ways.
\itemize{
\item It moves caching of OAuth tokens out of the token class, and into the \code{get_azure_token} function. Caching is based on all the inputs to \code{get_azure_token} as listed above. Directly calling the AzureToken class constructor will always acquire a new token from the server.
\item It defines its own directory for caching tokens, using the rappdirs package. On recent Windows versions, this will usually be in the location \code{C:\\Users\\(username)\\AppData\\Local\\AzureR\\AzureRMR}. On Linux, it will be in \code{~/.config/AzureRMR}, and on MacOS, it will be in \code{~/Library/Application Support/AzureRMR}. Note that a single directory is used for all tokens, unlike httr, and the working directory is not touched (which lessens the risk of accidentally introducing cached tokens into source control).
}
To list all cached tokens on disk, use \code{list_azure_tokens}. This returns a list of token objects, named according to their MD5 hashes.
To delete a cached token, use \code{delete_azure_token}. This takes the same inputs as \code{get_azure_token}, or you can specify the MD5 hash directly in the \code{hash} argument.
}
\section{Value}{
For \code{get_azure_token}, an object of class \code{AzureToken} representing the AAD token. For \code{list_azure_tokens}, a list of such objects retrieved from disk.
}
\examples{
\dontrun{
@ -84,9 +118,24 @@ storage_token <- get_azure_token(
owner_token <- get_azure_token(
resource_host="https://myresource/",
tenant="myaadtenant",
app="app_id",
username="user",
password="abcdefg")
# list saved tokens
list_azure_tokens()
# delete a saved token from disk
delete_azure_token(
resource_host="https://myresource/",
tenant="myaadtenant",
app="app_id",
username="user",
password="abcdefg")
# delete a saved token by specifying its MD5 hash
delete_azure_token(hash="7ea491716e5b10a77a673106f3f53bfd")
}
}
\seealso{

61
man/guid.Rd Normal file
Просмотреть файл

@ -0,0 +1,61 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/normalize.R
\name{normalize_tenant}
\alias{normalize_tenant}
\alias{normalize_guid}
\alias{is_guid}
\title{Normalize GUID and tenant values}
\usage{
normalize_tenant(tenant)
normalize_guid(x)
is_guid(x)
}
\arguments{
\item{tenant}{For \code{normalize_tenant}, a string containing an Azure Active Directory tenant. This can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a valid GUID.}
\item{x}{For \code{is_guid}, a character string; for \code{normalize_guid}, a string containing a \emph{validly formatted} GUID.}
}
\value{
For \code{normalize_guid}, the canonically formatted GUID. Note that if \code{normalize_guid} is given an improperly formatted GUID, its output is undefined; you should always test a string with \code{is_guid} before passing it to \code{normalize_guid}.
For \code{normalize_tenant}, the normalized ID or name of the tenant.
}
\description{
These functions are used by \code{get_azure_token} to recognise and properly format tenant and app IDs.
}
\details{
A tenant can be identified either by a GUID, or its name, or a fully-qualified domain name (FQDN). The rules for normalizing a tenant are:
\enumerate{
\item If \code{tenant} is recognised as a valid GUID, return its canonically formatted value
\item Otherwise, if it is a FQDN, return it
\item Otherwise, if it is not the string "common", append ".onmicrosoft.com" to it
\item Otherwise, return the value of \code{tenant}
}
See the link below for GUID formats recognised by these functions.
}
\examples{
is_guid("72f988bf-86f1-41af-91ab-2d7cd011db47") # TRUE
is_guid("{72f988bf-86f1-41af-91ab-2d7cd011db47}") # TRUE
is_guid("72f988bf-86f1-41af-91ab-2d7cd011db47}") # FALSE (unmatched brace)
is_guid("microsoft") # FALSE
# all of these return the same value
normalize_guid("72f988bf-86f1-41af-91ab-2d7cd011db47")
normalize_guid("{72f988bf-86f1-41af-91ab-2d7cd011db47}")
normalize_guid("(72f988bf-86f1-41af-91ab-2d7cd011db47)")
normalize_guid("72f988bf86f141af91ab2d7cd011db47")
normalize_tenant("microsoft") # returns 'microsoft.onmicrosoft.com'
normalize_tenant("microsoft.com") # returns 'microsoft.com'
normalize_tenant("72f988bf-86f1-41af-91ab-2d7cd011db47") # returns the GUID
}
\seealso{
\link{get_azure_token}
\href{https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse]}{Parsing rules for GUIDs in .NET}. \code{is_guid} and \code{normalize_guid} recognise the "N", "D", "B" and "P" formats.
}

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

@ -1,6 +1,7 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/is.R
\name{is_subscription}
\name{is_azure_login}
\alias{is_azure_login}
\alias{is_subscription}
\alias{is_resource_group}
\alias{is_resource}
@ -8,6 +9,8 @@
\alias{is_azure_token}
\title{Informational functions}
\usage{
is_azure_login(object)
is_subscription(object)
is_resource_group(object)

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

@ -1,31 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/AzureToken.R
\name{normalize_tenant}
\alias{normalize_tenant}
\title{Normalizes a tenant}
\usage{
normalize_tenant(tenant)
}
\arguments{
\item{tenant}{An Azure Active Directory tenant. This can be a name ("myaadtenant"), a fully qualified domain name ("myaadtenant.onmicrosoft.com" or "mycompanyname.com"), or a valid GUID.}
}
\value{
The normalized ID or name of the tenant.
}
\description{
Normalizes a tenant
}
\details{
This function is used by \code{get_azure_token} to recognise a tenant input. A tenant can be identified either by a GUID, or its name, or a fully-qualified domain name (FQDN). The rules for normalizing a tenant are:
\enumerate{
\item If \code{tenant} is a valid GUID, return its canonically formatted value
\item Otherwise, if it is a FQDN, return it
\item Otherwise, if it is not the string "common", append ".onmicrosoft.com" to it
\item Otherwise, return the value of \code{tenant}
}
}
\seealso{
\link{get_azure_token},
\href{https://docs.microsoft.com/en-us/dotnet/api/system.guid.parse]}{Parsing rules for GUIDs in .NET}. \code{normalize_tenant} recognises the "N", "D", "B" and "P" formats for GUIDs.
}

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

@ -0,0 +1,43 @@
context("AzureToken")
tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
app <- Sys.getenv("AZ_TEST_APP_ID")
password <- Sys.getenv("AZ_TEST_PASSWORD")
subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
if(tenant == "" || app == "" || password == "" || subscription == "")
skip("Authentication tests skipped: ARM credentials not set")
test_that("normalize_tenant, normalize_guid work",
{
guid <- "abcdefab-1234-5678-9012-abcdefabcdef"
expect_identical(normalize_guid(guid), guid)
guid2 <- paste0("{", guid, "}")
expect_identical(normalize_guid(guid2), guid)
guid3 <- paste0("(", guid, ")")
expect_identical(normalize_guid(guid3), guid)
guid4 <- sub("-", "", guid, fixed=TRUE)
expect_identical(normalize_guid(guid4), guid)
# improperly formatted GUID will be treated as a name
guid5 <- paste0("(", guid)
expect_identical(normalize_tenant(guid5), paste0(guid5, ".onmicrosoft.com"))
expect_identical(normalize_tenant("common"), "common")
expect_identical(normalize_tenant("mytenant"), "mytenant.onmicrosoft.com")
expect_identical(normalize_tenant("mytenant.com"), "mytenant.com")
})
test_that("Authentication works",
{
suppressWarnings(delete_azure_token("http://management.azure.com/", tenant, app, password, confirm=FALSE))
token <- get_azure_token("http://management.azure.com/", tenant, app, password)
expect_true(is_azure_token(token))
toklist <- list_azure_tokens()
expect_true(length(toklist) > 0)
expect_null(delete_azure_token("http://management.azure.com/", tenant, app, password, confirm=FALSE))
})