Add prettier and format code (#120)
This commit is contained in:
Родитель
4c177518c3
Коммит
957a3ee390
|
@ -0,0 +1,2 @@
|
|||
typings/
|
||||
**/*.d.ts
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"arrowParens": "always",
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "lf",
|
||||
"printWidth": 100,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "none"
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
import { checkPackageJsonVersion } from "@ts-common/azure-js-dev-tools";
|
||||
|
||||
process.exitCode = checkPackageJsonVersion({ startPath: __dirname }).check() as number;
|
||||
process.exitCode = checkPackageJsonVersion({ startPath: __dirname }).check() as number;
|
||||
|
|
|
@ -101,19 +101,11 @@ export class ApplicationTokenCertificateCredentials extends ApplicationTokenCred
|
|||
domain: string,
|
||||
options: AzureTokenCredentialsOptions
|
||||
): ApplicationTokenCertificateCredentials {
|
||||
if (
|
||||
!certificateStringOrFilePath ||
|
||||
typeof certificateStringOrFilePath.valueOf() !== "string"
|
||||
) {
|
||||
throw new Error(
|
||||
"'certificateStringOrFilePath' must be a non empty string."
|
||||
);
|
||||
if (!certificateStringOrFilePath || typeof certificateStringOrFilePath.valueOf() !== "string") {
|
||||
throw new Error("'certificateStringOrFilePath' must be a non empty string.");
|
||||
}
|
||||
if (!certificateStringOrFilePath.startsWith("-----BEGIN")) {
|
||||
certificateStringOrFilePath = readFileSync(
|
||||
certificateStringOrFilePath,
|
||||
"utf8"
|
||||
);
|
||||
certificateStringOrFilePath = readFileSync(certificateStringOrFilePath, "utf8");
|
||||
}
|
||||
const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9\+\/\n\r]+\=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/;
|
||||
const matchCert = certificateStringOrFilePath.match(certificatePattern);
|
||||
|
|
|
@ -46,10 +46,7 @@ export class ApplicationTokenCredentials extends ApplicationTokenCredentialsBase
|
|||
try {
|
||||
return await this.getTokenFromCache();
|
||||
} catch (error) {
|
||||
if (
|
||||
error.message &&
|
||||
error.message.startsWith(AuthConstants.SDK_INTERNAL_ERROR)
|
||||
) {
|
||||
if (error.message && error.message.startsWith(AuthConstants.SDK_INTERNAL_ERROR)) {
|
||||
throw error;
|
||||
}
|
||||
const resource = this.getActiveDirectoryResourceId();
|
||||
|
|
|
@ -52,9 +52,9 @@ export abstract class ApplicationTokenCredentialsBase extends TokenCredentialsBa
|
|||
|
||||
throw new Error(
|
||||
AuthConstants.SDK_INTERNAL_ERROR +
|
||||
" : " +
|
||||
"critical failure while removing expired token for service principal from token cache. " +
|
||||
message
|
||||
" : " +
|
||||
"critical failure while removing expired token for service principal from token cache. " +
|
||||
message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ export abstract class ApplicationTokenCredentialsBase extends TokenCredentialsBa
|
|||
query: object
|
||||
): Promise<{ result: boolean; details?: Error }> {
|
||||
const self = this;
|
||||
return new Promise<{ result: boolean; details?: Error }>(resolve => {
|
||||
return new Promise<{ result: boolean; details?: Error }>((resolve) => {
|
||||
self.tokenCache.find(query, (error: Error, entries: any[]) => {
|
||||
if (error) {
|
||||
return resolve({ result: false, details: error });
|
||||
|
|
|
@ -109,7 +109,8 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
subscriptionInfo: LinkedSubscription,
|
||||
tokenInfo: CliAccessToken,
|
||||
// tslint:disable-next-line: no-inferrable-types
|
||||
resource: string = "https://management.azure.com") {
|
||||
resource: string = "https://management.azure.com"
|
||||
) {
|
||||
this.subscriptionInfo = subscriptionInfo;
|
||||
this.tokenInfo = tokenInfo;
|
||||
this.resource = resource;
|
||||
|
@ -124,16 +125,14 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
if (this._hasTokenExpired() || this._hasSubscriptionChanged() || this._hasResourceChanged()) {
|
||||
try {
|
||||
// refresh the access token
|
||||
this.tokenInfo = await AzureCliCredentials.getAccessToken(
|
||||
{
|
||||
subscriptionIdOrName: this.subscriptionInfo.id,
|
||||
resource: this.resource
|
||||
}
|
||||
);
|
||||
this.tokenInfo = await AzureCliCredentials.getAccessToken({
|
||||
subscriptionIdOrName: this.subscriptionInfo.id,
|
||||
resource: this.resource
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`An error occurred while refreshing the new access ` +
|
||||
`token:${err.stderr ? err.stderr : err.message}`
|
||||
`token:${err.stderr ? err.stderr : err.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -162,9 +161,12 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
private _hasTokenExpired(): boolean {
|
||||
let result = true;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
if (this.tokenInfo.expiresOn &&
|
||||
if (
|
||||
this.tokenInfo.expiresOn &&
|
||||
this.tokenInfo.expiresOn instanceof Date &&
|
||||
Math.floor(this.tokenInfo.expiresOn.getTime() / 1000) - now > this._tokenRenewalMarginInSeconds) {
|
||||
Math.floor(this.tokenInfo.expiresOn.getTime() / 1000) - now >
|
||||
this._tokenRenewalMarginInSeconds
|
||||
) {
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
|
@ -178,9 +180,14 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
try {
|
||||
const base64Url: string = this.tokenInfo.accessToken.split(".")[1];
|
||||
const base64: string = decodeURIComponent(
|
||||
Buffer.from(base64Url, "base64").toString("binary").split("").map((c) => {
|
||||
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(""));
|
||||
Buffer.from(base64Url, "base64")
|
||||
.toString("binary")
|
||||
.split("")
|
||||
.map((c) => {
|
||||
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
})
|
||||
.join("")
|
||||
);
|
||||
|
||||
return JSON.parse(base64);
|
||||
} catch (err) {
|
||||
|
@ -192,22 +199,23 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
private _isAzureResourceManagerEndpoint(newResource: string, currentResource: string): boolean {
|
||||
if (newResource.endsWith("/")) newResource = newResource.slice(0, -1);
|
||||
if (currentResource.endsWith("/")) currentResource = currentResource.slice(0, -1);
|
||||
return (newResource === "https://management.core.windows.net" &&
|
||||
currentResource === "https://management.azure.com") ||
|
||||
return (
|
||||
(newResource === "https://management.core.windows.net" &&
|
||||
currentResource === "https://management.azure.com") ||
|
||||
(newResource === "https://management.azure.com" &&
|
||||
currentResource === "https://management.core.windows.net");
|
||||
currentResource === "https://management.core.windows.net")
|
||||
);
|
||||
}
|
||||
|
||||
private _hasResourceChanged(): boolean {
|
||||
const parsedToken: ParsedToken = this._parseToken();
|
||||
// normalize the resource string, since it is possible to
|
||||
// provide a resource without a trailing slash
|
||||
const currentResource = parsedToken.aud && parsedToken.aud.endsWith("/")
|
||||
? parsedToken.aud.slice(0, -1)
|
||||
: parsedToken.aud;
|
||||
const newResource = this.resource.endsWith("/")
|
||||
? this.resource.slice(0, -1)
|
||||
: this.resource;
|
||||
const currentResource =
|
||||
parsedToken.aud && parsedToken.aud.endsWith("/")
|
||||
? parsedToken.aud.slice(0, -1)
|
||||
: parsedToken.aud;
|
||||
const newResource = this.resource.endsWith("/") ? this.resource.slice(0, -1) : this.resource;
|
||||
const result = this._isAzureResourceManagerEndpoint(newResource, currentResource)
|
||||
? false
|
||||
: currentResource !== newResource;
|
||||
|
@ -232,8 +240,7 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
return result as CliAccessToken;
|
||||
} catch (err) {
|
||||
const message =
|
||||
`An error occurred while getting credentials from ` +
|
||||
`Azure CLI: ${err.stack}`;
|
||||
`An error occurred while getting credentials from ` + `Azure CLI: ${err.stack}`;
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +251,10 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
* required.
|
||||
*/
|
||||
static async getSubscription(subscriptionIdOrName?: string): Promise<LinkedSubscription> {
|
||||
if (subscriptionIdOrName && (typeof subscriptionIdOrName !== "string" || !subscriptionIdOrName.length)) {
|
||||
if (
|
||||
subscriptionIdOrName &&
|
||||
(typeof subscriptionIdOrName !== "string" || !subscriptionIdOrName.length)
|
||||
) {
|
||||
throw new Error("'subscriptionIdOrName' must be a non-empty string.");
|
||||
}
|
||||
try {
|
||||
|
@ -282,7 +292,9 @@ export class AzureCliCredentials implements TokenClientCredentials {
|
|||
* Returns a list of all the subscriptions from Azure CLI.
|
||||
* @param options Optional parameters that can be provided while listing all the subcriptions.
|
||||
*/
|
||||
static async listAllSubscriptions(options: ListAllSubscriptionOptions = {}): Promise<LinkedSubscription[]> {
|
||||
static async listAllSubscriptions(
|
||||
options: ListAllSubscriptionOptions = {}
|
||||
): Promise<LinkedSubscription[]> {
|
||||
let subscriptionList: any[] = [];
|
||||
try {
|
||||
let cmd = "account list";
|
||||
|
|
|
@ -7,7 +7,6 @@ import { AuthConstants, TokenAudience } from "../util/authConstants";
|
|||
import { TokenResponse, TokenCache } from "adal-node";
|
||||
|
||||
export class DeviceTokenCredentials extends TokenCredentialsBase {
|
||||
|
||||
readonly username: string;
|
||||
|
||||
/**
|
||||
|
@ -34,8 +33,8 @@ export class DeviceTokenCredentials extends TokenCredentialsBase {
|
|||
username?: string,
|
||||
tokenAudience?: TokenAudience,
|
||||
environment?: Environment,
|
||||
tokenCache?: TokenCache) {
|
||||
|
||||
tokenCache?: TokenCache
|
||||
) {
|
||||
if (!username) {
|
||||
username = "user@example.com";
|
||||
}
|
||||
|
@ -57,4 +56,4 @@ export class DeviceTokenCredentials extends TokenCredentialsBase {
|
|||
// For device auth, this is just getTokenFromCache.
|
||||
return this.getTokenFromCache(this.username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,51 +33,83 @@ function _convert(credentials: MSITokenCredentials): MSITokenCredentials {
|
|||
msiEndpoint: credentials.msiEndpoint
|
||||
});
|
||||
} else if (credentials instanceof MSITokenCredentials) {
|
||||
throw new Error("MSI-credentials not one of: MSIVmTokenCredentials, MSIAppServiceTokenCredentials");
|
||||
throw new Error(
|
||||
"MSI-credentials not one of: MSIVmTokenCredentials, MSIAppServiceTokenCredentials"
|
||||
);
|
||||
} else {
|
||||
return credentials;
|
||||
}
|
||||
}
|
||||
|
||||
function _createAuthenticatorMapper(credentials: MSITokenCredentials): Authenticator {
|
||||
return (challenge: any) => new Promise((resolve, reject) => {
|
||||
// Function to take token Response and format a authorization value
|
||||
const _formAuthorizationValue = (err: Error, tokenResponse: TokenResponse | ErrorResponse) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return (challenge: any) =>
|
||||
new Promise((resolve, reject) => {
|
||||
// Function to take token Response and format a authorization value
|
||||
const _formAuthorizationValue = (
|
||||
err: Error,
|
||||
tokenResponse: TokenResponse | ErrorResponse
|
||||
) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
if (tokenResponse.error) {
|
||||
return reject(tokenResponse.error);
|
||||
}
|
||||
if (tokenResponse.error) {
|
||||
return reject(tokenResponse.error);
|
||||
}
|
||||
|
||||
tokenResponse = tokenResponse as TokenResponse;
|
||||
// Calculate the value to be set in the request's Authorization header and resume the call.
|
||||
const authorizationValue = tokenResponse.tokenType + " " + tokenResponse.accessToken;
|
||||
return resolve(authorizationValue);
|
||||
};
|
||||
tokenResponse = tokenResponse as TokenResponse;
|
||||
// Calculate the value to be set in the request's Authorization header and resume the call.
|
||||
const authorizationValue = tokenResponse.tokenType + " " + tokenResponse.accessToken;
|
||||
return resolve(authorizationValue);
|
||||
};
|
||||
|
||||
// Create a new authentication context.
|
||||
if (credentials instanceof TokenCredentialsBase) {
|
||||
const context = new AuthenticationContext(challenge.authorization, true, credentials.authContext && credentials.authContext.cache);
|
||||
if (credentials instanceof ApplicationTokenCredentials) {
|
||||
return context.acquireTokenWithClientCredentials(
|
||||
challenge.resource, credentials.clientId, credentials.secret, _formAuthorizationValue);
|
||||
} else if (credentials instanceof ApplicationTokenCertificateCredentials) {
|
||||
return context.acquireTokenWithClientCertificate(
|
||||
challenge.resource, credentials.clientId, credentials.certificate, credentials.thumbprint, _formAuthorizationValue);
|
||||
} else if (credentials instanceof UserTokenCredentials) {
|
||||
return context.acquireTokenWithUsernamePassword(
|
||||
challenge.resource, credentials.username, credentials.password, credentials.clientId, _formAuthorizationValue);
|
||||
} else if (credentials instanceof DeviceTokenCredentials) {
|
||||
return context.acquireToken(
|
||||
challenge.resource, credentials.username, credentials.clientId, _formAuthorizationValue);
|
||||
// Create a new authentication context.
|
||||
if (credentials instanceof TokenCredentialsBase) {
|
||||
const context = new AuthenticationContext(
|
||||
challenge.authorization,
|
||||
true,
|
||||
credentials.authContext && credentials.authContext.cache
|
||||
);
|
||||
if (credentials instanceof ApplicationTokenCredentials) {
|
||||
return context.acquireTokenWithClientCredentials(
|
||||
challenge.resource,
|
||||
credentials.clientId,
|
||||
credentials.secret,
|
||||
_formAuthorizationValue
|
||||
);
|
||||
} else if (credentials instanceof ApplicationTokenCertificateCredentials) {
|
||||
return context.acquireTokenWithClientCertificate(
|
||||
challenge.resource,
|
||||
credentials.clientId,
|
||||
credentials.certificate,
|
||||
credentials.thumbprint,
|
||||
_formAuthorizationValue
|
||||
);
|
||||
} else if (credentials instanceof UserTokenCredentials) {
|
||||
return context.acquireTokenWithUsernamePassword(
|
||||
challenge.resource,
|
||||
credentials.username,
|
||||
credentials.password,
|
||||
credentials.clientId,
|
||||
_formAuthorizationValue
|
||||
);
|
||||
} else if (credentials instanceof DeviceTokenCredentials) {
|
||||
return context.acquireToken(
|
||||
challenge.resource,
|
||||
credentials.username,
|
||||
credentials.clientId,
|
||||
_formAuthorizationValue
|
||||
);
|
||||
}
|
||||
} else if (credentials instanceof MSITokenCredentials) {
|
||||
return credentials.getToken();
|
||||
} else {
|
||||
return reject(
|
||||
new Error(
|
||||
"credentials must be one of: ApplicationTokenCredentials, UserTokenCredentials, " +
|
||||
"DeviceTokenCredentials, MSITokenCredentials"
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if (credentials instanceof MSITokenCredentials) {
|
||||
return credentials.getToken();
|
||||
} else {
|
||||
return reject(new Error("credentials must be one of: ApplicationTokenCredentials, UserTokenCredentials, " +
|
||||
"DeviceTokenCredentials, MSITokenCredentials"));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -70,16 +70,28 @@ export class MSIAppServiceTokenCredentials extends MSITokenCredentials {
|
|||
constructor(options?: MSIAppServiceOptions) {
|
||||
if (!options) options = {};
|
||||
super(options);
|
||||
options.msiEndpoint = options.msiEndpoint || process.env["IDENTITY_ENDPOINT"] || process.env["MSI_ENDPOINT"];
|
||||
options.msiSecret = options.msiSecret || process.env["IDENTITY_SECRET"] || process.env["MSI_SECRET"];
|
||||
if (!options.msiEndpoint || (options.msiEndpoint && typeof options.msiEndpoint.valueOf() !== "string")) {
|
||||
throw new Error('Either provide "msiEndpoint" as a property of the "options" object ' +
|
||||
'or set the environment variable "IDENTITY_ENDPOINT" or "MSI_ENDPOINT" and it must be of type "string".');
|
||||
options.msiEndpoint =
|
||||
options.msiEndpoint || process.env["IDENTITY_ENDPOINT"] || process.env["MSI_ENDPOINT"];
|
||||
options.msiSecret =
|
||||
options.msiSecret || process.env["IDENTITY_SECRET"] || process.env["MSI_SECRET"];
|
||||
if (
|
||||
!options.msiEndpoint ||
|
||||
(options.msiEndpoint && typeof options.msiEndpoint.valueOf() !== "string")
|
||||
) {
|
||||
throw new Error(
|
||||
'Either provide "msiEndpoint" as a property of the "options" object ' +
|
||||
'or set the environment variable "IDENTITY_ENDPOINT" or "MSI_ENDPOINT" and it must be of type "string".'
|
||||
);
|
||||
}
|
||||
|
||||
if (!options.msiSecret || (options.msiSecret && typeof options.msiSecret.valueOf() !== "string")) {
|
||||
throw new Error('Either provide "msiSecret" as a property of the "options" object ' +
|
||||
'or set the environment variable "IDENTITY_SECRET" or "MSI_SECRET" and it must be of type "string".');
|
||||
if (
|
||||
!options.msiSecret ||
|
||||
(options.msiSecret && typeof options.msiSecret.valueOf() !== "string")
|
||||
) {
|
||||
throw new Error(
|
||||
'Either provide "msiSecret" as a property of the "options" object ' +
|
||||
'or set the environment variable "IDENTITY_SECRET" or "MSI_SECRET" and it must be of type "string".'
|
||||
);
|
||||
}
|
||||
|
||||
if (!options.msiApiVersion) {
|
||||
|
@ -103,14 +115,20 @@ export class MSIAppServiceTokenCredentials extends MSITokenCredentials {
|
|||
|
||||
const opRes = await this._httpClient.sendRequest(reqOptions);
|
||||
if (opRes.bodyAsText === undefined || opRes.bodyAsText!.indexOf("ExceptionMessage") !== -1) {
|
||||
throw new Error(`MSI: Failed to retrieve a token from "${reqOptions.url}" with an error: ${opRes.bodyAsText}`);
|
||||
throw new Error(
|
||||
`MSI: Failed to retrieve a token from "${reqOptions.url}" with an error: ${opRes.bodyAsText}`
|
||||
);
|
||||
}
|
||||
|
||||
const result = this.parseTokenResponse(opRes.bodyAsText!) as MSITokenResponse;
|
||||
if (!result.tokenType) {
|
||||
throw new Error(`Invalid token response, did not find tokenType. Response body is: ${opRes.bodyAsText}`);
|
||||
throw new Error(
|
||||
`Invalid token response, did not find tokenType. Response body is: ${opRes.bodyAsText}`
|
||||
);
|
||||
} else if (!result.accessToken) {
|
||||
throw new Error(`Invalid token response, did not find accessToken. Response body is: ${opRes.bodyAsText}`);
|
||||
throw new Error(
|
||||
`Invalid token response, did not find accessToken. Response body is: ${opRes.bodyAsText}`
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -121,14 +139,14 @@ export class MSIAppServiceTokenCredentials extends MSITokenCredentials {
|
|||
const reqOptions: RequestPrepareOptions = {
|
||||
url: endpoint,
|
||||
headers: {
|
||||
secret: this.msiSecret,
|
||||
secret: this.msiSecret
|
||||
},
|
||||
queryParameters: {
|
||||
"resource": this.resource,
|
||||
resource: this.resource,
|
||||
"api-version": this.msiApiVersion,
|
||||
"clientid": this.clientId,
|
||||
clientid: this.clientId
|
||||
},
|
||||
method: "GET",
|
||||
method: "GET"
|
||||
};
|
||||
|
||||
const webResource = new WebResource();
|
||||
|
|
|
@ -144,7 +144,10 @@ export abstract class MSITokenCredentials implements TokenClientCredentials {
|
|||
*/
|
||||
public async signRequest(webResource: WebResource): Promise<WebResource> {
|
||||
const tokenResponse = await this.getToken();
|
||||
webResource.headers.set(Constants.HeaderConstants.AUTHORIZATION, `${tokenResponse.tokenType} ${tokenResponse.accessToken}`);
|
||||
webResource.headers.set(
|
||||
Constants.HeaderConstants.AUTHORIZATION,
|
||||
`${tokenResponse.tokenType} ${tokenResponse.accessToken}`
|
||||
);
|
||||
return webResource;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,12 +97,15 @@ export class MSIVmTokenCredentials extends MSITokenCredentials {
|
|||
const opRes = await this._httpClient.sendRequest(reqOptions);
|
||||
const result = this.parseTokenResponse(opRes.bodyAsText!) as MSITokenResponse;
|
||||
if (!result.tokenType) {
|
||||
throw new Error(`Invalid token response, did not find tokenType. Response body is: ${opRes.bodyAsText}`);
|
||||
throw new Error(
|
||||
`Invalid token response, did not find tokenType. Response body is: ${opRes.bodyAsText}`
|
||||
);
|
||||
} else if (!result.accessToken) {
|
||||
throw new Error(`Invalid token response, did not find accessToken. Response body is: ${opRes.bodyAsText}`);
|
||||
throw new Error(
|
||||
`Invalid token response, did not find accessToken. Response body is: ${opRes.bodyAsText}`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -111,15 +114,15 @@ export class MSIVmTokenCredentials extends MSITokenCredentials {
|
|||
url: this.msiEndpoint,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"Metadata": "true"
|
||||
Metadata: "true"
|
||||
},
|
||||
method: this.httpMethod,
|
||||
queryParameters: {
|
||||
"api-version": this.apiVersion,
|
||||
"resource": this.resource,
|
||||
"object_id": this.objectId,
|
||||
"client_id": this.clientId,
|
||||
"mi_res_id": this.identityId
|
||||
resource: this.resource,
|
||||
object_id: this.objectId,
|
||||
client_id: this.clientId,
|
||||
mi_res_id: this.identityId
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
AuthenticationContext,
|
||||
MemoryCache,
|
||||
ErrorResponse,
|
||||
TokenCache,
|
||||
TokenCache
|
||||
} from "adal-node";
|
||||
|
||||
export abstract class TokenCredentialsBase implements TokenClientCredentials {
|
||||
|
@ -31,18 +31,14 @@ export abstract class TokenCredentialsBase implements TokenClientCredentials {
|
|||
throw new Error("domain must be a non empty string.");
|
||||
}
|
||||
|
||||
if (
|
||||
this.tokenAudience === "graph" &&
|
||||
this.domain.toLowerCase() === "common"
|
||||
) {
|
||||
if (this.tokenAudience === "graph" && this.domain.toLowerCase() === "common") {
|
||||
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;
|
||||
const authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
|
||||
this.authContext = new AuthenticationContext(
|
||||
authorityUrl,
|
||||
this.environment.validateAuthority,
|
||||
|
@ -52,8 +48,7 @@ export abstract class TokenCredentialsBase implements TokenClientCredentials {
|
|||
|
||||
public setDomain(domain: string): void {
|
||||
this.domain = domain;
|
||||
const authorityUrl =
|
||||
this.environment.activeDirectoryEndpointUrl + this.domain;
|
||||
const authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
|
||||
this.authContext = new AuthenticationContext(
|
||||
authorityUrl,
|
||||
this.environment.validateAuthority,
|
||||
|
|
|
@ -7,7 +7,6 @@ import { TokenAudience } from "../util/authConstants";
|
|||
import { TokenResponse, ErrorResponse, TokenCache } from "adal-node";
|
||||
|
||||
export class UserTokenCredentials extends TokenCredentialsBase {
|
||||
|
||||
readonly username: string;
|
||||
readonly password: string;
|
||||
|
||||
|
@ -33,8 +32,8 @@ export class UserTokenCredentials extends TokenCredentialsBase {
|
|||
password: string,
|
||||
tokenAudience?: TokenAudience,
|
||||
environment?: Environment,
|
||||
tokenCache?: TokenCache) {
|
||||
|
||||
tokenCache?: TokenCache
|
||||
) {
|
||||
if (!clientId || typeof clientId.valueOf() !== "string") {
|
||||
throw new Error("clientId must be a non empty string.");
|
||||
}
|
||||
|
@ -60,7 +59,7 @@ export class UserTokenCredentials extends TokenCredentialsBase {
|
|||
private crossCheckUserNameWithToken(username: string, userIdFromToken: string): boolean {
|
||||
// to maintain the casing consistency between "azureprofile.json" and token cache. (RD 1996587)
|
||||
// use the "userId" here, which should be the same with "username" except the casing.
|
||||
return (username.toLowerCase() === userIdFromToken.toLowerCase());
|
||||
return username.toLowerCase() === userIdFromToken.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,7 +75,11 @@ export class UserTokenCredentials extends TokenCredentialsBase {
|
|||
const resource = this.getActiveDirectoryResourceId();
|
||||
|
||||
return new Promise<TokenResponse>((resolve, reject) => {
|
||||
self.authContext.acquireTokenWithUsernamePassword(resource, self.username, self.password, self.clientId,
|
||||
self.authContext.acquireTokenWithUsernamePassword(
|
||||
resource,
|
||||
self.username,
|
||||
self.password,
|
||||
self.clientId,
|
||||
(error: Error, tokenResponse: TokenResponse | ErrorResponse) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
|
@ -88,12 +91,15 @@ export class UserTokenCredentials extends TokenCredentialsBase {
|
|||
|
||||
tokenResponse = tokenResponse as TokenResponse;
|
||||
if (self.crossCheckUserNameWithToken(self.username, tokenResponse.userId!)) {
|
||||
return resolve((tokenResponse as TokenResponse));
|
||||
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.`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
519
lib/login.ts
519
lib/login.ts
|
@ -12,9 +12,16 @@ import { ApplicationTokenCertificateCredentials } from "./credentials/applicatio
|
|||
import { DeviceTokenCredentials } from "./credentials/deviceTokenCredentials";
|
||||
import { UserTokenCredentials } from "./credentials/userTokenCredentials";
|
||||
import { AuthConstants, TokenAudience } from "./util/authConstants";
|
||||
import { buildTenantList, getSubscriptionsFromTenants, LinkedSubscription } from "./subscriptionManagement/subscriptionUtils";
|
||||
import {
|
||||
buildTenantList,
|
||||
getSubscriptionsFromTenants,
|
||||
LinkedSubscription
|
||||
} from "./subscriptionManagement/subscriptionUtils";
|
||||
import { MSIVmTokenCredentials, MSIVmOptions } from "./credentials/msiVmTokenCredentials";
|
||||
import { MSIAppServiceTokenCredentials, MSIAppServiceOptions } from "./credentials/msiAppServiceTokenCredentials";
|
||||
import {
|
||||
MSIAppServiceTokenCredentials,
|
||||
MSIAppServiceOptions
|
||||
} from "./credentials/msiAppServiceTokenCredentials";
|
||||
import { MSITokenResponse } from "./credentials/msiTokenCredentials";
|
||||
|
||||
/**
|
||||
|
@ -36,17 +43,16 @@ const managementPlaneTokenAudiences = [
|
|||
|
||||
function turnOnLogging() {
|
||||
const log = adal.Logging;
|
||||
log.setLoggingOptions(
|
||||
{
|
||||
level: 3, // Please use log.LOGGING_LEVEL.VERBOSE once AD TypeScript mappings are updated,
|
||||
log: function (level: any, message: any, error: any) {
|
||||
level;
|
||||
console.info(message);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
log.setLoggingOptions({
|
||||
level: 3, // Please use log.LOGGING_LEVEL.VERBOSE once AD TypeScript mappings are updated,
|
||||
log: function (level: any, message: any, error: any) {
|
||||
level;
|
||||
console.info(message);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env["AZURE_ADAL_LOGGING_ENABLED"]) {
|
||||
|
@ -160,7 +166,11 @@ export type Callback<TResult> = (error?: Error, result?: TResult) => void;
|
|||
*
|
||||
* @returns 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> {
|
||||
export async function withUsernamePasswordWithAuthResponse(
|
||||
username: string,
|
||||
password: string,
|
||||
options?: LoginWithUsernamePasswordOptions
|
||||
): Promise<AuthResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -174,7 +184,15 @@ export async function withUsernamePasswordWithAuthResponse(username: string, pas
|
|||
options.environment = Environment.AzureCloud;
|
||||
}
|
||||
|
||||
const creds = new UserTokenCredentials(options.clientId, options.domain, username, password, options.tokenAudience, options.environment, options.tokenCache);
|
||||
const creds = new UserTokenCredentials(
|
||||
options.clientId,
|
||||
options.domain,
|
||||
username,
|
||||
password,
|
||||
options.tokenAudience,
|
||||
options.environment,
|
||||
options.tokenCache
|
||||
);
|
||||
const tokenResponse = await creds.getToken();
|
||||
|
||||
// The token cache gets propulated for all the tenants as a part of building the tenantList.
|
||||
|
@ -183,7 +201,11 @@ export async function withUsernamePasswordWithAuthResponse(username: string, pas
|
|||
tenantList = [tokenResponse.tenantId];
|
||||
}
|
||||
|
||||
const subscriptionList: LinkedSubscription[] = await _getSubscriptions(creds, tenantList, options.tokenAudience);
|
||||
const subscriptionList: LinkedSubscription[] = await _getSubscriptions(
|
||||
creds,
|
||||
tenantList,
|
||||
options.tokenAudience
|
||||
);
|
||||
|
||||
return { credentials: creds, subscriptions: subscriptionList };
|
||||
}
|
||||
|
@ -206,7 +228,12 @@ export async function withUsernamePasswordWithAuthResponse(username: string, pas
|
|||
*
|
||||
* @returns 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> {
|
||||
export async function withServicePrincipalSecretWithAuthResponse(
|
||||
clientId: string,
|
||||
secret: string,
|
||||
domain: string,
|
||||
options?: AzureTokenCredentialsOptions
|
||||
): Promise<AuthResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -214,7 +241,14 @@ export async function withServicePrincipalSecretWithAuthResponse(clientId: strin
|
|||
options.environment = Environment.AzureCloud;
|
||||
}
|
||||
|
||||
const creds = new ApplicationTokenCredentials(clientId, domain, secret, options.tokenAudience, options.environment, options.tokenCache);
|
||||
const creds = new ApplicationTokenCredentials(
|
||||
clientId,
|
||||
domain,
|
||||
secret,
|
||||
options.tokenAudience,
|
||||
options.environment,
|
||||
options.tokenCache
|
||||
);
|
||||
await creds.getToken();
|
||||
|
||||
const subscriptionList = await _getSubscriptions(creds, [domain], options.tokenAudience);
|
||||
|
@ -242,7 +276,12 @@ export async function withServicePrincipalSecretWithAuthResponse(clientId: strin
|
|||
*
|
||||
* @returns 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> {
|
||||
export async function withServicePrincipalCertificateWithAuthResponse(
|
||||
clientId: string,
|
||||
certificateStringOrFilePath: string,
|
||||
domain: string,
|
||||
options?: AzureTokenCredentialsOptions
|
||||
): Promise<AuthResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -250,7 +289,12 @@ export async function withServicePrincipalCertificateWithAuthResponse(clientId:
|
|||
options.environment = Environment.AzureCloud;
|
||||
}
|
||||
|
||||
const creds = ApplicationTokenCertificateCredentials.create(clientId, certificateStringOrFilePath, domain, options);
|
||||
const creds = ApplicationTokenCertificateCredentials.create(
|
||||
clientId,
|
||||
certificateStringOrFilePath,
|
||||
domain,
|
||||
options
|
||||
);
|
||||
await creds.getToken();
|
||||
|
||||
const subscriptionList = await _getSubscriptions(creds, [domain], options.tokenAudience);
|
||||
|
@ -269,7 +313,9 @@ function validateAuthFileContent(credsObj: any, filePath: string) {
|
|||
throw new Error(`"clientId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.clientSecret && !credsObj.clientCertificate) {
|
||||
throw new Error(`Either "clientSecret" or "clientCertificate" must be present in the auth file: ${filePath}.`);
|
||||
throw new Error(
|
||||
`Either "clientSecret" or "clientCertificate" must be present in the auth file: ${filePath}.`
|
||||
);
|
||||
}
|
||||
if (!credsObj.subscriptionId) {
|
||||
throw new Error(`"subscriptionId" is missing from the auth file: ${filePath}.`);
|
||||
|
@ -302,7 +348,7 @@ function foundManagementEndpointUrl(authFileUrl: string, envUrl: string): boolea
|
|||
|
||||
authFileUrl = authFileUrl.endsWith("/") ? authFileUrl.slice(0, -1) : authFileUrl;
|
||||
envUrl = envUrl.endsWith("/") ? envUrl.slice(0, -1) : envUrl;
|
||||
return (authFileUrl.toLowerCase() === envUrl.toLowerCase());
|
||||
return authFileUrl.toLowerCase() === envUrl.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -330,15 +376,19 @@ function foundManagementEndpointUrl(authFileUrl: string, envUrl: string): boolea
|
|||
*
|
||||
* @returns 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> {
|
||||
export async function withAuthFileWithAuthResponse(
|
||||
options?: LoginWithAuthFileOptions
|
||||
): Promise<AuthResponse> {
|
||||
if (!options) options = { filePath: "" };
|
||||
const filePath = options.filePath || process.env[AuthConstants.AZURE_AUTH_LOCATION];
|
||||
const subscriptionEnvVariableName = options.subscriptionEnvVariableName || "AZURE_SUBSCRIPTION_ID";
|
||||
const subscriptionEnvVariableName =
|
||||
options.subscriptionEnvVariableName || "AZURE_SUBSCRIPTION_ID";
|
||||
if (!filePath) {
|
||||
const msg = `Either provide an absolute file path to the auth file or set/export the environment variable - ${AuthConstants.AZURE_AUTH_LOCATION}.`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
let content: string, credsObj: any = {};
|
||||
let content: string,
|
||||
credsObj: any = {};
|
||||
const optionsForSp: any = {};
|
||||
|
||||
content = readFileSync(filePath, { encoding: "utf8" });
|
||||
|
@ -358,9 +408,14 @@ export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOp
|
|||
for (let i = 0; i < envNames.length; i++) {
|
||||
const env = envNames[i];
|
||||
const environmentObj = (Environment as any)[env];
|
||||
if (environmentObj &&
|
||||
if (
|
||||
environmentObj &&
|
||||
environmentObj.managementEndpointUrl &&
|
||||
foundManagementEndpointUrl(credsObj.managementEndpointUrl, environmentObj.managementEndpointUrl)) {
|
||||
foundManagementEndpointUrl(
|
||||
credsObj.managementEndpointUrl,
|
||||
environmentObj.managementEndpointUrl
|
||||
)
|
||||
) {
|
||||
envFound.name = environmentObj.name;
|
||||
break;
|
||||
}
|
||||
|
@ -376,7 +431,9 @@ export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOp
|
|||
const keys = Object.keys(credsObj);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
if (key.match(/^(clientId|clientSecret|clientCertificate|subscriptionId|tenantId)$/ig) === null) {
|
||||
if (
|
||||
key.match(/^(clientId|clientSecret|clientCertificate|subscriptionId|tenantId)$/gi) === null
|
||||
) {
|
||||
if (key === "activeDirectoryEndpointUrl" && !key.endsWith("/")) {
|
||||
envParams[key] = credsObj[key] + "/";
|
||||
} else {
|
||||
|
@ -393,13 +450,22 @@ export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOp
|
|||
optionsForSp.environment = Environment.add(envParams);
|
||||
}
|
||||
if (credsObj.clientSecret) {
|
||||
return withServicePrincipalSecretWithAuthResponse(credsObj.clientId, credsObj.clientSecret, credsObj.tenantId, optionsForSp);
|
||||
return withServicePrincipalSecretWithAuthResponse(
|
||||
credsObj.clientId,
|
||||
credsObj.clientSecret,
|
||||
credsObj.tenantId,
|
||||
optionsForSp
|
||||
);
|
||||
}
|
||||
|
||||
return withServicePrincipalCertificateWithAuthResponse(credsObj.clientId, credsObj.clientCertificate, credsObj.tenantId, optionsForSp);
|
||||
return withServicePrincipalCertificateWithAuthResponse(
|
||||
credsObj.clientId,
|
||||
credsObj.clientCertificate,
|
||||
credsObj.tenantId,
|
||||
optionsForSp
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -429,7 +495,9 @@ export async function withAuthFileWithAuthResponse(options?: LoginWithAuthFileOp
|
|||
*
|
||||
* @returns 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> {
|
||||
export async function withInteractiveWithAuthResponse(
|
||||
options?: InteractiveLoginOptions
|
||||
): Promise<AuthResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -465,32 +533,42 @@ export async function withInteractiveWithAuthResponse(options?: InteractiveLogin
|
|||
interactiveOptions.tokenCache = options.tokenCache;
|
||||
interactiveOptions.language = options.language;
|
||||
interactiveOptions.userCodeResponseLogger = options.userCodeResponseLogger;
|
||||
const authorityUrl: string = interactiveOptions.environment.activeDirectoryEndpointUrl + interactiveOptions.domain;
|
||||
const authContext = new adal.AuthenticationContext(authorityUrl, interactiveOptions.environment.validateAuthority, interactiveOptions.tokenCache);
|
||||
const authorityUrl: string =
|
||||
interactiveOptions.environment.activeDirectoryEndpointUrl + interactiveOptions.domain;
|
||||
const authContext = new adal.AuthenticationContext(
|
||||
authorityUrl,
|
||||
interactiveOptions.environment.validateAuthority,
|
||||
interactiveOptions.tokenCache
|
||||
);
|
||||
interactiveOptions.context = authContext;
|
||||
|
||||
function tryAcquireToken(interactiveOptions: InteractiveLoginOptions, resolve: any, reject: any) {
|
||||
authContext.acquireUserCode(interactiveOptions.tokenAudience!, interactiveOptions.clientId!, interactiveOptions.language!, (err: any, userCodeRes: adal.UserCodeInfo) => {
|
||||
if (err) {
|
||||
if (err.error === "authorization_pending") {
|
||||
setTimeout(() => {
|
||||
tryAcquireToken(interactiveOptions, resolve, reject);
|
||||
}, 1000);
|
||||
} else {
|
||||
reject(err);
|
||||
authContext.acquireUserCode(
|
||||
interactiveOptions.tokenAudience!,
|
||||
interactiveOptions.clientId!,
|
||||
interactiveOptions.language!,
|
||||
(err: any, userCodeRes: adal.UserCodeInfo) => {
|
||||
if (err) {
|
||||
if (err.error === "authorization_pending") {
|
||||
setTimeout(() => {
|
||||
tryAcquireToken(interactiveOptions, resolve, reject);
|
||||
}, 1000);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (interactiveOptions.userCodeResponseLogger) {
|
||||
interactiveOptions.userCodeResponseLogger(userCodeRes.message);
|
||||
} else {
|
||||
console.log(userCodeRes.message);
|
||||
}
|
||||
|
||||
if (interactiveOptions.userCodeResponseLogger) {
|
||||
interactiveOptions.userCodeResponseLogger(userCodeRes.message);
|
||||
} else {
|
||||
console.log(userCodeRes.message);
|
||||
return resolve(userCodeRes);
|
||||
}
|
||||
|
||||
return resolve(userCodeRes);
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
const getUserCode = new Promise<adal.UserCodeInfo>((resolve, reject) => {
|
||||
|
@ -499,24 +577,35 @@ export async function withInteractiveWithAuthResponse(options?: InteractiveLogin
|
|||
|
||||
const userCodeResponse = await getUserCode;
|
||||
const creds = await new Promise<DeviceTokenCredentials>((resolve, reject) => {
|
||||
return authContext.acquireTokenWithDeviceCode(interactiveOptions.tokenAudience, interactiveOptions.clientId, userCodeResponse, (error, tokenResponse) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return authContext.acquireTokenWithDeviceCode(
|
||||
interactiveOptions.tokenAudience,
|
||||
interactiveOptions.clientId,
|
||||
userCodeResponse,
|
||||
(error, tokenResponse) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
const response = tokenResponse as adal.TokenResponse;
|
||||
interactiveOptions.userName = response.userId;
|
||||
interactiveOptions.authorizationScheme = response.tokenType;
|
||||
const response = tokenResponse as adal.TokenResponse;
|
||||
interactiveOptions.userName = response.userId;
|
||||
interactiveOptions.authorizationScheme = response.tokenType;
|
||||
|
||||
let creds;
|
||||
try {
|
||||
creds = new DeviceTokenCredentials(interactiveOptions.clientId, interactiveOptions.domain, interactiveOptions.userName,
|
||||
interactiveOptions.tokenAudience, interactiveOptions.environment, interactiveOptions.tokenCache);
|
||||
} catch (err) {
|
||||
return reject(err);
|
||||
let creds;
|
||||
try {
|
||||
creds = new DeviceTokenCredentials(
|
||||
interactiveOptions.clientId,
|
||||
interactiveOptions.domain,
|
||||
interactiveOptions.userName,
|
||||
interactiveOptions.tokenAudience,
|
||||
interactiveOptions.environment,
|
||||
interactiveOptions.tokenCache
|
||||
);
|
||||
} catch (err) {
|
||||
return reject(err);
|
||||
}
|
||||
return resolve(creds);
|
||||
}
|
||||
return resolve(creds);
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
const tenants = await buildTenantList(creds);
|
||||
|
@ -560,9 +649,27 @@ export async function withInteractiveWithAuthResponse(options?: InteractiveLogin
|
|||
*/
|
||||
export function withAuthFile(): Promise<TokenCredentialsBase>;
|
||||
export function withAuthFile(options: LoginWithAuthFileOptions): Promise<TokenCredentialsBase>;
|
||||
export function withAuthFile(options: LoginWithAuthFileOptions, callback: { (err: Error, credentials: ApplicationTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): void;
|
||||
export function withAuthFile(
|
||||
options: LoginWithAuthFileOptions,
|
||||
callback: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: ApplicationTokenCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): void;
|
||||
export function withAuthFile(callback: any): void;
|
||||
export function withAuthFile(options?: LoginWithAuthFileOptions, callback?: { (err: Error, credentials: ApplicationTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): any {
|
||||
export function withAuthFile(
|
||||
options?: LoginWithAuthFileOptions,
|
||||
callback?: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: ApplicationTokenCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): any {
|
||||
if (!callback && typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
|
@ -573,12 +680,14 @@ export function withAuthFile(options?: LoginWithAuthFileOptions, callback?: { (e
|
|||
return authRes.credentials;
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withAuthFileWithAuthResponse(options))((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
msRest.promiseToCallback(withAuthFileWithAuthResponse(options))(
|
||||
(err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(undefined, authRes.credentials, authRes.subscriptions);
|
||||
}
|
||||
return cb(undefined, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,9 +722,27 @@ export function withAuthFile(options?: LoginWithAuthFileOptions, callback?: { (e
|
|||
*/
|
||||
export function interactive(): Promise<DeviceTokenCredentials>;
|
||||
export function interactive(options: InteractiveLoginOptions): Promise<DeviceTokenCredentials>;
|
||||
export function interactive(options: InteractiveLoginOptions, callback: { (err: Error, credentials: DeviceTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): void;
|
||||
export function interactive(
|
||||
options: InteractiveLoginOptions,
|
||||
callback: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: DeviceTokenCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): void;
|
||||
export function interactive(callback: any): void;
|
||||
export function interactive(options?: InteractiveLoginOptions, callback?: { (err: Error, credentials: DeviceTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): any {
|
||||
export function interactive(
|
||||
options?: InteractiveLoginOptions,
|
||||
callback?: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: DeviceTokenCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): any {
|
||||
if (!callback && typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
|
@ -626,12 +753,14 @@ export function interactive(options?: InteractiveLoginOptions, callback?: { (err
|
|||
return authRes.credentials;
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withInteractiveWithAuthResponse(options))((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
msRest.promiseToCallback(withInteractiveWithAuthResponse(options))(
|
||||
(err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(undefined, authRes.credentials, authRes.subscriptions);
|
||||
}
|
||||
return cb(undefined, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -662,22 +791,64 @@ export function interactive(options?: InteractiveLoginOptions, callback?: { (err
|
|||
* @resolve {ApplicationTokenCredentials} The ApplicationTokenCredentials object.
|
||||
* @reject {Error} - The error object.
|
||||
*/
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string): Promise<ApplicationTokenCredentials>;
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, options: AzureTokenCredentialsOptions): Promise<ApplicationTokenCredentials>;
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, options: AzureTokenCredentialsOptions, callback: { (err: Error, credentials: ApplicationTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): void;
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, callback: any): void;
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, options?: AzureTokenCredentialsOptions, callback?: { (err: Error, credentials: ApplicationTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): any {
|
||||
export function withServicePrincipalSecret(
|
||||
clientId: string,
|
||||
secret: string,
|
||||
domain: string
|
||||
): Promise<ApplicationTokenCredentials>;
|
||||
export function withServicePrincipalSecret(
|
||||
clientId: string,
|
||||
secret: string,
|
||||
domain: string,
|
||||
options: AzureTokenCredentialsOptions
|
||||
): Promise<ApplicationTokenCredentials>;
|
||||
export function withServicePrincipalSecret(
|
||||
clientId: string,
|
||||
secret: string,
|
||||
domain: string,
|
||||
options: AzureTokenCredentialsOptions,
|
||||
callback: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: ApplicationTokenCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): void;
|
||||
export function withServicePrincipalSecret(
|
||||
clientId: string,
|
||||
secret: string,
|
||||
domain: string,
|
||||
callback: any
|
||||
): void;
|
||||
export function withServicePrincipalSecret(
|
||||
clientId: string,
|
||||
secret: string,
|
||||
domain: string,
|
||||
options?: AzureTokenCredentialsOptions,
|
||||
callback?: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: ApplicationTokenCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): any {
|
||||
if (!callback && typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
const cb = callback as Function;
|
||||
if (!callback) {
|
||||
return withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options).then((authRes) => {
|
||||
return authRes.credentials;
|
||||
});
|
||||
return withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options).then(
|
||||
(authRes) => {
|
||||
return authRes.credentials;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
msRest.promiseToCallback(withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options))((err: Error, authRes: AuthResponse) => {
|
||||
msRest.promiseToCallback(
|
||||
withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options)
|
||||
)((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
@ -715,22 +886,72 @@ export function withServicePrincipalSecret(clientId: string, secret: string, dom
|
|||
* @resolve {ApplicationTokenCertificateCredentials} The ApplicationTokenCertificateCredentials object.
|
||||
* @reject {Error} - The error object.
|
||||
*/
|
||||
export function withServicePrincipalCertificate(clientId: string, certificateStringOrFilePath: string, domain: string): Promise<ApplicationTokenCertificateCredentials>;
|
||||
export function withServicePrincipalCertificate(clientId: string, certificateStringOrFilePath: string, domain: string, options: AzureTokenCredentialsOptions): Promise<ApplicationTokenCredentials>;
|
||||
export function withServicePrincipalCertificate(clientId: string, certificateStringOrFilePath: string, domain: string, options: AzureTokenCredentialsOptions, callback: { (err: Error, credentials: ApplicationTokenCertificateCredentials, subscriptions: Array<LinkedSubscription>): void }): void;
|
||||
export function withServicePrincipalCertificate(clientId: string, certificateStringOrFilePath: string, domain: string, callback: any): void;
|
||||
export function withServicePrincipalCertificate(clientId: string, certificateStringOrFilePath: string, domain: string, options?: AzureTokenCredentialsOptions, callback?: { (err: Error, credentials: ApplicationTokenCertificateCredentials, subscriptions: Array<LinkedSubscription>): void }): any {
|
||||
export function withServicePrincipalCertificate(
|
||||
clientId: string,
|
||||
certificateStringOrFilePath: string,
|
||||
domain: string
|
||||
): Promise<ApplicationTokenCertificateCredentials>;
|
||||
export function withServicePrincipalCertificate(
|
||||
clientId: string,
|
||||
certificateStringOrFilePath: string,
|
||||
domain: string,
|
||||
options: AzureTokenCredentialsOptions
|
||||
): Promise<ApplicationTokenCredentials>;
|
||||
export function withServicePrincipalCertificate(
|
||||
clientId: string,
|
||||
certificateStringOrFilePath: string,
|
||||
domain: string,
|
||||
options: AzureTokenCredentialsOptions,
|
||||
callback: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: ApplicationTokenCertificateCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): void;
|
||||
export function withServicePrincipalCertificate(
|
||||
clientId: string,
|
||||
certificateStringOrFilePath: string,
|
||||
domain: string,
|
||||
callback: any
|
||||
): void;
|
||||
export function withServicePrincipalCertificate(
|
||||
clientId: string,
|
||||
certificateStringOrFilePath: string,
|
||||
domain: string,
|
||||
options?: AzureTokenCredentialsOptions,
|
||||
callback?: {
|
||||
(
|
||||
err: Error,
|
||||
credentials: ApplicationTokenCertificateCredentials,
|
||||
subscriptions: Array<LinkedSubscription>
|
||||
): void;
|
||||
}
|
||||
): any {
|
||||
if (!callback && typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
const cb = callback as Function;
|
||||
if (!callback) {
|
||||
return withServicePrincipalCertificateWithAuthResponse(clientId, certificateStringOrFilePath, domain, options).then((authRes) => {
|
||||
return withServicePrincipalCertificateWithAuthResponse(
|
||||
clientId,
|
||||
certificateStringOrFilePath,
|
||||
domain,
|
||||
options
|
||||
).then((authRes) => {
|
||||
return authRes.credentials;
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withServicePrincipalCertificateWithAuthResponse(clientId, certificateStringOrFilePath, domain, options))((err: Error, authRes: AuthResponse) => {
|
||||
msRest.promiseToCallback(
|
||||
withServicePrincipalCertificateWithAuthResponse(
|
||||
clientId,
|
||||
certificateStringOrFilePath,
|
||||
domain,
|
||||
options
|
||||
)
|
||||
)((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
@ -769,11 +990,32 @@ export function withServicePrincipalCertificate(clientId: string, certificateStr
|
|||
* @resolve {UserTokenCredentials} The UserTokenCredentials object.
|
||||
* @reject {Error} - The error object.
|
||||
*/
|
||||
export function withUsernamePassword(username: string, password: string): Promise<UserTokenCredentials>;
|
||||
export function withUsernamePassword(username: string, password: string, options: LoginWithUsernamePasswordOptions): Promise<UserTokenCredentials>;
|
||||
export function withUsernamePassword(
|
||||
username: string,
|
||||
password: string
|
||||
): Promise<UserTokenCredentials>;
|
||||
export function withUsernamePassword(
|
||||
username: string,
|
||||
password: string,
|
||||
options: LoginWithUsernamePasswordOptions
|
||||
): Promise<UserTokenCredentials>;
|
||||
export function withUsernamePassword(username: string, password: string, callback: any): void;
|
||||
export function withUsernamePassword(username: string, password: string, options: LoginWithUsernamePasswordOptions, callback: { (err: Error, credentials: UserTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): void;
|
||||
export function withUsernamePassword(username: string, password: string, options?: LoginWithUsernamePasswordOptions, callback?: { (err: Error, credentials: UserTokenCredentials, subscriptions: Array<LinkedSubscription>): void }): any {
|
||||
export function withUsernamePassword(
|
||||
username: string,
|
||||
password: string,
|
||||
options: LoginWithUsernamePasswordOptions,
|
||||
callback: {
|
||||
(err: Error, credentials: UserTokenCredentials, subscriptions: Array<LinkedSubscription>): void;
|
||||
}
|
||||
): void;
|
||||
export function withUsernamePassword(
|
||||
username: string,
|
||||
password: string,
|
||||
options?: LoginWithUsernamePasswordOptions,
|
||||
callback?: {
|
||||
(err: Error, credentials: UserTokenCredentials, subscriptions: Array<LinkedSubscription>): void;
|
||||
}
|
||||
): any {
|
||||
if (!callback && typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
|
@ -784,12 +1026,14 @@ export function withUsernamePassword(username: string, password: string, options
|
|||
return authRes.credentials;
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withUsernamePasswordWithAuthResponse(username, password, options))((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
msRest.promiseToCallback(withUsernamePasswordWithAuthResponse(username, password, options))(
|
||||
(err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(undefined, authRes.credentials, authRes.subscriptions);
|
||||
}
|
||||
return cb(undefined, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -799,9 +1043,14 @@ export function withUsernamePassword(username: string, password: string, options
|
|||
function _getSubscriptions(
|
||||
creds: TokenCredentialsBase,
|
||||
tenants: string[],
|
||||
tokenAudience?: string): Promise<LinkedSubscription[]> {
|
||||
if (tokenAudience &&
|
||||
!managementPlaneTokenAudiences.some((item) => { return item === tokenAudience!.toLowerCase(); })) {
|
||||
tokenAudience?: string
|
||||
): Promise<LinkedSubscription[]> {
|
||||
if (
|
||||
tokenAudience &&
|
||||
!managementPlaneTokenAudiences.some((item) => {
|
||||
return item === tokenAudience!.toLowerCase();
|
||||
})
|
||||
) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return getSubscriptionsFromTenants(creds, tenants);
|
||||
|
@ -865,9 +1114,15 @@ async function _withMSI(options?: MSIVmOptions): Promise<MSIVmTokenCredentials>
|
|||
*/
|
||||
export function loginWithVmMSI(): Promise<MSIVmTokenCredentials>;
|
||||
export function loginWithVmMSI(options: MSIVmOptions): Promise<MSIVmTokenCredentials>;
|
||||
export function loginWithVmMSI(options: MSIVmOptions, callback: Callback<MSIVmTokenCredentials>): void;
|
||||
export function loginWithVmMSI(
|
||||
options: MSIVmOptions,
|
||||
callback: Callback<MSIVmTokenCredentials>
|
||||
): void;
|
||||
export function loginWithVmMSI(callback: Callback<MSIVmTokenCredentials>): void;
|
||||
export function loginWithVmMSI(options?: MSIVmOptions | Callback<MSIVmTokenCredentials>, callback?: Callback<MSIVmTokenCredentials>): void | Promise<MSIVmTokenCredentials> {
|
||||
export function loginWithVmMSI(
|
||||
options?: MSIVmOptions | Callback<MSIVmTokenCredentials>,
|
||||
callback?: Callback<MSIVmTokenCredentials>
|
||||
): void | Promise<MSIVmTokenCredentials> {
|
||||
if (!callback && typeof options === "function") {
|
||||
callback = options;
|
||||
options = {};
|
||||
|
@ -876,19 +1131,23 @@ export function loginWithVmMSI(options?: MSIVmOptions | Callback<MSIVmTokenCrede
|
|||
if (!callback) {
|
||||
return _withMSI(options as MSIVmOptions);
|
||||
} else {
|
||||
msRest.promiseToCallback(_withMSI(options as MSIVmOptions))((err: Error, tokenRes: MSITokenResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
msRest.promiseToCallback(_withMSI(options as MSIVmOptions))(
|
||||
(err: Error, tokenRes: MSITokenResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(undefined, tokenRes);
|
||||
}
|
||||
return cb(undefined, tokenRes);
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method
|
||||
*/
|
||||
async function _withAppServiceMSI(options: MSIAppServiceOptions): Promise<MSIAppServiceTokenCredentials> {
|
||||
async function _withAppServiceMSI(
|
||||
options: MSIAppServiceOptions
|
||||
): Promise<MSIAppServiceTokenCredentials> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
@ -923,10 +1182,18 @@ async function _withAppServiceMSI(options: MSIAppServiceOptions): Promise<MSIApp
|
|||
* @reject {Error} - error object.
|
||||
*/
|
||||
export function loginWithAppServiceMSI(): Promise<MSIAppServiceTokenCredentials>;
|
||||
export function loginWithAppServiceMSI(options: MSIAppServiceOptions): Promise<MSIAppServiceTokenCredentials>;
|
||||
export function loginWithAppServiceMSI(options: MSIAppServiceOptions, callback: Callback<MSIAppServiceTokenCredentials>): void;
|
||||
export function loginWithAppServiceMSI(
|
||||
options: MSIAppServiceOptions
|
||||
): Promise<MSIAppServiceTokenCredentials>;
|
||||
export function loginWithAppServiceMSI(
|
||||
options: MSIAppServiceOptions,
|
||||
callback: Callback<MSIAppServiceTokenCredentials>
|
||||
): void;
|
||||
export function loginWithAppServiceMSI(callback: Callback<MSIAppServiceTokenCredentials>): void;
|
||||
export function loginWithAppServiceMSI(options?: MSIAppServiceOptions | Callback<MSIAppServiceTokenCredentials>, callback?: Callback<MSIAppServiceTokenCredentials>): void | Promise<MSIAppServiceTokenCredentials> {
|
||||
export function loginWithAppServiceMSI(
|
||||
options?: MSIAppServiceOptions | Callback<MSIAppServiceTokenCredentials>,
|
||||
callback?: Callback<MSIAppServiceTokenCredentials>
|
||||
): void | Promise<MSIAppServiceTokenCredentials> {
|
||||
if (!callback && typeof options === "function") {
|
||||
callback = options;
|
||||
options = {};
|
||||
|
@ -935,12 +1202,14 @@ export function loginWithAppServiceMSI(options?: MSIAppServiceOptions | Callback
|
|||
if (!callback) {
|
||||
return _withAppServiceMSI(options as MSIAppServiceOptions);
|
||||
} else {
|
||||
msRest.promiseToCallback(_withAppServiceMSI(options as MSIAppServiceOptions))((err: Error, tokenRes: MSITokenResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
msRest.promiseToCallback(_withAppServiceMSI(options as MSIAppServiceOptions))(
|
||||
(err: Error, tokenRes: MSITokenResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(undefined, tokenRes);
|
||||
}
|
||||
return cb(undefined, tokenRes);
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -959,7 +1228,8 @@ export async function execAz(cmd: string): Promise<any> {
|
|||
try {
|
||||
return resolve(JSON.parse(stdout));
|
||||
} catch (err) {
|
||||
const msg = `An error occurred 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));
|
||||
}
|
||||
|
@ -967,5 +1237,4 @@ export async function execAz(cmd: string): Promise<any> {
|
|||
return resolve();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -5,21 +5,36 @@ export { ApplicationTokenCredentials } from "./credentials/applicationTokenCrede
|
|||
export { ApplicationTokenCertificateCredentials } from "./credentials/applicationTokenCertificateCredentials";
|
||||
export { DeviceTokenCredentials } from "./credentials/deviceTokenCredentials";
|
||||
export { createAuthenticator } from "./credentials/keyVaultFactory";
|
||||
export { MSIAppServiceOptions, MSIAppServiceTokenCredentials } from "./credentials/msiAppServiceTokenCredentials";
|
||||
export { MSIOptions, MSITokenCredentials, MSITokenResponse } from "./credentials/msiTokenCredentials";
|
||||
export {
|
||||
MSIAppServiceOptions,
|
||||
MSIAppServiceTokenCredentials
|
||||
} from "./credentials/msiAppServiceTokenCredentials";
|
||||
export {
|
||||
MSIOptions,
|
||||
MSITokenCredentials,
|
||||
MSITokenResponse
|
||||
} from "./credentials/msiTokenCredentials";
|
||||
export { MSIVmOptions, MSIVmTokenCredentials } from "./credentials/msiVmTokenCredentials";
|
||||
export { TokenCredentialsBase } from "./credentials/tokenCredentialsBase";
|
||||
export { UserTokenCredentials } from "./credentials/userTokenCredentials";
|
||||
export { AuthConstants, TokenAudience } from "./util/authConstants";
|
||||
export { LinkedSubscription, LinkedUser, UserType, buildTenantList } from "./subscriptionManagement/subscriptionUtils";
|
||||
export {
|
||||
LinkedSubscription,
|
||||
LinkedUser,
|
||||
UserType,
|
||||
buildTenantList
|
||||
} from "./subscriptionManagement/subscriptionUtils";
|
||||
export {
|
||||
AzureCliCredentials,
|
||||
CliAccessToken,
|
||||
ListAllSubscriptionOptions
|
||||
} from "./credentials/azureCliCredentials";
|
||||
export {
|
||||
AuthResponse, LoginWithAuthFileOptions, InteractiveLoginOptions,
|
||||
AzureTokenCredentialsOptions, LoginWithUsernamePasswordOptions,
|
||||
AuthResponse,
|
||||
LoginWithAuthFileOptions,
|
||||
InteractiveLoginOptions,
|
||||
AzureTokenCredentialsOptions,
|
||||
LoginWithUsernamePasswordOptions,
|
||||
interactive as interactiveLogin,
|
||||
withInteractiveWithAuthResponse as interactiveLoginWithAuthResponse,
|
||||
withUsernamePassword as loginWithUsernamePassword,
|
||||
|
|
|
@ -76,7 +76,10 @@ export interface LinkedSubscription {
|
|||
* @param apiVersion - default value 2016-06-01
|
||||
* @returns A promise that resolves to an array of tenantIds and rejects with an error.
|
||||
*/
|
||||
export async function buildTenantList(credentials: TokenCredentialsBase, apiVersion = "2016-06-01"): Promise<string[]> {
|
||||
export async function buildTenantList(
|
||||
credentials: TokenCredentialsBase,
|
||||
apiVersion = "2016-06-01"
|
||||
): Promise<string[]> {
|
||||
if (credentials.domain && credentials.domain !== AuthConstants.AAD_COMMON_TENANT) {
|
||||
return [credentials.domain];
|
||||
}
|
||||
|
@ -86,7 +89,7 @@ export async function buildTenantList(credentials: TokenCredentialsBase, apiVers
|
|||
const reqUrl = `${baseUrl}${baseUrl.endsWith("/") ? "" : "/"}tenants?api-version=${apiVersion}`;
|
||||
const req: msRest.RequestPrepareOptions = {
|
||||
url: reqUrl,
|
||||
method: "GET",
|
||||
method: "GET"
|
||||
};
|
||||
const res = await client.sendRequest(req);
|
||||
const result: string[] = [];
|
||||
|
@ -101,7 +104,11 @@ export async function buildTenantList(credentials: TokenCredentialsBase, apiVers
|
|||
return result;
|
||||
}
|
||||
|
||||
export async function getSubscriptionsFromTenants(credentials: TokenCredentialsBase, tenantList: string[], apiVersion = "2016-06-01"): Promise<LinkedSubscription[]> {
|
||||
export async function getSubscriptionsFromTenants(
|
||||
credentials: TokenCredentialsBase,
|
||||
tenantList: string[],
|
||||
apiVersion = "2016-06-01"
|
||||
): Promise<LinkedSubscription[]> {
|
||||
let subscriptions: LinkedSubscription[] = [];
|
||||
let userType = "user";
|
||||
let username: string;
|
||||
|
@ -116,25 +123,29 @@ export async function getSubscriptionsFromTenants(credentials: TokenCredentialsB
|
|||
credentials.domain = tenant;
|
||||
const client = new msRest.ServiceClient(credentials);
|
||||
const baseUrl = credentials.environment.resourceManagerEndpointUrl;
|
||||
const reqUrl = `${baseUrl}${baseUrl.endsWith("/") ? "" : "/"}subscriptions?api-version=${apiVersion}`;
|
||||
const reqUrl = `${baseUrl}${
|
||||
baseUrl.endsWith("/") ? "" : "/"
|
||||
}subscriptions?api-version=${apiVersion}`;
|
||||
const req: msRest.RequestPrepareOptions = {
|
||||
url: reqUrl,
|
||||
method: "GET",
|
||||
method: "GET"
|
||||
};
|
||||
|
||||
const res = await client.sendRequest(req);
|
||||
const subscriptionList: any[] = (<any>res.parsedBody).value;
|
||||
subscriptions = subscriptions.concat(subscriptionList.map((s: any) => {
|
||||
s.tenantId = tenant;
|
||||
s.user = { name: username, type: userType };
|
||||
s.environmentName = credentials.environment.name;
|
||||
s.name = s.displayName;
|
||||
s.id = s.subscriptionId;
|
||||
delete s.displayName;
|
||||
delete s.subscriptionId;
|
||||
delete s.subscriptionPolicies;
|
||||
return s;
|
||||
}));
|
||||
subscriptions = subscriptions.concat(
|
||||
subscriptionList.map((s: any) => {
|
||||
s.tenantId = tenant;
|
||||
s.user = { name: username, type: userType };
|
||||
s.environmentName = credentials.environment.name;
|
||||
s.name = s.displayName;
|
||||
s.id = s.subscriptionId;
|
||||
delete s.displayName;
|
||||
delete s.subscriptionId;
|
||||
delete s.subscriptionPolicies;
|
||||
return s;
|
||||
})
|
||||
);
|
||||
}
|
||||
// Reset the original domain.
|
||||
credentials.domain = originalDomain;
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
export const AuthConstants = {
|
||||
"AAD_COMMON_TENANT": "common",
|
||||
"DEFAULT_ADAL_CLIENT_ID": "04b07795-8ddb-461a-bbee-02f9e1bf7b46",
|
||||
"SDK_INTERNAL_ERROR": "SDK_INTERNAL_ERROR",
|
||||
"DEFAULT_LANGUAGE": "en-us",
|
||||
"AZURE_AUTH_LOCATION": "AZURE_AUTH_LOCATION",
|
||||
"RESOURCE_MANAGER_ENDPOINT": "https://management.azure.com/"
|
||||
AAD_COMMON_TENANT: "common",
|
||||
DEFAULT_ADAL_CLIENT_ID: "04b07795-8ddb-461a-bbee-02f9e1bf7b46",
|
||||
SDK_INTERNAL_ERROR: "SDK_INTERNAL_ERROR",
|
||||
DEFAULT_LANGUAGE: "en-us",
|
||||
AZURE_AUTH_LOCATION: "AZURE_AUTH_LOCATION",
|
||||
RESOURCE_MANAGER_ENDPOINT: "https://management.azure.com/"
|
||||
};
|
||||
|
||||
export type TokenAudience = "graph" | "batch" | string | undefined;
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
"nock": "^10.0.6",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"nyc": "^14.1.1",
|
||||
"prettier": "2.2.1",
|
||||
"rollup": "^1.18.0",
|
||||
"rollup-plugin-sourcemaps": "^0.4.2",
|
||||
"ts-node": "^8.3.0",
|
||||
|
@ -64,10 +65,11 @@
|
|||
"build": "run-s build:tsc build:rollup",
|
||||
"build:tsc": "tsc -p tsconfig.json",
|
||||
"build:rollup": "rollup -c rollup.config.js",
|
||||
"format": "prettier --write \"./**/*.ts\"",
|
||||
"prepack": "npm install && npm run build",
|
||||
"test": "npm run build && run-p test:tslint test:unit",
|
||||
"test:tslint": "tslint -p . -c tslint.json",
|
||||
"test:unit": "mocha",
|
||||
"check:packagejsonversion": "ts-node ./.scripts/checkPackageJsonVersion.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,16 +16,21 @@ async function listKeyVaultSecrets(creds: AzureCliCredentials): Promise<void> {
|
|||
try {
|
||||
console.log(">>>>>>> KeyVault <<<<<<<<<<<");
|
||||
const client = new ServiceClient(creds);
|
||||
console.log(">>> Subscription associated with the access token: '%s'.",
|
||||
creds.tokenInfo.subscription);
|
||||
console.log(
|
||||
">>> Subscription associated with the access token: '%s'.",
|
||||
creds.tokenInfo.subscription
|
||||
);
|
||||
const request: RequestPrepareOptions = {
|
||||
url: getKVUrl(keyvaultAccountName),
|
||||
method: "GET"
|
||||
};
|
||||
console.log(">>> Request url: '%s'.", request.url);
|
||||
const res = await client.sendRequest(request);
|
||||
console.log("List of secrets from keyvault account '%s': \n%O",
|
||||
keyvaultAccountName, res.parsedBody);
|
||||
console.log(
|
||||
"List of secrets from keyvault account '%s': \n%O",
|
||||
keyvaultAccountName,
|
||||
res.parsedBody
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
@ -40,29 +45,41 @@ async function listResourceGroups(creds: AzureCliCredentials): Promise<void> {
|
|||
// Setting the resource to ARM endpoint.
|
||||
creds.resource = "https://management.azure.com";
|
||||
const client = new ServiceClient(creds);
|
||||
console.log(">>> Subscription associated with the access token: '%s'.",
|
||||
creds.tokenInfo.subscription);
|
||||
console.log(
|
||||
">>> Subscription associated with the access token: '%s'.",
|
||||
creds.tokenInfo.subscription
|
||||
);
|
||||
const request: RequestPrepareOptions = {
|
||||
url: getUrl(creds.subscriptionInfo.id),
|
||||
method: "GET"
|
||||
};
|
||||
console.log(">>> Request url: '%s'.", request.url);
|
||||
const res = await client.sendRequest(request);
|
||||
console.log("List of resource groups from subscriptionId '%s': \n%O",
|
||||
creds.subscriptionInfo.id, res.parsedBody);
|
||||
console.log(
|
||||
"List of resource groups from subscriptionId '%s': \n%O",
|
||||
creds.subscriptionInfo.id,
|
||||
res.parsedBody
|
||||
);
|
||||
|
||||
// Let us change the subscriptionId, which should trigger refreshing the access token.
|
||||
const subscriptions = await AzureCliCredentials.listAllSubscriptions();
|
||||
creds.subscriptionInfo = subscriptions[1];
|
||||
console.log(">>> The new subscription id associated with the credential object is: '%s'.",
|
||||
creds.subscriptionInfo.id);
|
||||
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);
|
||||
const res2 = await client.sendRequest(request);
|
||||
console.log("List of resource groups from subscriptionId '%s': \n%O",
|
||||
creds.subscriptionInfo.id, res2.parsedBody);
|
||||
console.log(">>> Subscription associated with the access token: '%s'.",
|
||||
creds.tokenInfo.subscription);
|
||||
console.log(
|
||||
"List of resource groups from subscriptionId '%s': \n%O",
|
||||
creds.subscriptionInfo.id,
|
||||
res2.parsedBody
|
||||
);
|
||||
console.log(
|
||||
">>> Subscription associated with the access token: '%s'.",
|
||||
creds.tokenInfo.subscription
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
@ -74,4 +91,4 @@ async function main() {
|
|||
await listResourceGroups(creds);
|
||||
}
|
||||
|
||||
main();
|
||||
main();
|
||||
|
|
|
@ -33,9 +33,7 @@ ${e}
|
|||
}
|
||||
|
||||
// To get the tenants for your account, you can use the buildTenantList method:
|
||||
const tenants = await msRestNodeAuth.buildTenantList(
|
||||
authResponse.credentials
|
||||
);
|
||||
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]);
|
||||
|
|
|
@ -7,7 +7,6 @@ import { expect, assert } from "chai";
|
|||
import { WebResource, HttpHeaders, HttpClient, HttpOperationResponse } from "@azure/ms-rest-js";
|
||||
|
||||
describe("MSI App Service Authentication", function () {
|
||||
|
||||
function getMockHttpClient(response?: any, error?: any): HttpClient {
|
||||
const httpClient = {
|
||||
sendRequest: async (request: WebResource): Promise<HttpOperationResponse> => {
|
||||
|
@ -60,7 +59,6 @@ describe("MSI App Service Authentication", function () {
|
|||
token_type: "Bearer"
|
||||
};
|
||||
|
||||
|
||||
const httpClient = getMockHttpClient(mockResponse);
|
||||
process.env["MSI_ENDPOINT"] = "http://127.0.0.1:41741/MSI/token/";
|
||||
process.env["MSI_SECRET"] = "69418689F1E342DD946CB82994CDA3CB";
|
||||
|
@ -73,8 +71,9 @@ describe("MSI App Service Authentication", function () {
|
|||
|
||||
it('should throw if the response contains "ExceptionMessage"', async function () {
|
||||
const errorResponse = {
|
||||
"error": "unknown",
|
||||
"error_description": "ExceptionMessage: Failed to retrieve token from the Active directory. For details see logs in C:\\User1\\Logs\\Plugins\\Microsoft.Identity.MSI\\1.0\\service_identity_0.log"
|
||||
error: "unknown",
|
||||
error_description:
|
||||
"ExceptionMessage: Failed to retrieve token from the Active directory. For details see logs in C:\\User1\\Logs\\Plugins\\Microsoft.Identity.MSI\\1.0\\service_identity_0.log"
|
||||
};
|
||||
|
||||
const httpClient = getMockHttpClient(undefined, errorResponse);
|
||||
|
@ -84,15 +83,13 @@ describe("MSI App Service Authentication", function () {
|
|||
try {
|
||||
await msiCredsObj.getToken();
|
||||
assert.fail(undefined, undefined, "getToken should throw an exception");
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
expect(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("loginWithAppServiceMSI (callback)", () => {
|
||||
|
||||
it("should successfully provide MSIAppServiceTokenCredentials object by providing optional properties", (done) => {
|
||||
const mockResponse = {
|
||||
access_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1d",
|
||||
|
@ -139,8 +136,9 @@ describe("MSI App Service Authentication", function () {
|
|||
|
||||
it('should throw if the response contains "ExceptionMessage"', async () => {
|
||||
const errorResponse = {
|
||||
"error": "unknown",
|
||||
"error_description": "ExceptionMessage: Failed to retrieve token from the Active directory. For details see logs in C:\\User1\\Logs\\Plugins\\Microsoft.Identity.MSI\\1.0\\service_identity_0.log"
|
||||
error: "unknown",
|
||||
error_description:
|
||||
"ExceptionMessage: Failed to retrieve token from the Active directory. For details see logs in C:\\User1\\Logs\\Plugins\\Microsoft.Identity.MSI\\1.0\\service_identity_0.log"
|
||||
};
|
||||
|
||||
const httpClient = getMockHttpClient(undefined, errorResponse);
|
||||
|
@ -155,4 +153,4 @@ describe("MSI App Service Authentication", function () {
|
|||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,14 +6,23 @@ import { expect, assert } from "chai";
|
|||
import { HttpClient, HttpOperationResponse, WebResource, HttpHeaders } from "@azure/ms-rest-js";
|
||||
|
||||
describe("MSI Vm Authentication", () => {
|
||||
|
||||
function setupNockResponse(msiEndpoint?: string, expectedRequestHeaders?: any, response?: any, error?: any): HttpClient {
|
||||
function setupNockResponse(
|
||||
msiEndpoint?: string,
|
||||
expectedRequestHeaders?: any,
|
||||
response?: any,
|
||||
error?: any
|
||||
): HttpClient {
|
||||
if (!msiEndpoint) {
|
||||
msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token";
|
||||
}
|
||||
|
||||
const isMatch = (actualRequest: WebResource, expectedRequestHeaders: any) => {
|
||||
return actualRequest.url === `${msiEndpoint}?api-version=${expectedRequestHeaders.apiVersion}&resource=${encodeURIComponent(expectedRequestHeaders.resource)}`;
|
||||
return (
|
||||
actualRequest.url ===
|
||||
`${msiEndpoint}?api-version=${
|
||||
expectedRequestHeaders.apiVersion
|
||||
}&resource=${encodeURIComponent(expectedRequestHeaders.resource)}`
|
||||
);
|
||||
};
|
||||
|
||||
const httpClient = {
|
||||
|
@ -47,8 +56,8 @@ describe("MSI Vm Authentication", () => {
|
|||
};
|
||||
|
||||
const expectedQuery = {
|
||||
"apiVersion": "2018-02-01",
|
||||
"resource": "https://management.azure.com/"
|
||||
apiVersion: "2018-02-01",
|
||||
resource: "https://management.azure.com/"
|
||||
};
|
||||
|
||||
const httpClient = setupNockResponse(undefined, expectedQuery, mockResponse);
|
||||
|
@ -72,13 +81,16 @@ describe("MSI Vm Authentication", () => {
|
|||
};
|
||||
|
||||
const expectedQuery = {
|
||||
"apiVersion": "2018-02-01",
|
||||
"resource": "https://management.azure.com/"
|
||||
apiVersion: "2018-02-01",
|
||||
resource: "https://management.azure.com/"
|
||||
};
|
||||
const customMsiEndpoint = "http://localhost:50342/oauth2/token";
|
||||
const httpClient = setupNockResponse(customMsiEndpoint, expectedQuery, mockResponse);
|
||||
|
||||
const msiCredsObj = new MSIVmTokenCredentials({ msiEndpoint: customMsiEndpoint, httpClient: httpClient });
|
||||
const msiCredsObj = new MSIVmTokenCredentials({
|
||||
msiEndpoint: customMsiEndpoint,
|
||||
httpClient: httpClient
|
||||
});
|
||||
const response = await msiCredsObj.getToken();
|
||||
expect(response).to.exist;
|
||||
expect(response!.accessToken).to.exist;
|
||||
|
@ -87,18 +99,19 @@ describe("MSI Vm Authentication", () => {
|
|||
|
||||
it("should throw on requests with bad resource", async () => {
|
||||
const errorMessage = "unknown";
|
||||
const errorDescription = "Failed to retrieve token from the Active directory. For details see logs in C:\\User1\\Logs\\Plugins\\Microsoft.Identity.MSI\\1.0\\service_identity_0.log";
|
||||
const errorDescription =
|
||||
"Failed to retrieve token from the Active directory. For details see logs in C:\\User1\\Logs\\Plugins\\Microsoft.Identity.MSI\\1.0\\service_identity_0.log";
|
||||
const errorResponse = {
|
||||
"error": errorMessage,
|
||||
"error_description": errorDescription
|
||||
error: errorMessage,
|
||||
error_description: errorDescription
|
||||
};
|
||||
|
||||
const requestBodyToMatch = {
|
||||
"resource": "badvalue"
|
||||
resource: "badvalue"
|
||||
};
|
||||
|
||||
const httpClient = setupNockResponse(undefined, requestBodyToMatch, undefined, errorResponse);
|
||||
const msiCredsObj = new MSIVmTokenCredentials({ "resource": "badvalue", httpClient: httpClient });
|
||||
const msiCredsObj = new MSIVmTokenCredentials({ resource: "badvalue", httpClient: httpClient });
|
||||
|
||||
try {
|
||||
await msiCredsObj.getToken();
|
||||
|
@ -114,16 +127,16 @@ describe("MSI Vm Authentication", () => {
|
|||
const errorMessage = "bad_resource_200";
|
||||
const errorDescription = "Invalid Resource";
|
||||
const errorResponse = {
|
||||
"error": errorMessage,
|
||||
"error_description": errorDescription
|
||||
error: errorMessage,
|
||||
error_description: errorDescription
|
||||
};
|
||||
|
||||
const requestBodyToMatch = {
|
||||
"resource": " "
|
||||
resource: " "
|
||||
};
|
||||
|
||||
const httpClient = setupNockResponse(undefined, requestBodyToMatch, undefined, errorResponse);
|
||||
const msiCredsObj = new MSIVmTokenCredentials({ "resource": " ", httpClient: httpClient });
|
||||
const msiCredsObj = new MSIVmTokenCredentials({ resource: " ", httpClient: httpClient });
|
||||
|
||||
try {
|
||||
await msiCredsObj.getToken();
|
||||
|
|
Загрузка…
Ссылка в новой задаче