Allow changing domain on a credential and listing of all tenants (#91)

This commit is contained in:
Daniel Rodríguez 2020-06-16 12:55:58 -04:00 коммит произвёл GitHub
Родитель 0fe59073c6
Коммит 029767b92f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 148 добавлений и 56 удалений

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

@ -2,9 +2,16 @@
## 3.0.5 - (unreleased)
- The helper method `buildTenantList` is made public. This is helpful if one needs to get the Ids of all the tenants in the account programmatically.
- A new method `setDomain()` which takes the Id of a tenant is now available on all credentials. Use this to change the domain i.e. the tenant against which tokens are created.
- Fixed typos in error messages.
- Added support for passing a `clientId` property in the `options` parameter of the MSI based login method `loginWithAppServiceMSI()`. This is required to allow user-assigned managed identities to be used to authenticate through Azure App Services and Azure Functions.
- Added support for the `IDENTITY_ENDPOINT` and `IDENTITY_SECRET` when using the `MSIAppServiceTokenCredentials` credentials.
## 3.0.4 - 2020/05/19 (deprecated)
- Through a mistake of release automation, a CI job from PR #91 got shipped by accident.
## 3.0.2 - 2019/08/22
- Fixed a bug where the callback to `loginWithServicePrincipalSecretWithAuthResponse` is sometimes not called.
@ -24,7 +31,7 @@
## 2.0.3 - 2019/07/23
- Updated min version of dependency `@azure/ms-rest-js` to `^2.0.3`.
- Updated min version of dependenct `@azure/ms-rest-azure-env` to `^2.0.0`.
- Updated min version of dependency `@azure/ms-rest-azure-env` to `^2.0.0`.
- Improved documentation of `MSIOptions.resource`
- Improved samples in README.md

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

@ -1,8 +1,20 @@
# ms-rest-nodeauth [![Build Status](https://dev.azure.com/azure-public/adx/_apis/build/status/public.Azure.ms-rest-nodeauth)](https://dev.azure.com/azure-public/adx/_build/latest?definitionId=9)
This library provides different node.js based authentication mechanisms for services in Azure. It also contains rich type definitions thereby providing a good TypeScript experience.
All the authentication methods support callbacks as well as promises. If they are called within an async method in your application then you can use the async/await pattern as well.
**Things to consider when using personal accounts:**
When using personal accounts, the `domain` property in the options passed to the authentication methods is mandatory and should be set to the tenant Id. If this property is not set, the credentials created by the authentication methods will not be able to access any of the resources of the personal account. For that same reason, the list of subscriptions expected in the return value of these methods will be empty.
You can get the tenant Id from Azure portal or the Azure CLI. If you need to fetch the tenant Id programmatically, follow the below steps:
- Use any of the authentication methods without setting the domain to get a credential.
- Call the `buildTenantLists(credential)` method by sending that same credential as the first parameter to get the list of all tenants in your account.
You can now use any of the authentication methods and pass in the tenant Id or use the `setDomain()` method on the existing credential to change the tenant it uses to create the tokens.
### Example
### username/password based login
@ -203,7 +215,7 @@ async function main(): Promise<void> {
const subscriptions = await AzureCliCredentials.listAllSubscriptions();
creds.subscriptionInfo = subscriptions[1];
console.log(">>> The new subscription id associated with the credential object is: '%s'.",
console.log(">>> The new subscription Id associated with the credential object is: '%s'.",
creds.subscriptionInfo.id);
request.url = getUrl(creds.subscriptionInfo.id);
console.log(">>> Request url: '%s'.", request.url);

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

@ -116,7 +116,7 @@ export abstract class MSITokenCredentials implements TokenClientCredentials {
if (typeof parsedBody["expires_on"] === "string") {
// possibly a Date string '09/14/2017 00:00:00 PM +00:00'
if (parsedBody["expires_on"].includes(":") || parsedBody["expires_on"].includes("/")) {
parsedBody.expiresOn = new Date(parsedBody["expires_on"], 10);
parsedBody.expiresOn = new Date(parseInt(parsedBody["expires_on"], 10));
} else {
// normal number as a string '1504130527'
parsedBody.expiresOn = new Date(parseInt(parsedBody["expires_on"], 10));

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

@ -8,15 +8,15 @@ import { TokenClientCredentials } from "./tokenClientCredentials";
import { TokenResponse, AuthenticationContext, MemoryCache, ErrorResponse, TokenCache } from "adal-node";
export abstract class TokenCredentialsBase implements TokenClientCredentials {
public readonly authContext: AuthenticationContext;
public authContext: AuthenticationContext;
public constructor(
public readonly clientId: string,
public domain: string,
public readonly tokenAudience?: TokenAudience,
public readonly environment: Environment = Environment.AzureCloud,
public tokenCache: TokenCache = new MemoryCache()) {
public tokenCache: TokenCache = new MemoryCache()
) {
if (!clientId || typeof clientId.valueOf() !== "string") {
throw new Error("clientId must be a non empty string.");
}
@ -26,14 +26,20 @@ export abstract class TokenCredentialsBase implements TokenClientCredentials {
}
if (this.tokenAudience === "graph" && this.domain.toLowerCase() === "common") {
throw new Error(`${"If the tokenAudience is specified as \"graph\" then \"domain\" cannot be defaulted to \"commmon\" tenant.\
It must be the actual tenant (preferrably a string in a guid format)."}`);
throw new Error(`${"If the tokenAudience is specified as \"graph\" then \"domain\" cannot be defaulted to \"common\" tenant.\
It must be the actual tenant (preferably a string in a guid format)."}`);
}
const authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
this.authContext = new AuthenticationContext(authorityUrl, this.environment.validateAuthority, this.tokenCache);
}
public setDomain(domain: string): void {
this.domain = domain;
const authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
this.authContext = new AuthenticationContext(authorityUrl, this.environment.validateAuthority, this.tokenCache);
}
protected getActiveDirectoryResourceId(): string {
let resource = this.environment.activeDirectoryResourceId;
if (this.tokenAudience) {

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

@ -22,7 +22,7 @@ export class UserTokenCredentials extends TokenCredentialsBase {
* @param {string} username The user name for the Organization Id account.
* @param {string} password The password for the Organization Id account.
* @param {string} [tokenAudience] The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
* @param {Environment} [environment] The azure environment to authenticate with.
* @param {object} [tokenCache] The token cache. Default value is the MemoryCache object from adal.
*/
@ -91,7 +91,7 @@ export class UserTokenCredentials extends TokenCredentialsBase {
if (self.crossCheckUserNameWithToken(self.username, tokenResponse.userId!)) {
return resolve((tokenResponse as TokenResponse));
} else {
return reject(`The userId "${tokenResponse.userId}" in access token doesn"t match the username "${self.username}" provided during authentication.`);
return reject(`The userId "${tokenResponse.userId}" in access token doesn't match the username "${self.username}" provided during authentication.`);
}
});
});

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

@ -54,12 +54,12 @@ if (process.env["AZURE_ADAL_LOGGING_ENABLED"]) {
}
/**
* @interface AzureTokenCredentialsOptions - Describes optional parameters for serviceprincipal/secret authentication.
* @interface AzureTokenCredentialsOptions - Describes optional parameters for servicePrincipal/secret authentication.
*/
export interface AzureTokenCredentialsOptions {
/**
* @property {TokenAudience} [tokenAudience] - The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
*/
tokenAudience?: TokenAudience;
/**
@ -83,7 +83,7 @@ export interface LoginWithUsernamePasswordOptions extends AzureTokenCredentialsO
*/
clientId?: string;
/**
* @property {string} [domain] - The domain or tenant id containing this application. Default value is "common".
* @property {string} [domain] - The domain or tenant Id containing this application. Default value is "common".
*/
domain?: string;
}
@ -112,7 +112,7 @@ export interface AuthResponse {
*/
credentials: TokenCredentialsBase;
/**
* @property {Array<LinkedSubscription>} [subscriptions] List of associated subscriptions.
* @property {Array<LinkedSubscription>} [subscriptions] List of associated subscriptions. It will be empty for personal accounts, unless the login method is called with a tenant Id sent as the `domain` optional parameter.
*/
subscriptions?: LinkedSubscription[];
}
@ -144,6 +144,8 @@ export type Callback<TResult> = (error?: Error, result?: TResult) => void;
* Provides a UserTokenCredentials object and the list of subscriptions associated with that userId across all the applicable tenants.
* This method is applicable only for organizational ids that are not 2FA enabled otherwise please use interactive login.
*
* When using personal accounts, the `domain` property in the `options` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {string} username The user name for the Organization Id account.
* @param {string} password The password for the Organization Id account.
* @param {object} [options] Object representing optional parameters.
@ -151,12 +153,12 @@ export type Callback<TResult> = (error?: Error, result?: TResult) => void;
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* @param {string} [options.domain] The domain or tenant id containing this application. Default value "common".
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
* @param {string} [options.domain] The domain or tenant Id containing this application. Default value "common".
* @param {Environment} [options.environment] The azure environment to authenticate with.
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
*
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse that contains "credentials" and optional "subscriptions" array and rejects with an Error.
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse, which contains `credentials` and an optional `subscriptions` array, and rejects with an Error.
*/
export async function withUsernamePasswordWithAuthResponse(username: string, password: string, options?: LoginWithUsernamePasswordOptions): Promise<AuthResponse> {
if (!options) {
@ -175,7 +177,7 @@ export async function withUsernamePasswordWithAuthResponse(username: string, pas
const creds = new UserTokenCredentials(options.clientId, options.domain, username, password, options.tokenAudience, options.environment);
await creds.getToken();
// The token cache gets propulated for all the tenants as a part of building the tenantList.
// The token cache gets populated for all the tenants as a part of building the tenantList.
const tenantList = await buildTenantList(creds);
const subscriptionList: LinkedSubscription[] = await _getSubscriptions(creds, tenantList, options.tokenAudience);
@ -183,20 +185,22 @@ export async function withUsernamePasswordWithAuthResponse(username: string, pas
}
/**
* Provides an ApplicationTokenCredentials object and the list of subscriptions associated with that servicePrinicpalId/clientId across all the applicable tenants.
* Provides an ApplicationTokenCredentials object and the list of subscriptions associated with that servicePrincipalId/clientId across all the applicable tenants.
*
* @param {string} clientId The active directory application client id also known as the SPN (ServicePrincipal Name).
* When using personal accounts, the `domain` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {string} clientId The active directory application client Id also known as the SPN (ServicePrincipal Name).
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
* @param {string} secret The application secret for the service principal.
* @param {string} domain The domain or tenant id containing this application.
* @param {string} domain The domain or tenant Id containing this application.
* @param {object} [options] Object representing optional parameters.
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
* @param {Environment} [options.environment] The azure environment to authenticate with.
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
*
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse that contains "credentials" and optional "subscriptions" array and rejects with an Error.
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse, which contains "credentials" and optional "subscriptions" array and rejects with an Error.
*/
export async function withServicePrincipalSecretWithAuthResponse(clientId: string, secret: string, domain: string, options?: AzureTokenCredentialsOptions): Promise<AuthResponse> {
if (!options) {
@ -215,22 +219,24 @@ export async function withServicePrincipalSecretWithAuthResponse(clientId: strin
}
/**
* Provides an ApplicationTokenCertificateCredentials object and the list of subscriptions associated with that servicePrinicpalId/clientId across all the applicable tenants.
* Provides an ApplicationTokenCertificateCredentials object and the list of subscriptions associated with that servicePrincipalId/clientId across all the applicable tenants.
*
* @param {string} clientId The active directory application client id also known as the SPN (ServicePrincipal Name).
* When using personal accounts, the `domain` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {string} clientId The active directory application client Id also known as the SPN (ServicePrincipal Name).
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
* @param {string} certificateStringOrFilePath A PEM encoded certificate and private key OR an absolute filepath to the .pem file containing that information. For example:
* - CertificateString: "-----BEGIN PRIVATE KEY-----\n<xxxxx>\n-----END PRIVATE KEY-----\n-----BEGIN CERTIFICATE-----\n<yyyyy>\n-----END CERTIFICATE-----\n"
* - CertificateFilePath: **Absolute** file path of the .pem file.
* @param {string} domain The domain or tenant id containing this application.
* @param {string} domain The domain or tenant Id containing this application.
* @param {object} [options] Object representing optional parameters.
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
* @param {Environment} [options.environment] The azure environment to authenticate with.
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
*
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse that contains "credentials" and optional "subscriptions" array and rejects with an Error.
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse, which contains "credentials" and optional "subscriptions" array and rejects with an Error.
*/
export async function withServicePrincipalCertificateWithAuthResponse(clientId: string, certificateStringOrFilePath: string, domain: string, options?: AzureTokenCredentialsOptions): Promise<AuthResponse> {
if (!options) {
@ -318,7 +324,7 @@ function foundManagementEndpointUrl(authFileUrl: string, envUrl: string): boolea
* name. Default is "AZURE_SUBSCRIPTION_ID".
* @param {function} [optionalCallback] The optional callback.
*
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse that contains "credentials" and optional "subscriptions" array and rejects with an Error.
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse, which contains "credentials" and optional "subscriptions" array and rejects with an Error.
*/
export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOptions): Promise<AuthResponse> {
if (!options) options = { filePath: "" };
@ -391,8 +397,9 @@ export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOp
/**
* Provides a url and code that needs to be copy and pasted in a browser and authenticated over there. If successful, the user will get a
* DeviceTokenCredentials object and the list of subscriptions associated with that userId across all the applicable tenants.
* Provides a url and code that needs to be copy and pasted in a browser and authenticated over there. If successful, the user will get a DeviceTokenCredentials object and the list of subscriptions associated with that userId across all the applicable tenants.
*
* When using personal accounts, the `domain` property in the `options` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {object} [options] Object representing optional parameters.
*
@ -401,9 +408,9 @@ export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOp
* for an example.
*
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid value is "graph".If tokenAudience is provided
* then domain should also be provided its value should not be the default "common" tenant. It must be a string (preferrably in a guid format).
* then domain should also be provided its value should not be the default "common" tenant. It must be a string (preferably in a guid format).
*
* @param {string} [options.domain] The domain or tenant id containing this application. Default value is "common".
* @param {string} [options.domain] The domain or tenant Id containing this application. Default value is "common".
*
* @param {Environment} [options.environment] The azure environment to authenticate with. Default environment is "Public Azure".
*
@ -416,7 +423,7 @@ export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOp
*
* @param {function} [optionalCallback] The optional callback.
*
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse that contains "credentials" and optional "subscriptions" array and rejects with an Error.
* @returns {Promise<AuthResponse>} A Promise that resolves to AuthResponse, which contains "credentials" and optional "subscriptions" array and rejects with an Error.
*/
export async function withInteractiveWithAuthResponse(options?: InteractiveLoginOptions): Promise<AuthResponse> {
if (!options) {
@ -572,16 +579,17 @@ export function withAuthFile(options?: LoginWithAuthFileOptions, callback?: { (e
}
/**
* Provides a url and code that needs to be copy and pasted in a browser and authenticated over there. If successful, the user will get a
* DeviceTokenCredentials object and the list of subscriptions associated with that userId across all the applicable tenants.
* Provides a url and code that needs to be copy and pasted in a browser and authenticated over there. If successful, the user will get a DeviceTokenCredentials object and the list of subscriptions associated with that userId across all the applicable tenants.
*
* When using personal accounts, the `domain` property in the `options` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {object} [options] Object representing optional parameters.
* @param {string} [options.clientId] The active directory application client id.
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid value is "graph".If tokenAudience is provided
* then domain should also be provided its value should not be the default "common" tenant. It must be a string (preferrably in a guid format).
* @param {string} [options.domain] The domain or tenant id containing this application. Default value is "common".
* then domain should also be provided its value should not be the default "common" tenant. It must be a string (preferably in a guid format).
* @param {string} [options.domain] The domain or tenant Id containing this application. Default value is "common".
* @param {Environment} [options.environment] The azure environment to authenticate with. Default environment is "Public Azure".
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
* @param {object} [options.language] The language code specifying how the message should be localized to. Default value "en-us".
@ -592,9 +600,9 @@ export function withAuthFile(options?: LoginWithAuthFileOptions, callback?: { (e
* @returns {function | Promise} If a callback was passed as the last parameter then it returns the callback else returns a Promise.
*
* {function} optionalCallback(err, credentials)
* {Error} [err] - The Error object if an error occurred, null otherwise.
* {DeviceTokenCredentials} [credentials] - The DeviceTokenCredentials object.
* {Array} [subscriptions] - List of associated subscriptions across all the applicable tenants.
* {Error} [err] - The Error object if an error occurred, null otherwise.
* {DeviceTokenCredentials} [credentials] - The DeviceTokenCredentials object.
* {Array} [subscriptions] - List of associated subscriptions across all the applicable tenants.
* {Promise} A promise is returned.
* @resolve {DeviceTokenCredentials} The DeviceTokenCredentials object.
* @reject {Error} - The error object.
@ -624,16 +632,18 @@ export function interactive(options?: InteractiveLoginOptions, callback?: { (err
}
/**
* Provides an ApplicationTokenCredentials object and the list of subscriptions associated with that servicePrinicpalId/clientId across all the applicable tenants.
* Provides an ApplicationTokenCredentials object and the list of subscriptions associated with that servicePrincipalId/clientId across all the applicable tenants.
*
* @param {string} clientId The active directory application client id also known as the SPN (ServicePrincipal Name).
* When using personal accounts, the `domain` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {string} clientId The active directory application client Id also known as the SPN (ServicePrincipal Name).
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
* @param {string} secret The application secret for the service principal.
* @param {string} domain The domain or tenant id containing this application.
* @param {string} domain The domain or tenant Id containing this application.
* @param {object} [options] Object representing optional parameters.
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
* @param {Environment} [options.environment] The azure environment to authenticate with.
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
* @param {function} [optionalCallback] The optional callback.
@ -641,9 +651,9 @@ export function interactive(options?: InteractiveLoginOptions, callback?: { (err
* @returns {function | Promise} If a callback was passed as the last parameter then it returns the callback else returns a Promise.
*
* {function} optionalCallback(err, credentials)
* {Error} [err] - The Error object if an error occurred, null otherwise.
* {Error} [err] - The Error object if an error occurred, null otherwise.
* {ApplicationTokenCredentials} [credentials] - The ApplicationTokenCredentials object.
* {Array} [subscriptions] - List of associated subscriptions across all the applicable tenants.
* {Array} [subscriptions] - List of associated subscriptions across all the applicable tenants.
* {Promise} A promise is returned.
* @resolve {ApplicationTokenCredentials} The ApplicationTokenCredentials object.
* @reject {Error} - The error object.
@ -673,18 +683,20 @@ export function withServicePrincipalSecret(clientId: string, secret: string, dom
}
/**
* Provides an ApplicationTokenCertificateCredentials object and the list of subscriptions associated with that servicePrinicpalId/clientId across all the applicable tenants.
* Provides an ApplicationTokenCertificateCredentials object and the list of subscriptions associated with that servicePrincipalId/clientId across all the applicable tenants.
*
* @param {string} clientId The active directory application client id also known as the SPN (ServicePrincipal Name).
* When using personal accounts, the `domain` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {string} clientId The active directory application client Id also known as the SPN (ServicePrincipal Name).
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
* @param {string} certificateStringOrFilePath A PEM encoded certificate and private key OR an absolute filepath to the .pem file containing that information. For example:
* - CertificateString: "-----BEGIN PRIVATE KEY-----\n<xxxxx>\n-----END PRIVATE KEY-----\n-----BEGIN CERTIFICATE-----\n<yyyyy>\n-----END CERTIFICATE-----\n"
* - CertificateFilePath: **Absolute** file path of the .pem file.
* @param {string} domain The domain or tenant id containing this application.
* @param {string} domain The domain or tenant Id containing this application.
* @param {object} [options] Object representing optional parameters.
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
* @param {Environment} [options.environment] The azure environment to authenticate with.
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
* @param {function} [optionalCallback] The optional callback.
@ -725,8 +737,11 @@ export function withServicePrincipalCertificate(clientId: string, certificateStr
/**
* Provides a UserTokenCredentials object and the list of subscriptions associated with that userId across all the applicable tenants.
*
* This method is applicable only for organizational ids that are not 2FA enabled otherwise please use interactive login.
*
* When using personal accounts, the `domain` property in the `options` parameter is required to be set to the Id of a tenant for that account. Otherwise, the resulting credential will not be able to access the account's resources.
*
* @param {string} username The user name for the Organization Id account.
* @param {string} password The password for the Organization Id account.
* @param {object} [options] Object representing optional parameters.
@ -734,8 +749,8 @@ export function withServicePrincipalCertificate(clientId: string, certificateStr
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
* @param {string} [options.tokenAudience] The audience for which the token is requested. Valid values are 'graph', 'batch', or any other resource like 'https://vault.azure.net/'.
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferrably in a guid format).
* @param {string} [options.domain] The domain or tenant id containing this application. Default value "common".
* If tokenAudience is 'graph' then domain should also be provided and its value should not be the default 'common' tenant. It must be a string (preferably in a guid format).
* @param {string} [options.domain] The domain or tenant Id containing this application. Default value "common".
* @param {Environment} [options.environment] The azure environment to authenticate with.
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
* @param {function} [optionalCallback] The optional callback.
@ -940,7 +955,7 @@ export async function execAz(cmd: string): Promise<any> {
try {
return resolve(JSON.parse(stdout));
} catch (err) {
const msg = `An error occured while parsing the output "${stdout}", of ` +
const msg = `An error occurred while parsing the output "${stdout}", of ` +
`the cmd "${cmd}": ${err.stack}.`;
return reject(new Error(msg));
}

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

@ -11,7 +11,7 @@ export { MSIVmOptions, MSIVmTokenCredentials } from "./credentials/msiVmTokenCre
export { TokenCredentialsBase } from "./credentials/tokenCredentialsBase";
export { UserTokenCredentials } from "./credentials/userTokenCredentials";
export { AuthConstants, TokenAudience } from "./util/authConstants";
export { LinkedSubscription, LinkedUser, UserType } from "./subscriptionManagement/subscriptionUtils";
export { LinkedSubscription, LinkedUser, UserType, buildTenantList } from "./subscriptionManagement/subscriptionUtils";
export {
AzureCliCredentials,
CliAccessToken,

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

@ -5,7 +5,7 @@
"email": "azsdkteam@microsoft.com",
"url": "https://github.com/Azure/ms-rest-nodeauth"
},
"version": "3.0.3",
"version": "3.0.5",
"description": "Azure Authentication library in node.js with type definitions.",
"keywords": [
"node",
@ -34,6 +34,7 @@
},
"license": "MIT",
"devDependencies": {
"@azure/arm-subscriptions": "^2.0.0",
"@ts-common/azure-js-dev-tools": "^22.2.0",
"@types/chai": "^4.1.7",
"@types/dotenv": "^6.1.1",

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

@ -0,0 +1,51 @@
/**
* When using personal accounts, the `domain` property in the options passed to the authentication methods is mandatory and should be set to the tenant Id. If this property is not set, the credentials created by the authentication methods will not be able to access any of the resources of the personal account. For that same reason, the list of subscriptions expected in the return value of these methods will be empty.
*
* You can get the tenant Id from Azure portal or the Azure CLI. If you need to fetch the tenant Id programmatically, you can use the helper method `buildTenantList(credential)`.
*
* This sample shows how the authentication fails for personal accounts when `domain` is not set, and how to overcome this issue.
*
* For more context: https://github.com/Azure/ms-rest-nodeauth/issues/89#issuecomment-643471343
*/
import * as msRestNodeAuth from "../lib/msRestNodeAuth";
import { SubscriptionClient } from "@azure/arm-subscriptions";
async function main(): Promise<void> {
const authResponse = await msRestNodeAuth.interactiveLoginWithAuthResponse();
// For personal accounts, the line below will print an empty array as we did not set the domain.
console.log("Subscriptions retrieved by default", authResponse.subscriptions);
const client = new SubscriptionClient(authResponse.credentials);
// Note: Replace `<my-subscription>` below with the Id of one of your subscriptions.
const subscriptionId = "<my-subscription>";
// The below request to get the subscription details will fail for personal accounts until we update the domain on the credential.
try {
await client.subscriptions.get(subscriptionId);
} catch (e) {
console.log(`
Expected error:
For personal accounts, we won't be able to retrieve subscriptions unless we specify a domain in the credentials.
${e}
`);
}
// To get the tenants for your account, you can use the buildTenantList method:
const tenants = await msRestNodeAuth.buildTenantList(
authResponse.credentials
);
// Update the domain used by the credentials so that it can generate tokens against a specific tenant.
authResponse.credentials.setDomain(tenants[0]);
// Once the domain is properly set, further requests will work as expected:
const subscription = await client.subscriptions.get(subscriptionId);
console.log(
"After specifying the tenant, we're able to retrieve the full information of our subscriptions:",
subscription
);
}
main();