initial commit
This commit is contained in:
Родитель
f7fab73679
Коммит
aa74328046
|
@ -0,0 +1,37 @@
|
|||
*.bmp binary
|
||||
*.dll binary
|
||||
*.gif binary
|
||||
*.jpg binary
|
||||
*.png binary
|
||||
*.snk binary
|
||||
*.exe binary
|
||||
*.wmv binary
|
||||
*.mp4 binary
|
||||
*.ismv binary
|
||||
*.isma binary
|
||||
|
||||
*.ascx text
|
||||
*.cmd text
|
||||
*.config text
|
||||
*.cs text diff=csharp
|
||||
*.csproj text merge=union
|
||||
*.edmx text
|
||||
|
||||
*.htm text
|
||||
*.html text
|
||||
|
||||
*.json text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.js text eol=lf
|
||||
|
||||
*.msbuild text
|
||||
*.nuspec text
|
||||
|
||||
*.resx text
|
||||
*.ruleset text
|
||||
*.StyleCop text
|
||||
*.targets text
|
||||
*.txt text
|
||||
*.xml text
|
||||
|
||||
*.sln text eol=crlf merge=union
|
|
@ -0,0 +1,7 @@
|
|||
.vscode/
|
||||
node_modules/
|
||||
samples/
|
||||
test/
|
||||
.travis.yml
|
||||
gulpfile.js
|
||||
.gitignore
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible Node.js debug attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceRoot}/lib/azureEnvironment.ts",
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/dist/**/*.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
"**/.DS_Store": true
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.detectIndentation": false
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.detectIndentation": false
|
||||
}
|
||||
}
|
12
README.md
12
README.md
|
@ -1,5 +1,15 @@
|
|||
### Purpose
|
||||
|
||||
# Contributing
|
||||
This package provides a mechanism to access the Azure Endpoints in different Azure clouds. It also provides a mechanism to add a custom environment.
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
import * as msRestNodeAuth from "ms-rest-nodeauth";
|
||||
|
||||
```
|
||||
|
||||
### Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const TokenCredentialsBase_1 = require("./TokenCredentialsBase");
|
||||
const authConstants_1 = require("../util/authConstants");
|
||||
class ApplicationTokenCredentials extends TokenCredentialsBase_1.TokenCredentialsBase {
|
||||
/**
|
||||
* Creates a new ApplicationTokenCredentials object.
|
||||
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
|
||||
* for detailed instructions on creating an Azure Active Directory application.
|
||||
* @constructor
|
||||
* @param {string} clientId The active directory application client id.
|
||||
* @param {string} domain The domain or tenant id containing this application.
|
||||
* @param {string} secret The authentication secret for the application.
|
||||
* @param {string} [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 {AzureEnvironment} [environment] The azure environment to authenticate with.
|
||||
* @param {object} [tokenCache] The token cache. Default value is the MemoryCache object from adal.
|
||||
*/
|
||||
constructor(clientId, domain, secret, tokenAudience, environment, tokenCache) {
|
||||
if (!Boolean(secret) || typeof secret.valueOf() !== 'string') {
|
||||
throw new Error('secret must be a non empty string.');
|
||||
}
|
||||
super(clientId, domain, tokenAudience, environment, tokenCache);
|
||||
this.secret = secret;
|
||||
}
|
||||
/**
|
||||
* Tries to get the token from cache initially. If that is unsuccessfull then it tries to get the token from ADAL.
|
||||
* @returns {Promise<TokenResponse>} A promise that resolves to TokenResponse and rejects with an Error.
|
||||
*/
|
||||
getToken() {
|
||||
return this.getTokenFromCache()
|
||||
.then((tokenResponse) => tokenResponse)
|
||||
.catch((error) => {
|
||||
if (error.message.startsWith(authConstants_1.AuthConstants.SDK_INTERNAL_ERROR)) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
const resource = this.getActiveDirectoryResourceId();
|
||||
return new Promise((resolve, reject) => {
|
||||
this.authContext.acquireTokenWithClientCredentials(resource, this.clientId, this.secret, (error, tokenResponse) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return resolve(tokenResponse);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
getTokenFromCache() {
|
||||
const self = this;
|
||||
// a thin wrapper over the base implementation. try get token from cache, additionaly clean up cache if required.
|
||||
return super.getTokenFromCache(undefined)
|
||||
.then((tokenResponse) => { return Promise.resolve(tokenResponse); })
|
||||
.catch((error) => {
|
||||
// Remove the stale token from the tokencache. ADAL gives the same error message "Entry not found in cache."
|
||||
// for entry not being present in the cache and for accessToken being expired in the cache. We do not want the token cache
|
||||
// to contain the expired token, we clean it up here.
|
||||
self.removeInvalidItemsFromCache({ _clientId: self.clientId })
|
||||
.then(() => Promise.reject(error))
|
||||
.catch((reason) => {
|
||||
return Promise.reject(new Error(authConstants_1.AuthConstants.SDK_INTERNAL_ERROR + " : "
|
||||
+ "critical failure while removing expired token for service principal from token cache. "
|
||||
+ reason.message));
|
||||
});
|
||||
});
|
||||
}
|
||||
removeInvalidItemsFromCache(query) {
|
||||
const self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
self.tokenCache.find(query, (error, entries) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
if (entries && entries.length > 0) {
|
||||
return resolve(self.tokenCache.remove(entries, () => resolve(true)));
|
||||
}
|
||||
else {
|
||||
return resolve(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.ApplicationTokenCredentials = ApplicationTokenCredentials;
|
||||
//# sourceMappingURL=applicationTokenCredentials.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"applicationTokenCredentials.js","sourceRoot":"","sources":["../../../lib/credentials/applicationTokenCredentials.ts"],"names":[],"mappings":"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"}
|
|
@ -0,0 +1,45 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tokenCredentialsBase_1 = require("./tokenCredentialsBase");
|
||||
const authConstants_1 = require("../util/authConstants");
|
||||
class DeviceTokenCredentials extends tokenCredentialsBase_1.TokenCredentialsBase {
|
||||
/**
|
||||
* Creates a new DeviceTokenCredentials object that gets a new access token using userCodeInfo (contains user_code, device_code)
|
||||
* for authenticating user on device.
|
||||
*
|
||||
* When this credential is used, the script will provide a url and code. The user needs to copy the url and the code, paste it
|
||||
* in a browser and authenticate over there. If successful, the script will get the access token.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} [clientId] The active directory application client id.
|
||||
* @param {string} [domain] The domain or tenant id containing this application. Default value is 'common'
|
||||
* @param {string} [username] The user name for account in the form: 'user@example.com'.
|
||||
* @param {string} [tokenAudience] The audience for which the token is requested. Valid value is 'graph'. If tokenAudience is provided
|
||||
* 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).
|
||||
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
|
||||
* for an example.
|
||||
* @param {AzureEnvironment} [environment] The azure environment to authenticate with. Default environment is "Azure" popularly known as "Public Azure Cloud".
|
||||
* @param {object} [tokenCache] The token cache. Default value is the MemoryCache object from adal.
|
||||
*/
|
||||
constructor(clientId, domain, userName, tokenAudience, environment, tokenCache) {
|
||||
if (!userName) {
|
||||
userName = "user@example.com";
|
||||
}
|
||||
if (!domain) {
|
||||
domain = authConstants_1.AuthConstants.AAD_COMMON_TENANT;
|
||||
}
|
||||
if (!clientId) {
|
||||
clientId = authConstants_1.AuthConstants.DEFAULT_ADAL_CLIENT_ID;
|
||||
}
|
||||
super(clientId, domain, tokenAudience, environment, tokenCache);
|
||||
this.userName = userName;
|
||||
}
|
||||
getToken() {
|
||||
// For device auth, this is just getTokenFromCache.
|
||||
return this.getTokenFromCache(this.userName);
|
||||
}
|
||||
}
|
||||
exports.DeviceTokenCredentials = DeviceTokenCredentials;
|
||||
//# sourceMappingURL=deviceTokenCredentials.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"deviceTokenCredentials.js","sourceRoot":"","sources":["../../../lib/credentials/deviceTokenCredentials.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;AAE/F,iEAA6E;AAE7E,yDAAqE;AAErE,4BAAoC,SAAQ,2CAAoB;IAI9D;;;;;;;;;;;;;;;;;OAiBG;IACH,YACE,QAAiB,EACjB,MAAe,EACf,QAAiB,EACjB,aAA6B,EAC7B,WAA8B,EAC9B,UAAgB;QAEhB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YACd,QAAQ,GAAG,kBAAkB,CAAC;QAChC,CAAC;QAED,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,GAAG,6BAAa,CAAC,iBAAiB,CAAC;QAC3C,CAAC;QAED,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YACd,QAAQ,GAAG,6BAAa,CAAC,sBAAsB,CAAC;QAClD,CAAC;QAED,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,WAAkB,EAAE,UAAU,CAAC,CAAC;QAEvE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEM,QAAQ;QACb,mDAAmD;QACnD,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;CACF;AAnDD,wDAmDC"}
|
|
@ -0,0 +1,116 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const msRest = require("ms-rest-ts");
|
||||
/**
|
||||
* @class MSITokenCredentials - Provides information about managed service identity token credentials.
|
||||
* This object can only be used to acquire token on a virtual machine provisioned in Azure with managed service identity.
|
||||
*/
|
||||
class MSITokenCredentials {
|
||||
constructor(
|
||||
/**
|
||||
* @property {string} domain - The domain or tenant id for which the token is required.
|
||||
*/
|
||||
domain,
|
||||
/**
|
||||
* @property {number} port - Port on which the MSI service is running on the host VM. Default port is 50342
|
||||
*/
|
||||
port = 50342,
|
||||
/**
|
||||
* @property {string} resource - The resource uri or token audience for which the token is needed.
|
||||
* For e.g. it can be:
|
||||
* - resourcemanagement endpoint "https://management.azure.com"(default)
|
||||
* - management endpoint "https://management.core.windows.net/"
|
||||
*/
|
||||
resource = "https://management.azure.com",
|
||||
/**
|
||||
* @property {string} aadEndpoint - The add endpoint for authentication. default - "https://login.microsoftonline.com"
|
||||
*/
|
||||
aadEndpoint = "https://login.microsoftonline.com") {
|
||||
this.domain = domain;
|
||||
this.port = port;
|
||||
this.resource = resource;
|
||||
this.aadEndpoint = aadEndpoint;
|
||||
if (!Boolean(domain) || typeof domain.valueOf() !== 'string') {
|
||||
throw new TypeError('domain must be a non empty string.');
|
||||
}
|
||||
if (typeof port.valueOf() !== 'number') {
|
||||
throw new Error('port must be a number.');
|
||||
}
|
||||
if (typeof resource.valueOf() !== 'string') {
|
||||
throw new Error('resource must be a uri of type string.');
|
||||
}
|
||||
if (typeof aadEndpoint.valueOf() !== 'string') {
|
||||
throw new Error('aadEndpoint must be a uri of type string.');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Prepares and sends a POST request to a service endpoint hosted on the Azure VM, which responds with the access token.
|
||||
* @param {function} callback The callback in the form (err, result)
|
||||
* @return {function} callback
|
||||
* {Error} [err] The error if any
|
||||
* {object} [tokenResponse] The tokenResponse (token_type and access_token are the two important properties).
|
||||
*/
|
||||
getToken() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const reqOptions = this.prepareRequestOptions();
|
||||
let client = new msRest.ServiceClient();
|
||||
let opRes;
|
||||
let result;
|
||||
try {
|
||||
opRes = yield client.sendRequest(reqOptions);
|
||||
result = opRes.bodyAsJson;
|
||||
if (!result.token_type) {
|
||||
throw new Error(`Invalid token response, did not find token_type. Response body is: ${opRes.bodyAsText}`);
|
||||
}
|
||||
else if (!result.access_token) {
|
||||
throw new Error(`Invalid token response, did not find access_token. Response body is: ${opRes.bodyAsText}`);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
});
|
||||
}
|
||||
prepareRequestOptions() {
|
||||
const resource = encodeURIComponent(this.resource);
|
||||
const aadEndpoint = encodeURIComponent(this.aadEndpoint);
|
||||
const forwardSlash = encodeURIComponent('/');
|
||||
let reqOptions = {
|
||||
url: `http://localhost:${this.port}/oauth2/token`,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"Metadata": "true"
|
||||
},
|
||||
body: `authority=${aadEndpoint}${forwardSlash}${this.domain}&resource=${resource}`,
|
||||
method: "POST"
|
||||
};
|
||||
return reqOptions;
|
||||
}
|
||||
/**
|
||||
* Signs a request with the Authentication header.
|
||||
*
|
||||
* @param {webResource} The WebResource to be signed.
|
||||
* @param {function(error)} callback The callback function.
|
||||
* @return {undefined}
|
||||
*/
|
||||
signRequest(webResource) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const tokenResponse = yield this.getToken();
|
||||
webResource.headers[msRest.Constants.HeaderConstants.AUTHORIZATION] = `${tokenResponse.tokenType} ${tokenResponse.accessToken}`;
|
||||
return Promise.resolve(webResource);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.MSITokenCredentials = MSITokenCredentials;
|
||||
//# sourceMappingURL=msiTokenCredentials.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"msiTokenCredentials.js","sourceRoot":"","sources":["../../../lib/credentials/msiTokenCredentials.ts"],"names":[],"mappings":"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"}
|
|
@ -0,0 +1,67 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ms_rest_ts_1 = require("ms-rest-ts");
|
||||
const ms_rest_azure_env_1 = require("ms-rest-azure-env");
|
||||
const authConstants_1 = require("../util/authConstants");
|
||||
const adal = require("adal-node");
|
||||
class TokenCredentialsBase {
|
||||
constructor(clientId, domain, tokenAudience, environment = ms_rest_azure_env_1.AzureEnvironment.Azure, tokenCache = new adal.MemoryCache()) {
|
||||
this.clientId = clientId;
|
||||
this.domain = domain;
|
||||
this.tokenAudience = tokenAudience;
|
||||
this.environment = environment;
|
||||
this.tokenCache = tokenCache;
|
||||
if (!Boolean(clientId) || typeof clientId.valueOf() !== 'string') {
|
||||
throw new Error('clientId must be a non empty string.');
|
||||
}
|
||||
if (!Boolean(domain) || typeof domain.valueOf() !== 'string') {
|
||||
throw new Error('domain must be a non empty string.');
|
||||
}
|
||||
if (this.tokenAudience === authConstants_1.TokenAudience.graph) {
|
||||
this.isGraphContext = true;
|
||||
if (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)."}`);
|
||||
}
|
||||
}
|
||||
const authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
|
||||
this.authContext = new adal.AuthenticationContext(authorityUrl, this.environment.validateAuthority, this.tokenCache);
|
||||
}
|
||||
getActiveDirectoryResourceId() {
|
||||
const resource = this.isGraphContext
|
||||
? this.environment.activeDirectoryGraphResourceId
|
||||
: this.environment.activeDirectoryResourceId;
|
||||
return resource;
|
||||
}
|
||||
getTokenFromCache(userName) {
|
||||
const self = this;
|
||||
const resource = this.getActiveDirectoryResourceId();
|
||||
return new Promise((resolve, reject) => {
|
||||
self.authContext.acquireToken(resource, userName, self.clientId, (error, tokenResponse) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return resolve(tokenResponse);
|
||||
});
|
||||
});
|
||||
}
|
||||
signRequest(webResource) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const tokenResponse = yield this.getToken();
|
||||
webResource.headers[ms_rest_ts_1.Constants.HeaderConstants.AUTHORIZATION] = `${tokenResponse.tokenType} ${tokenResponse.accessToken}`;
|
||||
return Promise.resolve(webResource);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.TokenCredentialsBase = TokenCredentialsBase;
|
||||
//# sourceMappingURL=tokenCredentialsBase.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"tokenCredentialsBase.js","sourceRoot":"","sources":["../../../lib/credentials/tokenCredentialsBase.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;;;;;;;;;AAE/F,2CAAuE;AACvE,yDAAqD;AACrD,yDAAsD;AACtD,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAQlC;IAIE,YACkB,QAAgB,EACzB,MAAc,EACL,aAA6B,EAC7B,cAAc,oCAAgB,CAAC,KAAK,EAC7C,aAAkB,IAAI,IAAI,CAAC,WAAW,EAAE;QAJ/B,aAAQ,GAAR,QAAQ,CAAQ;QACzB,WAAM,GAAN,MAAM,CAAQ;QACL,kBAAa,GAAb,aAAa,CAAgB;QAC7B,gBAAW,GAAX,WAAW,CAAyB;QAC7C,eAAU,GAAV,UAAU,CAA8B;QAE/C,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,KAAK,6BAAa,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAE3B,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC;gBAC3C,MAAM,IAAI,KAAK,CAAC,GAAG;gFACqD,EAAE,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,0BAA0B,GAAG,IAAI,CAAC,MAAM,CAAC;QAC/E,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,qBAAqB,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACvH,CAAC;IAES,4BAA4B;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc;cAChC,IAAI,CAAC,WAAW,CAAC,8BAA8B;cAC/C,IAAI,CAAC,WAAW,CAAC,yBAAyB,CAAC;QAE/C,MAAM,CAAC,QAAQ,CAAC;IAClB,CAAC;IAES,iBAAiB,CAAC,QAAiB;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,4BAA4B,EAAE,CAAC;QAErD,MAAM,CAAC,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,MAAM;YAChD,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAY,EAAE,aAA4B;gBAC1G,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;oBACV,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvB,CAAC;gBACD,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAIY,WAAW,CAAC,WAAwB;;YAC/C,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,WAAW,CAAC,OAAO,CAAC,sBAAe,CAAC,eAAe,CAAC,aAAa,CAAC,GAAG,GAAG,aAAa,CAAC,SAAS,IAAI,aAAa,CAAC,WAAW,EAAE,CAAC;YAC/H,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACtC,CAAC;KAAA;CACF;AA7DD,oDA6DC"}
|
|
@ -0,0 +1,84 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tokenCredentialsBase_1 = require("./tokenCredentialsBase");
|
||||
class UserTokenCredentials extends tokenCredentialsBase_1.TokenCredentialsBase {
|
||||
/**
|
||||
* Creates a new UserTokenCredentials object.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} 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} domain The domain or tenant id containing this application.
|
||||
* @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 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 {AzureEnvironment} [environment] The azure environment to authenticate with.
|
||||
* @param {object} [tokenCache] The token cache. Default value is the MemoryCache object from adal.
|
||||
*/
|
||||
constructor(clientId, domain, username, password, tokenAudience, environment, tokenCache) {
|
||||
if (!Boolean(clientId) || typeof clientId.valueOf() !== 'string') {
|
||||
throw new Error('clientId must be a non empty string.');
|
||||
}
|
||||
if (!Boolean(domain) || typeof domain.valueOf() !== 'string') {
|
||||
throw new Error('domain must be a non empty string.');
|
||||
}
|
||||
if (!Boolean(username) || typeof username.valueOf() !== 'string') {
|
||||
throw new Error('username must be a non empty string.');
|
||||
}
|
||||
if (!Boolean(password) || typeof password.valueOf() !== 'string') {
|
||||
throw new Error('password must be a non empty string.');
|
||||
}
|
||||
super(clientId, domain, tokenAudience, environment, tokenCache);
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
crossCheckUserNameWithToken(username, userIdFromToken) {
|
||||
//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());
|
||||
}
|
||||
/**
|
||||
* Tries to get the token from cache initially. If that is unsuccessful then it tries to get the token from ADAL.
|
||||
* @returns {Promise<any>}
|
||||
* {object} [tokenResponse] The tokenResponse (tokenType and accessToken are the two important properties).
|
||||
* @memberof UserTokenCredentials
|
||||
*/
|
||||
getToken() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
return this.getTokenFromCache(this.username);
|
||||
}
|
||||
catch (error) {
|
||||
const self = this;
|
||||
const resource = this.getActiveDirectoryResourceId();
|
||||
return new Promise((resolve, reject) => {
|
||||
self.authContext.acquireTokenWithUsernamePassword(resource, self.username, self.password, self.clientId, (error, tokenResponse) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
if (self.crossCheckUserNameWithToken(self.username, tokenResponse.userId)) {
|
||||
resolve(tokenResponse);
|
||||
}
|
||||
else {
|
||||
reject(`The userId "${tokenResponse.userId}" in access token doesn't match the username "${self.username}" provided during authentication.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.UserTokenCredentials = UserTokenCredentials;
|
||||
//# sourceMappingURL=userTokenCredentials.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"userTokenCredentials.js","sourceRoot":"","sources":["../../../lib/credentials/userTokenCredentials.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;;;;;;;;;AAE/F,iEAA6E;AAI7E,0BAAkC,SAAQ,2CAAoB;IAK5D;;;;;;;;;;;;;;OAcG;IACH,YACE,QAAgB,EAChB,MAAc,EACd,QAAgB,EAChB,QAAgB,EAChB,aAA6B,EAC7B,WAA8B,EAC9B,UAAgB;QAEhB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,WAAkB,EAAE,UAAU,CAAC,CAAC;QAEvE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEO,2BAA2B,CAAC,QAAgB,EAAE,eAAuB;QAC3E,8FAA8F;QAC9F,oFAAoF;QACpF,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,WAAW,EAAE,CAAC,CAAC;IACpE,CAAC;IAED;;;;;OAKG;IACU,QAAQ;;YACnB,IAAI,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC/C,CAAC;YAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gBAEf,MAAM,IAAI,GAAG,IAAI,CAAC;gBAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,4BAA4B,EAAE,CAAC;gBAErD,MAAM,CAAC,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,MAAM;oBAChD,IAAI,CAAC,WAAW,CAAC,gCAAgC,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACrG,CAAC,KAAY,EAAE,aAA4B;wBACzC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;4BACV,MAAM,CAAC,KAAK,CAAC,CAAC;wBAChB,CAAC;wBACD,EAAE,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;4BAC1E,OAAO,CAAE,aAA+B,CAAC,CAAC;wBAC5C,CAAC;wBAAC,IAAI,CAAC,CAAC;4BACN,MAAM,CAAC,eAAe,aAAa,CAAC,MAAM,iDAAiD,IAAI,CAAC,QAAQ,mCAAmC,CAAC,CAAC;wBAC/I,CAAC;oBACH,CAAC,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;KAAA;CACF;AAtFD,oDAsFC"}
|
|
@ -0,0 +1,410 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const adal = require("adal");
|
||||
const fs = require("fs");
|
||||
const msRest = require("ms-rest-ts");
|
||||
const ms_rest_azure_env_1 = require("ms-rest-azure-env");
|
||||
const applicationTokenCredentials_1 = require("./credentials/applicationTokenCredentials");
|
||||
const deviceTokenCredentials_1 = require("./credentials/deviceTokenCredentials");
|
||||
const userTokenCredentials_1 = require("./credentials/userTokenCredentials");
|
||||
const authConstants_1 = require("./util/authConstants");
|
||||
const subscriptionUtils_1 = require("./subscriptionManagement/subscriptionUtils");
|
||||
const msiTokenCredentials_1 = require("./credentials/msiTokenCredentials");
|
||||
function turnOnLogging() {
|
||||
let log = adal.Logging;
|
||||
log.setLoggingOptions({
|
||||
level: log.LOGGING_LEVEL.VERBOSE,
|
||||
log: function (level, message, error) {
|
||||
level;
|
||||
console.info(message);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (process.env['AZURE_ADAL_LOGGING_ENABLED']) {
|
||||
turnOnLogging();
|
||||
}
|
||||
function withUsernamePasswordWithAuthResponse(username, password, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options.clientId) {
|
||||
options.clientId = authConstants_1.AuthConstants.DEFAULT_ADAL_CLIENT_ID;
|
||||
}
|
||||
if (!options.domain) {
|
||||
options.domain = authConstants_1.AuthConstants.AAD_COMMON_TENANT;
|
||||
}
|
||||
let creds;
|
||||
let result;
|
||||
let tenantList = [];
|
||||
let subscriptionList = [];
|
||||
try {
|
||||
creds = new userTokenCredentials_1.UserTokenCredentials(options.clientId, options.domain, username, password, options.tokenAudience, options.environment);
|
||||
result = yield creds.getToken();
|
||||
// The token cache gets propulated for all the tenants as a part of building the tenantList.
|
||||
tenantList = yield subscriptionUtils_1.buildTenantList(creds);
|
||||
// We dont need to get the subscriptionList if the tokenAudience is graph as graph clients are tenant based.
|
||||
if (!(options.tokenAudience && options.tokenAudience === authConstants_1.TokenAudience.graph)) {
|
||||
subscriptionList = yield subscriptionUtils_1.getSubscriptionsFromTenants(creds, tenantList);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return Promise.resolve({ credentials: creds, subscriptions: subscriptionList });
|
||||
});
|
||||
}
|
||||
exports.withUsernamePasswordWithAuthResponse = withUsernamePasswordWithAuthResponse;
|
||||
function withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
let creds;
|
||||
let result;
|
||||
let subscriptionList = [];
|
||||
try {
|
||||
creds = new applicationTokenCredentials_1.ApplicationTokenCredentials(clientId, domain, secret, options.tokenAudience, options.environment);
|
||||
result = yield creds.getToken();
|
||||
// We dont need to get the subscriptionList if the tokenAudience is graph as graph clients are tenant based.
|
||||
if (!(options.tokenAudience && options.tokenAudience === authConstants_1.TokenAudience.graph)) {
|
||||
subscriptionList = yield subscriptionUtils_1.getSubscriptionsFromTenants(creds, [domain]);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return Promise.resolve({ credentials: creds, subscriptions: subscriptionList });
|
||||
});
|
||||
}
|
||||
exports.withServicePrincipalSecretWithAuthResponse = withServicePrincipalSecretWithAuthResponse;
|
||||
function validateAuthFileContent(credsObj, filePath) {
|
||||
if (!credsObj) {
|
||||
throw new Error('Please provide a credsObj to validate.');
|
||||
}
|
||||
if (!filePath) {
|
||||
throw new Error('Please provide a filePath.');
|
||||
}
|
||||
if (!credsObj.clientId) {
|
||||
throw new Error(`"clientId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.clientSecret) {
|
||||
throw new Error(`"clientSecret" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.subscriptionId) {
|
||||
throw new Error(`"subscriptionId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.tenantId) {
|
||||
throw new Error(`"tenantId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.activeDirectoryEndpointUrl) {
|
||||
throw new Error(`"activeDirectoryEndpointUrl" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.resourceManagerEndpointUrl) {
|
||||
throw new Error(`"resourceManagerEndpointUrl" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.activeDirectoryGraphResourceId) {
|
||||
throw new Error(`"activeDirectoryGraphResourceId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.sqlManagementEndpointUrl) {
|
||||
throw new Error(`"sqlManagementEndpointUrl" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
}
|
||||
function foundManagementEndpointUrl(authFileUrl, envUrl) {
|
||||
if (!authFileUrl || (authFileUrl && typeof authFileUrl.valueOf() !== 'string')) {
|
||||
throw new Error('authFileUrl cannot be null or undefined and must be of type string.');
|
||||
}
|
||||
if (!envUrl || (envUrl && typeof envUrl.valueOf() !== 'string')) {
|
||||
throw new Error('envUrl cannot be null or undefined and must be of type string.');
|
||||
}
|
||||
authFileUrl = authFileUrl.endsWith('/') ? authFileUrl.slice(0, -1) : authFileUrl;
|
||||
envUrl = envUrl.endsWith('/') ? envUrl.slice(0, -1) : envUrl;
|
||||
return (authFileUrl.toLowerCase() === envUrl.toLowerCase());
|
||||
}
|
||||
function withAuthFileWithAuthResponse(options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (!options)
|
||||
options = { filePath: '' };
|
||||
let filePath = options.filePath || process.env[authConstants_1.AuthConstants.AZURE_AUTH_LOCATION];
|
||||
let subscriptionEnvVariableName = options.subscriptionEnvVariableName || 'AZURE_SUBSCRIPTION_ID';
|
||||
if (!filePath) {
|
||||
let msg = `Either provide an absolute file path to the auth file or set/export the environment variable - ${authConstants_1.AuthConstants.AZURE_AUTH_LOCATION}.`;
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
let content, credsObj = {}, optionsForSpSecret = {};
|
||||
try {
|
||||
content = fs.readFileSync(filePath, { encoding: 'utf8' });
|
||||
credsObj = JSON.parse(content);
|
||||
validateAuthFileContent(credsObj, filePath);
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
if (!credsObj.managementEndpointUrl) {
|
||||
credsObj.managementEndpointUrl = credsObj.resourceManagerEndpointUrl;
|
||||
}
|
||||
//setting the subscriptionId from auth file to the environment variable
|
||||
process.env[subscriptionEnvVariableName] = credsObj.subscriptionId;
|
||||
//get the AzureEnvironment or create a new AzureEnvironment based on the info provided in the auth file
|
||||
let envFound = {
|
||||
name: ''
|
||||
};
|
||||
let envNames = Object.keys(Object.getPrototypeOf(ms_rest_azure_env_1.AzureEnvironment)).slice(1);
|
||||
for (let i = 0; i < envNames.length; i++) {
|
||||
let env = envNames[i];
|
||||
let environmentObj = ms_rest_azure_env_1.AzureEnvironment[env];
|
||||
if (environmentObj &&
|
||||
environmentObj.managementEndpointUrl &&
|
||||
foundManagementEndpointUrl(credsObj.managementEndpointUrl, environmentObj.managementEndpointUrl)) {
|
||||
envFound.name = environmentObj.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (envFound.name) {
|
||||
optionsForSpSecret.environment = ms_rest_azure_env_1.AzureEnvironment[envFound.name];
|
||||
}
|
||||
else {
|
||||
//create a new environment with provided info.
|
||||
let envParams = {
|
||||
//try to find a logical name or set the filepath as the env name.
|
||||
name: credsObj.managementEndpointUrl.match(/.*management\.core\.(.*)\..*/i)[1] || filePath
|
||||
};
|
||||
let keys = Object.keys(credsObj);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
if (key.match(/^(clientId|clientSecret|subscriptionId|tenantId)$/ig) === null) {
|
||||
if (key === 'activeDirectoryEndpointUrl' && !key.endsWith('/')) {
|
||||
envParams[key] = credsObj[key] + '/';
|
||||
}
|
||||
else {
|
||||
envParams[key] = credsObj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!envParams.activeDirectoryResourceId) {
|
||||
envParams.activeDirectoryResourceId = credsObj.managementEndpointUrl;
|
||||
}
|
||||
if (!envParams.portalUrl) {
|
||||
envParams.portalUrl = 'https://portal.azure.com';
|
||||
}
|
||||
optionsForSpSecret.environment = ms_rest_azure_env_1.AzureEnvironment.add(envParams);
|
||||
}
|
||||
return withServicePrincipalSecretWithAuthResponse(credsObj.clientId, credsObj.clientSecret, credsObj.tenantId, optionsForSpSecret);
|
||||
});
|
||||
}
|
||||
exports.withAuthFileWithAuthResponse = withAuthFileWithAuthResponse;
|
||||
function withInteractiveWithAuthResponse(options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options.environment) {
|
||||
options.environment = ms_rest_azure_env_1.AzureEnvironment.Azure;
|
||||
}
|
||||
if (!options.domain) {
|
||||
options.domain = authConstants_1.AuthConstants.AAD_COMMON_TENANT;
|
||||
}
|
||||
if (!options.clientId) {
|
||||
options.clientId = authConstants_1.AuthConstants.DEFAULT_ADAL_CLIENT_ID;
|
||||
}
|
||||
if (!options.tokenCache) {
|
||||
options.tokenCache = new adal.MemoryCache();
|
||||
}
|
||||
if (!options.language) {
|
||||
options.language = authConstants_1.AuthConstants.DEFAULT_LANGUAGE;
|
||||
}
|
||||
let interactiveOptions = {};
|
||||
interactiveOptions.tokenAudience = options.tokenAudience;
|
||||
interactiveOptions.environment = options.environment;
|
||||
interactiveOptions.domain = options.domain;
|
||||
interactiveOptions.clientId = options.clientId;
|
||||
interactiveOptions.tokenCache = options.tokenCache;
|
||||
interactiveOptions.language = options.language;
|
||||
interactiveOptions.userCodeResponseLogger = options.userCodeResponseLogger;
|
||||
let authorityUrl = interactiveOptions.environment.activeDirectoryEndpointUrl + interactiveOptions.domain;
|
||||
let authContext = new adal.AuthenticationContext(authorityUrl, interactiveOptions.environment.validateAuthority, interactiveOptions.tokenCache);
|
||||
interactiveOptions.context = authContext;
|
||||
let tenantList = [];
|
||||
let subscriptionList = [];
|
||||
let getUserCode = new Promise((resolve, reject) => {
|
||||
return authContext.acquireUserCode(interactiveOptions.environment.activeDirectoryResourceId, interactiveOptions.clientId, interactiveOptions.language, (err, userCodeResponse) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
if (interactiveOptions.userCodeResponseLogger) {
|
||||
interactiveOptions.userCodeResponseLogger(userCodeResponse.message);
|
||||
}
|
||||
else {
|
||||
console.log(userCodeResponse.message);
|
||||
}
|
||||
return resolve(userCodeResponse.message);
|
||||
});
|
||||
});
|
||||
return getUserCode.then((userCodeResponse) => {
|
||||
return authContext.acquireTokenWithDeviceCode(interactiveOptions.environment.activeDirectoryResourceId, interactiveOptions.clientId, userCodeResponse, (error, tokenResponse) => __awaiter(this, void 0, void 0, function* () {
|
||||
if (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
interactiveOptions.username = tokenResponse.userId;
|
||||
interactiveOptions.authorizationScheme = tokenResponse.tokenType;
|
||||
try {
|
||||
let creds = new deviceTokenCredentials_1.DeviceTokenCredentials(interactiveOptions.clientId, interactiveOptions.domain, interactiveOptions.userName, interactiveOptions.tokenAudience, interactiveOptions.environment, interactiveOptions.tokenCache);
|
||||
tenantList = yield subscriptionUtils_1.buildTenantList(creds);
|
||||
if (!(interactiveOptions.tokenAudience && interactiveOptions.tokenAudience === authConstants_1.TokenAudience.graph)) {
|
||||
subscriptionList = yield subscriptionUtils_1.getSubscriptionsFromTenants(creds, tenantList);
|
||||
}
|
||||
return Promise.resolve({ credentials: creds, subscriptions: subscriptionList });
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.withInteractiveWithAuthResponse = withInteractiveWithAuthResponse;
|
||||
function withAuthFile(options, callback) {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback;
|
||||
if (!callback) {
|
||||
return withAuthFileWithAuthResponse(options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
msRest.promiseToCallback(withAuthFileWithAuthResponse(options))((err, authRes) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.withAuthFile = withAuthFile;
|
||||
function interactive(options, callback) {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback;
|
||||
if (!callback) {
|
||||
return withInteractiveWithAuthResponse(options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
msRest.promiseToCallback(withInteractiveWithAuthResponse(options))((err, authRes) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.interactive = interactive;
|
||||
function withServicePrincipalSecret(clientId, secret, domain, options, callback) {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback;
|
||||
if (!callback) {
|
||||
return withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
msRest.promiseToCallback(withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options))((err, authRes) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.withServicePrincipalSecret = withServicePrincipalSecret;
|
||||
function withUsernamePassword(username, password, options, callback) {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback;
|
||||
if (!callback) {
|
||||
return withUsernamePasswordWithAuthResponse(username, password, options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
msRest.promiseToCallback(withUsernamePasswordWithAuthResponse(username, password, options))((err, authRes) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.withUsernamePassword = withUsernamePassword;
|
||||
/**
|
||||
* Initializes MSITokenCredentials class and calls getToken and returns a token response.
|
||||
*
|
||||
* @param {string} domain -- required. The tenant id.
|
||||
* @param {object} options -- Optional parameters
|
||||
* @param {string} [options.port] - port on which the MSI service is running on the host VM. Default port is 50342
|
||||
* @param {string} [options.resource] - The resource uri or token audience for which the token is needed. Default - "https://management.azure.com"
|
||||
* @param {string} [options.aadEndpoint] - The add endpoint for authentication. default - "https://login.microsoftonline.com"
|
||||
* @param {any} callback - the callback function.
|
||||
*/
|
||||
function _withMSI(domain, options) {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
const creds = new msiTokenCredentials_1.MSITokenCredentials(domain, options.port, options.resource, options.aadEndpoint);
|
||||
return creds.getToken();
|
||||
}
|
||||
function withMSI(domain, options, callback) {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
let cb = callback;
|
||||
if (!callback) {
|
||||
return _withMSI(domain, options);
|
||||
}
|
||||
else {
|
||||
msRest.promiseToCallback(_withMSI(domain, options))((err, tokenRes) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, tokenRes);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.withMSI = withMSI;
|
||||
//# sourceMappingURL=login.js.map
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,28 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tokenCredentialsBase_1 = require("./credentials/tokenCredentialsBase");
|
||||
exports.TokenCredentialsBase = tokenCredentialsBase_1.TokenCredentialsBase;
|
||||
const applicationTokenCredentials_1 = require("./credentials/applicationTokenCredentials");
|
||||
exports.ApplicationTokenCredentials = applicationTokenCredentials_1.ApplicationTokenCredentials;
|
||||
const deviceTokenCredentials_1 = require("./credentials/deviceTokenCredentials");
|
||||
exports.DeviceTokenCredentials = deviceTokenCredentials_1.DeviceTokenCredentials;
|
||||
const userTokenCredentials_1 = require("./credentials/userTokenCredentials");
|
||||
exports.UserTokenCredentials = userTokenCredentials_1.UserTokenCredentials;
|
||||
const msiTokenCredentials_1 = require("./credentials/msiTokenCredentials");
|
||||
exports.MSITokenCredentials = msiTokenCredentials_1.MSITokenCredentials;
|
||||
const authConstants_1 = require("./util/authConstants");
|
||||
exports.AuthConstants = authConstants_1.AuthConstants;
|
||||
exports.TokenAudience = authConstants_1.TokenAudience;
|
||||
const login_1 = require("./login");
|
||||
exports.interactiveLogin = login_1.interactive;
|
||||
exports.loginWithAuthFile = login_1.withAuthFile;
|
||||
exports.loginWithAuthFileWithAuthResponse = login_1.withAuthFileWithAuthResponse;
|
||||
exports.interactiveLoginWithAuthResponse = login_1.withInteractiveWithAuthResponse;
|
||||
exports.loginWithMSI = login_1.withMSI;
|
||||
exports.loginWithServicePrincipalSecret = login_1.withServicePrincipalSecret;
|
||||
exports.loginWithServicePrincipalSecretWithAuthResponse = login_1.withServicePrincipalSecretWithAuthResponse;
|
||||
exports.loginWithUsernamePassword = login_1.withUsernamePassword;
|
||||
exports.loginWithUsernamePasswordWithAuthResponse = login_1.withUsernamePasswordWithAuthResponse;
|
||||
//# sourceMappingURL=msRestNodeAuth.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"msRestNodeAuth.js","sourceRoot":"","sources":["../../lib/msRestNodeAuth.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;AAE/F,6EAAyF;AAgBvF,+BAhBO,2CAAoB,CAgBP;AAftB,2FAAwF;AAejD,sCAf9B,yDAA2B,CAe8B;AAdlE,iFAA8E;AAcV,iCAd3D,+CAAsB,CAc2D;AAb1F,6EAA0E;AAcxE,+BAdO,2CAAoB,CAcP;AAbtB,2EAA0F;AAalE,8BAbf,yCAAmB,CAae;AAZ3C,wDAAoE;AAYL,wBAZtD,6BAAa,CAYsD;AAAE,wBAZtD,6BAAa,CAYsD;AAV3F,mCAMiB;AAOA,2BAVf,mBAAW,CAUoB;AAMf,4BAhBH,oBAAY,CAgBQ;AACD,4CAjBL,oCAA4B,CAiBU;AAN9B,2CAXsB,uCAA+B,CAWrB;AAOxD,uBAjBX,eAAO,CAiBgB;AAJO,0CAbrB,kCAA0B,CAa0B;AACf,0DAdT,kDAA0C,CAcc;AAHrE,oCAVxB,4BAAoB,CAU6B;AACT,oDAXlB,4CAAoC,CAWuB"}
|
|
@ -0,0 +1,98 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const msRest = require("ms-rest-ts");
|
||||
const applicationTokenCredentials_1 = require("../credentials/applicationTokenCredentials");
|
||||
const authConstants_1 = require("../util/authConstants");
|
||||
/**
|
||||
* Builds an array of tenantIds.
|
||||
* @param {TokenCredentialsBase} credentials
|
||||
* @param {string} apiVersion default value 2016-06-01
|
||||
* @returns {Promise<string[]>} resolves to an array of tenantIds and rejects with an error.
|
||||
*/
|
||||
function buildTenantList(credentials, apiVersion = "2016-06-01") {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
if (credentials.domain && credentials.domain !== authConstants_1.AuthConstants.AAD_COMMON_TENANT) {
|
||||
return Promise.resolve([credentials.domain]);
|
||||
}
|
||||
let client = new msRest.ServiceClient(credentials);
|
||||
let baseUrl = credentials.environment.resourceManagerEndpointUrl;
|
||||
let reqUrl = `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}tenants?api-version=${apiVersion}`;
|
||||
let req = {
|
||||
url: reqUrl,
|
||||
method: "GET",
|
||||
};
|
||||
let res;
|
||||
try {
|
||||
res = yield client.sendRequest(req);
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
let result = [];
|
||||
let tenants = res.bodyAsJson;
|
||||
for (let tenant in tenants.value) {
|
||||
result.push(tenant.tenantId);
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
});
|
||||
}
|
||||
exports.buildTenantList = buildTenantList;
|
||||
function getSubscriptionsFromTenants(credentials, tenantList, apiVersion = "2016-06-01") {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let subscriptions = [];
|
||||
let userType = 'user';
|
||||
let username;
|
||||
let originalDomain = credentials.domain;
|
||||
if (credentials instanceof applicationTokenCredentials_1.ApplicationTokenCredentials) {
|
||||
userType = 'servicePrincipal';
|
||||
username = credentials.clientId;
|
||||
}
|
||||
else {
|
||||
username = credentials.username;
|
||||
}
|
||||
for (let tenant of tenantList) {
|
||||
credentials.domain = tenant;
|
||||
let client = new msRest.ServiceClient(credentials);
|
||||
let baseUrl = credentials.environment.resourceManagerEndpointUrl;
|
||||
let reqUrl = `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}subscriptions?api-version=${apiVersion}`;
|
||||
let req = {
|
||||
url: reqUrl,
|
||||
method: "GET",
|
||||
};
|
||||
let res;
|
||||
try {
|
||||
res = yield client.sendRequest(req);
|
||||
}
|
||||
catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
let subscriptionList = res.bodyAsJson.value;
|
||||
subscriptions = subscriptions.concat(subscriptionList.map((s) => {
|
||||
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;
|
||||
return Promise.resolve(subscriptions);
|
||||
});
|
||||
}
|
||||
exports.getSubscriptionsFromTenants = getSubscriptionsFromTenants;
|
||||
//# sourceMappingURL=subscriptionUtils.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"subscriptionUtils.js","sourceRoot":"","sources":["../../../lib/subscriptionManagement/subscriptionUtils.ts"],"names":[],"mappings":"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"}
|
|
@ -0,0 +1,16 @@
|
|||
"use strict";
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.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"
|
||||
};
|
||||
var TokenAudience;
|
||||
(function (TokenAudience) {
|
||||
TokenAudience[TokenAudience["graph"] = 0] = "graph";
|
||||
})(TokenAudience = exports.TokenAudience || (exports.TokenAudience = {}));
|
||||
//# sourceMappingURL=authConstants.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"authConstants.js","sourceRoot":"","sources":["../../../lib/util/authConstants.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;AAElF,QAAA,aAAa,GAAG;IAC3B,mBAAmB,EAAE,QAAQ;IAC7B,wBAAwB,EAAE,sCAAsC;IAChE,oBAAoB,EAAE,oBAAoB;IAC1C,kBAAkB,EAAE,OAAO;IAC3B,qBAAqB,EAAE,qBAAqB;CAC7C,CAAC;AAEF,IAAY,aAEX;AAFD,WAAY,aAAa;IACvB,mDAAK,CAAA;AACP,CAAC,EAFW,aAAa,GAAb,qBAAa,KAAb,qBAAa,QAExB"}
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { TokenCredentialsBase, TokenResponse } from "./TokenCredentialsBase";
|
||||
import { AzureEnvironment } from "ms-rest-azure-env";
|
||||
import { AuthConstants, TokenAudience } from "../util/authConstants";
|
||||
|
||||
export class ApplicationTokenCredentials extends TokenCredentialsBase {
|
||||
|
||||
private readonly secret: string;
|
||||
/**
|
||||
* Creates a new ApplicationTokenCredentials object.
|
||||
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
|
||||
* for detailed instructions on creating an Azure Active Directory application.
|
||||
* @constructor
|
||||
* @param {string} clientId The active directory application client id.
|
||||
* @param {string} domain The domain or tenant id containing this application.
|
||||
* @param {string} secret The authentication secret for the application.
|
||||
* @param {string} [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 {AzureEnvironment} [environment] The azure environment to authenticate with.
|
||||
* @param {object} [tokenCache] The token cache. Default value is the MemoryCache object from adal.
|
||||
*/
|
||||
public constructor(
|
||||
clientId: string,
|
||||
domain: string,
|
||||
secret: string,
|
||||
tokenAudience?: TokenAudience,
|
||||
environment?: AzureEnvironment,
|
||||
tokenCache?: any) {
|
||||
|
||||
if (!Boolean(secret) || typeof secret.valueOf() !== 'string') {
|
||||
throw new Error('secret must be a non empty string.');
|
||||
}
|
||||
super(clientId, domain, tokenAudience, environment as any, tokenCache);
|
||||
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the token from cache initially. If that is unsuccessfull then it tries to get the token from ADAL.
|
||||
* @returns {Promise<TokenResponse>} A promise that resolves to TokenResponse and rejects with an Error.
|
||||
*/
|
||||
public getToken(): Promise<TokenResponse> {
|
||||
return this.getTokenFromCache()
|
||||
.then((tokenResponse) => tokenResponse)
|
||||
.catch((error) => {
|
||||
if (error.message.startsWith(AuthConstants.SDK_INTERNAL_ERROR)) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
const resource = this.getActiveDirectoryResourceId();
|
||||
return new Promise((resolve, reject) => {
|
||||
this.authContext.acquireTokenWithClientCredentials(resource, this.clientId, this.secret,
|
||||
(error: any, tokenResponse: TokenResponse) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return resolve(tokenResponse);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
protected getTokenFromCache(): Promise<any> {
|
||||
const self = this;
|
||||
|
||||
// a thin wrapper over the base implementation. try get token from cache, additionaly clean up cache if required.
|
||||
return super.getTokenFromCache(undefined)
|
||||
.then((tokenResponse) => { return Promise.resolve(tokenResponse); })
|
||||
.catch((error) => {
|
||||
// Remove the stale token from the tokencache. ADAL gives the same error message "Entry not found in cache."
|
||||
// for entry not being present in the cache and for accessToken being expired in the cache. We do not want the token cache
|
||||
// to contain the expired token, we clean it up here.
|
||||
self.removeInvalidItemsFromCache({ _clientId: self.clientId })
|
||||
.then(() => Promise.reject(error))
|
||||
.catch((reason) => {
|
||||
return Promise.reject(new Error(AuthConstants.SDK_INTERNAL_ERROR + " : "
|
||||
+ "critical failure while removing expired token for service principal from token cache. "
|
||||
+ reason.message));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private removeInvalidItemsFromCache(query: object): Promise<boolean> {
|
||||
const self = this;
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
self.tokenCache.find(query, (error: Error, entries: any[]) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
if (entries && entries.length > 0) {
|
||||
return resolve(self.tokenCache.remove(entries, () => resolve(true)));
|
||||
} else {
|
||||
return resolve(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { TokenCredentialsBase, TokenResponse } from "./tokenCredentialsBase";
|
||||
import { AzureEnvironment } from "ms-rest-azure-env";
|
||||
import { AuthConstants, TokenAudience } from "../util/authConstants";
|
||||
|
||||
export class DeviceTokenCredentials extends TokenCredentialsBase {
|
||||
|
||||
private readonly userName: string;
|
||||
|
||||
/**
|
||||
* Creates a new DeviceTokenCredentials object that gets a new access token using userCodeInfo (contains user_code, device_code)
|
||||
* for authenticating user on device.
|
||||
*
|
||||
* When this credential is used, the script will provide a url and code. The user needs to copy the url and the code, paste it
|
||||
* in a browser and authenticate over there. If successful, the script will get the access token.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} [clientId] The active directory application client id.
|
||||
* @param {string} [domain] The domain or tenant id containing this application. Default value is 'common'
|
||||
* @param {string} [username] The user name for account in the form: 'user@example.com'.
|
||||
* @param {string} [tokenAudience] The audience for which the token is requested. Valid value is 'graph'. If tokenAudience is provided
|
||||
* 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).
|
||||
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
|
||||
* for an example.
|
||||
* @param {AzureEnvironment} [environment] The azure environment to authenticate with. Default environment is "Azure" popularly known as "Public Azure Cloud".
|
||||
* @param {object} [tokenCache] The token cache. Default value is the MemoryCache object from adal.
|
||||
*/
|
||||
public constructor(
|
||||
clientId?: string,
|
||||
domain?: string,
|
||||
userName?: string,
|
||||
tokenAudience?: TokenAudience,
|
||||
environment?: AzureEnvironment,
|
||||
tokenCache?: any) {
|
||||
|
||||
if (!userName) {
|
||||
userName = "user@example.com";
|
||||
}
|
||||
|
||||
if (!domain) {
|
||||
domain = AuthConstants.AAD_COMMON_TENANT;
|
||||
}
|
||||
|
||||
if (!clientId) {
|
||||
clientId = AuthConstants.DEFAULT_ADAL_CLIENT_ID;
|
||||
}
|
||||
|
||||
super(clientId, domain, tokenAudience, environment as any, tokenCache);
|
||||
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public getToken(): Promise<TokenResponse> {
|
||||
// For device auth, this is just getTokenFromCache.
|
||||
return this.getTokenFromCache(this.userName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import * as msRest from "ms-rest-ts";
|
||||
|
||||
export interface MSITokenResponse {
|
||||
readonly token_type: string;
|
||||
readonly access_token: string;
|
||||
readonly [x: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class MSITokenCredentials - Provides information about managed service identity token credentials.
|
||||
* This object can only be used to acquire token on a virtual machine provisioned in Azure with managed service identity.
|
||||
*/
|
||||
export class MSITokenCredentials {
|
||||
public constructor(
|
||||
/**
|
||||
* @property {string} domain - The domain or tenant id for which the token is required.
|
||||
*/
|
||||
public domain: string,
|
||||
/**
|
||||
* @property {number} port - Port on which the MSI service is running on the host VM. Default port is 50342
|
||||
*/
|
||||
public port: number = 50342,
|
||||
/**
|
||||
* @property {string} resource - The resource uri or token audience for which the token is needed.
|
||||
* For e.g. it can be:
|
||||
* - resourcemanagement endpoint "https://management.azure.com"(default)
|
||||
* - management endpoint "https://management.core.windows.net/"
|
||||
*/
|
||||
public resource: string = "https://management.azure.com",
|
||||
/**
|
||||
* @property {string} aadEndpoint - The add endpoint for authentication. default - "https://login.microsoftonline.com"
|
||||
*/
|
||||
public aadEndpoint = "https://login.microsoftonline.com") {
|
||||
if (!Boolean(domain) || typeof domain.valueOf() !== 'string') {
|
||||
throw new TypeError('domain must be a non empty string.');
|
||||
}
|
||||
if (typeof port.valueOf() !== 'number') {
|
||||
throw new Error('port must be a number.');
|
||||
}
|
||||
if (typeof resource.valueOf() !== 'string') {
|
||||
throw new Error('resource must be a uri of type string.');
|
||||
}
|
||||
if (typeof aadEndpoint.valueOf() !== 'string') {
|
||||
throw new Error('aadEndpoint must be a uri of type string.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares and sends a POST request to a service endpoint hosted on the Azure VM, which responds with the access token.
|
||||
* @param {function} callback The callback in the form (err, result)
|
||||
* @return {function} callback
|
||||
* {Error} [err] The error if any
|
||||
* {object} [tokenResponse] The tokenResponse (token_type and access_token are the two important properties).
|
||||
*/
|
||||
async getToken(): Promise<MSITokenResponse> {
|
||||
const reqOptions = this.prepareRequestOptions();
|
||||
let client = new msRest.ServiceClient();
|
||||
let opRes: msRest.HttpOperationResponse;
|
||||
let result: MSITokenResponse
|
||||
try {
|
||||
opRes = await client.sendRequest(reqOptions);
|
||||
result = opRes.bodyAsJson as MSITokenResponse;
|
||||
if (!result.token_type) {
|
||||
throw new Error(`Invalid token response, did not find token_type. Response body is: ${opRes.bodyAsText}`);
|
||||
} else if (!result.access_token) {
|
||||
throw new Error(`Invalid token response, did not find access_token. Response body is: ${opRes.bodyAsText}`);
|
||||
}
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
prepareRequestOptions(): msRest.RequestPrepareOptions {
|
||||
const resource = encodeURIComponent(this.resource);
|
||||
const aadEndpoint = encodeURIComponent(this.aadEndpoint);
|
||||
const forwardSlash = encodeURIComponent('/');
|
||||
let reqOptions: msRest.RequestPrepareOptions = {
|
||||
url: `http://localhost:${this.port}/oauth2/token`,
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"Metadata": "true"
|
||||
},
|
||||
body: `authority=${aadEndpoint}${forwardSlash}${this.domain}&resource=${resource}`,
|
||||
method: "POST"
|
||||
};
|
||||
|
||||
return reqOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs a request with the Authentication header.
|
||||
*
|
||||
* @param {webResource} The WebResource to be signed.
|
||||
* @param {function(error)} callback The callback function.
|
||||
* @return {undefined}
|
||||
*/
|
||||
public async signRequest(webResource: msRest.WebResource): Promise<msRest.WebResource> {
|
||||
const tokenResponse = await this.getToken();
|
||||
webResource.headers[msRest.Constants.HeaderConstants.AUTHORIZATION] = `${tokenResponse.tokenType} ${tokenResponse.accessToken}`;
|
||||
return Promise.resolve(webResource);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { Constants as MSRestConstants, WebResource } from "ms-rest-ts";
|
||||
import { AzureEnvironment } from "ms-rest-azure-env";
|
||||
import { TokenAudience } from "../util/authConstants";
|
||||
const adal = require("adal-node");
|
||||
|
||||
export interface TokenResponse {
|
||||
readonly tokenType: string;
|
||||
readonly accessToken: string;
|
||||
readonly [x: string]: any;
|
||||
}
|
||||
|
||||
export abstract class TokenCredentialsBase {
|
||||
protected readonly isGraphContext: boolean;
|
||||
protected readonly authContext: any;
|
||||
|
||||
public constructor(
|
||||
public readonly clientId: string,
|
||||
public domain: string,
|
||||
public readonly tokenAudience?: TokenAudience,
|
||||
public readonly environment = AzureEnvironment.Azure,
|
||||
public tokenCache: any = new adal.MemoryCache()) {
|
||||
|
||||
if (!Boolean(clientId) || typeof clientId.valueOf() !== 'string') {
|
||||
throw new Error('clientId must be a non empty string.');
|
||||
}
|
||||
|
||||
if (!Boolean(domain) || typeof domain.valueOf() !== 'string') {
|
||||
throw new Error('domain must be a non empty string.');
|
||||
}
|
||||
|
||||
if (this.tokenAudience === TokenAudience.graph) {
|
||||
this.isGraphContext = true;
|
||||
|
||||
if (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)."}`);
|
||||
}
|
||||
}
|
||||
|
||||
const authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
|
||||
this.authContext = new adal.AuthenticationContext(authorityUrl, this.environment.validateAuthority, this.tokenCache);
|
||||
}
|
||||
|
||||
protected getActiveDirectoryResourceId(): string {
|
||||
const resource = this.isGraphContext
|
||||
? this.environment.activeDirectoryGraphResourceId
|
||||
: this.environment.activeDirectoryResourceId;
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected getTokenFromCache(userName?: string): Promise<TokenResponse> {
|
||||
const self = this;
|
||||
const resource = this.getActiveDirectoryResourceId();
|
||||
|
||||
return new Promise<TokenResponse>((resolve, reject) => {
|
||||
self.authContext.acquireToken(resource, userName, self.clientId, (error: Error, tokenResponse: TokenResponse) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return resolve(tokenResponse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async abstract getToken(): Promise<TokenResponse>;
|
||||
|
||||
public async signRequest(webResource: WebResource): Promise<WebResource> {
|
||||
const tokenResponse = await this.getToken();
|
||||
webResource.headers[MSRestConstants.HeaderConstants.AUTHORIZATION] = `${tokenResponse.tokenType} ${tokenResponse.accessToken}`;
|
||||
return Promise.resolve(webResource);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { TokenCredentialsBase, TokenResponse } from "./tokenCredentialsBase";
|
||||
import { AzureEnvironment } from "ms-rest-azure-env";
|
||||
import { TokenAudience } from "../util/authConstants";
|
||||
|
||||
export class UserTokenCredentials extends TokenCredentialsBase {
|
||||
|
||||
private readonly username: string;
|
||||
private readonly password: string;
|
||||
|
||||
/**
|
||||
* Creates a new UserTokenCredentials object.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} 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} domain The domain or tenant id containing this application.
|
||||
* @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 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 {AzureEnvironment} [environment] The azure environment to authenticate with.
|
||||
* @param {object} [tokenCache] The token cache. Default value is the MemoryCache object from adal.
|
||||
*/
|
||||
public constructor(
|
||||
clientId: string,
|
||||
domain: string,
|
||||
username: string,
|
||||
password: string,
|
||||
tokenAudience?: TokenAudience,
|
||||
environment?: AzureEnvironment,
|
||||
tokenCache?: any) {
|
||||
|
||||
if (!Boolean(clientId) || typeof clientId.valueOf() !== 'string') {
|
||||
throw new Error('clientId must be a non empty string.');
|
||||
}
|
||||
|
||||
if (!Boolean(domain) || typeof domain.valueOf() !== 'string') {
|
||||
throw new Error('domain must be a non empty string.');
|
||||
}
|
||||
|
||||
if (!Boolean(username) || typeof username.valueOf() !== 'string') {
|
||||
throw new Error('username must be a non empty string.');
|
||||
}
|
||||
|
||||
if (!Boolean(password) || typeof password.valueOf() !== 'string') {
|
||||
throw new Error('password must be a non empty string.');
|
||||
}
|
||||
|
||||
super(clientId, domain, tokenAudience, environment as any, tokenCache);
|
||||
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the token from cache initially. If that is unsuccessful then it tries to get the token from ADAL.
|
||||
* @returns {Promise<any>}
|
||||
* {object} [tokenResponse] The tokenResponse (tokenType and accessToken are the two important properties).
|
||||
* @memberof UserTokenCredentials
|
||||
*/
|
||||
public async getToken(): Promise<TokenResponse> {
|
||||
try {
|
||||
return this.getTokenFromCache(this.username);
|
||||
} catch (error) {
|
||||
|
||||
const self = this;
|
||||
const resource = this.getActiveDirectoryResourceId();
|
||||
|
||||
return new Promise<TokenResponse>((resolve, reject) => {
|
||||
self.authContext.acquireTokenWithUsernamePassword(resource, self.username, self.password, self.clientId,
|
||||
(error: Error, tokenResponse: TokenResponse) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
if (self.crossCheckUserNameWithToken(self.username, tokenResponse.userId)) {
|
||||
resolve((tokenResponse as TokenResponse));
|
||||
} else {
|
||||
reject(`The userId "${tokenResponse.userId}" in access token doesn't match the username "${self.username}" provided during authentication.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,539 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
const adal = require("adal");
|
||||
import * as fs from "fs";
|
||||
import * as msRest from "ms-rest-ts";
|
||||
import { AzureEnvironment } from "ms-rest-azure-env";
|
||||
import { TokenResponse, TokenCredentialsBase } from "./credentials/tokenCredentialsBase";
|
||||
import { ApplicationTokenCredentials } from "./credentials/applicationTokenCredentials";
|
||||
import { DeviceTokenCredentials } from "./credentials/deviceTokenCredentials";
|
||||
import { UserTokenCredentials } from "./credentials/userTokenCredentials";
|
||||
import { AuthConstants, TokenAudience } from "./util/authConstants";
|
||||
import { buildTenantList, getSubscriptionsFromTenants, SubscriptionInfo } from "./subscriptionManagement/subscriptionUtils";
|
||||
import { MSITokenCredentials, MSITokenResponse } from "./credentials/msiTokenCredentials";
|
||||
|
||||
function turnOnLogging() {
|
||||
let log = adal.Logging;
|
||||
log.setLoggingOptions(
|
||||
{
|
||||
level: log.LOGGING_LEVEL.VERBOSE,
|
||||
log: function (level: any, message: any, error: any) {
|
||||
level;
|
||||
console.info(message);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env['AZURE_ADAL_LOGGING_ENABLED']) {
|
||||
turnOnLogging();
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface OptionalInteractiveParameters - Describes optional parameters for serviceprincipal/secret authentication.
|
||||
*/
|
||||
export interface OptionalServicePrincipalParameters {
|
||||
tokenAudience?: TokenAudience;
|
||||
environment?: AzureEnvironment;
|
||||
tokenCache?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface OptionalInteractiveParameters - Describes optional parameters for username/password authentication.
|
||||
*/
|
||||
export interface OptionalUsernamePasswordParameters extends OptionalServicePrincipalParameters {
|
||||
clientId?: string;
|
||||
domain?: string;
|
||||
}
|
||||
/**
|
||||
* @interface OptionalInteractiveParameters - Describes optional parameters for interactive authentication.
|
||||
*/
|
||||
export interface OptionalInteractiveParameters extends OptionalUsernamePasswordParameters {
|
||||
/**
|
||||
* @property {object|function} [userCodeResponseLogger] A logger that logs the user code response message required for interactive login. When
|
||||
* this option is specified the usercode response message will not be logged to console.
|
||||
*/
|
||||
userCodeResponseLogger?: any
|
||||
/**
|
||||
* @property {string} [language] The language code specifying how the message should be localized to. Default value 'en-us'.
|
||||
*/
|
||||
language?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface AuthResponse - Describes the authentication response.
|
||||
*/
|
||||
export interface AuthResponse {
|
||||
/**
|
||||
* @property {TokenCredentialsBase} credentials - The credentials object.
|
||||
*/
|
||||
credentials: TokenCredentialsBase;
|
||||
/**
|
||||
* @property {Array<SubscriptionInfo>} [subscriptions] List of associated subscriptions.
|
||||
*/
|
||||
subscriptions?: SubscriptionInfo[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface OptionalAuthFileParameters - Describes optional parameters for login withAuthFile.
|
||||
*/
|
||||
export interface OptionalAuthFileParameters {
|
||||
/**
|
||||
* @property {string} [filePath] - Absolute file path to the auth file. If not provided
|
||||
* then please set the environment variable AZURE_AUTH_LOCATION.
|
||||
*/
|
||||
filePath?: string;
|
||||
/**
|
||||
* @property {string} [subscriptionEnvVariableName] - The subscriptionId environment variable
|
||||
* name. Default is 'AZURE_SUBSCRIPTION_ID'.
|
||||
*/
|
||||
subscriptionEnvVariableName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface OptionalMSIParameters - Describes optional parameters for MSI authentication.
|
||||
*/
|
||||
export interface OptionalMSIParameters {
|
||||
/**
|
||||
* @property {number} port - Port on which the MSI service is running on the host VM. Default port is 50342
|
||||
*/
|
||||
port?: number;
|
||||
/**
|
||||
* @property {string} resource - The resource uri or token audience for which the token is needed.
|
||||
* For e.g. it can be:
|
||||
* - resourcemanagement endpoint "https://management.azure.com"(default)
|
||||
* - management endpoint "https://management.core.windows.net/"
|
||||
*/
|
||||
resource?: string;
|
||||
/**
|
||||
* @property {string} aadEndpoint - The add endpoint for authentication. default - "https://login.microsoftonline.com"
|
||||
*/
|
||||
aadEndpoint?: string;
|
||||
}
|
||||
|
||||
export async function withUsernamePasswordWithAuthResponse(username: string, password: string, options?: OptionalUsernamePasswordParameters): Promise<AuthResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options.clientId) {
|
||||
options.clientId = AuthConstants.DEFAULT_ADAL_CLIENT_ID;
|
||||
}
|
||||
if (!options.domain) {
|
||||
options.domain = AuthConstants.AAD_COMMON_TENANT;
|
||||
}
|
||||
let creds: UserTokenCredentials;
|
||||
let result: TokenResponse;
|
||||
let tenantList: string[] = [];
|
||||
let subscriptionList: SubscriptionInfo[] = [];
|
||||
try {
|
||||
creds = new UserTokenCredentials(options.clientId, options.domain, username, password, options.tokenAudience, options.environment);
|
||||
result = await creds.getToken();
|
||||
// The token cache gets propulated for all the tenants as a part of building the tenantList.
|
||||
tenantList = await buildTenantList(creds);
|
||||
// We dont need to get the subscriptionList if the tokenAudience is graph as graph clients are tenant based.
|
||||
if (!(options.tokenAudience && options.tokenAudience === TokenAudience.graph)) {
|
||||
subscriptionList = await getSubscriptionsFromTenants(creds, tenantList);
|
||||
}
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return Promise.resolve({ credentials: creds, subscriptions: subscriptionList });
|
||||
}
|
||||
|
||||
export async function withServicePrincipalSecretWithAuthResponse(clientId: string, secret: string, domain: string, options?: OptionalServicePrincipalParameters): Promise<AuthResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
let creds: ApplicationTokenCredentials;
|
||||
let result: TokenResponse;
|
||||
let subscriptionList: SubscriptionInfo[] = [];
|
||||
try {
|
||||
creds = new ApplicationTokenCredentials(clientId, domain, secret, options.tokenAudience, options.environment);
|
||||
result = await creds.getToken();
|
||||
// We dont need to get the subscriptionList if the tokenAudience is graph as graph clients are tenant based.
|
||||
if (!(options.tokenAudience && options.tokenAudience === TokenAudience.graph)) {
|
||||
subscriptionList = await getSubscriptionsFromTenants(creds, [domain]);
|
||||
}
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
return Promise.resolve({ credentials: creds, subscriptions: subscriptionList });
|
||||
}
|
||||
|
||||
function validateAuthFileContent(credsObj: any, filePath: string) {
|
||||
if (!credsObj) {
|
||||
throw new Error('Please provide a credsObj to validate.');
|
||||
}
|
||||
if (!filePath) {
|
||||
throw new Error('Please provide a filePath.');
|
||||
}
|
||||
if (!credsObj.clientId) {
|
||||
throw new Error(`"clientId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.clientSecret) {
|
||||
throw new Error(`"clientSecret" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.subscriptionId) {
|
||||
throw new Error(`"subscriptionId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.tenantId) {
|
||||
throw new Error(`"tenantId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.activeDirectoryEndpointUrl) {
|
||||
throw new Error(`"activeDirectoryEndpointUrl" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.resourceManagerEndpointUrl) {
|
||||
throw new Error(`"resourceManagerEndpointUrl" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.activeDirectoryGraphResourceId) {
|
||||
throw new Error(`"activeDirectoryGraphResourceId" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
if (!credsObj.sqlManagementEndpointUrl) {
|
||||
throw new Error(`"sqlManagementEndpointUrl" is missing from the auth file: ${filePath}.`);
|
||||
}
|
||||
}
|
||||
|
||||
function foundManagementEndpointUrl(authFileUrl: string, envUrl: string): boolean {
|
||||
if (!authFileUrl || (authFileUrl && typeof authFileUrl.valueOf() !== 'string')) {
|
||||
throw new Error('authFileUrl cannot be null or undefined and must be of type string.');
|
||||
}
|
||||
|
||||
if (!envUrl || (envUrl && typeof envUrl.valueOf() !== 'string')) {
|
||||
throw new Error('envUrl cannot be null or undefined and must be of type string.');
|
||||
}
|
||||
|
||||
authFileUrl = authFileUrl.endsWith('/') ? authFileUrl.slice(0, -1) : authFileUrl;
|
||||
envUrl = envUrl.endsWith('/') ? envUrl.slice(0, -1) : envUrl;
|
||||
return (authFileUrl.toLowerCase() === envUrl.toLowerCase());
|
||||
}
|
||||
|
||||
export async function withAuthFileWithAuthResponse(options?: OptionalAuthFileParameters): Promise<AuthResponse> {
|
||||
if (!options) options = { filePath: '' };
|
||||
let filePath = options.filePath || process.env[AuthConstants.AZURE_AUTH_LOCATION];
|
||||
let subscriptionEnvVariableName = options.subscriptionEnvVariableName || 'AZURE_SUBSCRIPTION_ID';
|
||||
if (!filePath) {
|
||||
let msg = `Either provide an absolute file path to the auth file or set/export the environment variable - ${AuthConstants.AZURE_AUTH_LOCATION}.`;
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
let content: string, credsObj: any = {}, optionsForSpSecret: any = {};
|
||||
try {
|
||||
content = fs.readFileSync(filePath, { encoding: 'utf8' });
|
||||
credsObj = JSON.parse(content);
|
||||
validateAuthFileContent(credsObj, filePath);
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
if (!credsObj.managementEndpointUrl) {
|
||||
credsObj.managementEndpointUrl = credsObj.resourceManagerEndpointUrl;
|
||||
}
|
||||
//setting the subscriptionId from auth file to the environment variable
|
||||
process.env[subscriptionEnvVariableName] = credsObj.subscriptionId;
|
||||
//get the AzureEnvironment or create a new AzureEnvironment based on the info provided in the auth file
|
||||
let envFound: any = {
|
||||
name: ''
|
||||
};
|
||||
let envNames = Object.keys(Object.getPrototypeOf(AzureEnvironment)).slice(1);
|
||||
for (let i = 0; i < envNames.length; i++) {
|
||||
let env = envNames[i];
|
||||
let environmentObj = (AzureEnvironment as any)[env];
|
||||
if (environmentObj &&
|
||||
environmentObj.managementEndpointUrl &&
|
||||
foundManagementEndpointUrl(credsObj.managementEndpointUrl, environmentObj.managementEndpointUrl)) {
|
||||
envFound.name = environmentObj.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (envFound.name) {
|
||||
optionsForSpSecret.environment = (AzureEnvironment as any)[envFound.name];
|
||||
} else {
|
||||
//create a new environment with provided info.
|
||||
let envParams: any = {
|
||||
//try to find a logical name or set the filepath as the env name.
|
||||
name: credsObj.managementEndpointUrl.match(/.*management\.core\.(.*)\..*/i)[1] || filePath
|
||||
};
|
||||
let keys = Object.keys(credsObj);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let key = keys[i];
|
||||
if (key.match(/^(clientId|clientSecret|subscriptionId|tenantId)$/ig) === null) {
|
||||
if (key === 'activeDirectoryEndpointUrl' && !key.endsWith('/')) {
|
||||
envParams[key] = credsObj[key] + '/';
|
||||
} else {
|
||||
envParams[key] = credsObj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!envParams.activeDirectoryResourceId) {
|
||||
envParams.activeDirectoryResourceId = credsObj.managementEndpointUrl;
|
||||
}
|
||||
if (!envParams.portalUrl) {
|
||||
envParams.portalUrl = 'https://portal.azure.com';
|
||||
}
|
||||
optionsForSpSecret.environment = AzureEnvironment.add(envParams);
|
||||
}
|
||||
return withServicePrincipalSecretWithAuthResponse(credsObj.clientId, credsObj.clientSecret, credsObj.tenantId, optionsForSpSecret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function withInteractiveWithAuthResponse(options?: OptionalInteractiveParameters): Promise<AuthResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (!options.environment) {
|
||||
options.environment = AzureEnvironment.Azure;
|
||||
}
|
||||
|
||||
if (!options.domain) {
|
||||
options.domain = AuthConstants.AAD_COMMON_TENANT;
|
||||
}
|
||||
|
||||
if (!options.clientId) {
|
||||
options.clientId = AuthConstants.DEFAULT_ADAL_CLIENT_ID;
|
||||
}
|
||||
|
||||
if (!options.tokenCache) {
|
||||
options.tokenCache = new adal.MemoryCache();
|
||||
}
|
||||
|
||||
if (!options.language) {
|
||||
options.language = AuthConstants.DEFAULT_LANGUAGE;
|
||||
}
|
||||
let interactiveOptions: any = {};
|
||||
interactiveOptions.tokenAudience = options.tokenAudience;
|
||||
interactiveOptions.environment = options.environment;
|
||||
interactiveOptions.domain = options.domain;
|
||||
interactiveOptions.clientId = options.clientId;
|
||||
interactiveOptions.tokenCache = options.tokenCache;
|
||||
interactiveOptions.language = options.language;
|
||||
interactiveOptions.userCodeResponseLogger = options.userCodeResponseLogger;
|
||||
let authorityUrl: string = interactiveOptions.environment.activeDirectoryEndpointUrl + interactiveOptions.domain;
|
||||
let authContext: any = new adal.AuthenticationContext(authorityUrl, interactiveOptions.environment.validateAuthority, interactiveOptions.tokenCache);
|
||||
interactiveOptions.context = authContext;
|
||||
let tenantList: string[] = [];
|
||||
let subscriptionList: SubscriptionInfo[] = [];
|
||||
let getUserCode = new Promise<any>((resolve, reject) => {
|
||||
return authContext.acquireUserCode(interactiveOptions.environment.activeDirectoryResourceId, interactiveOptions.clientId, interactiveOptions.language, (err: Error, userCodeResponse: any) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
if (interactiveOptions.userCodeResponseLogger) {
|
||||
interactiveOptions.userCodeResponseLogger(userCodeResponse.message);
|
||||
} else {
|
||||
console.log(userCodeResponse.message);
|
||||
}
|
||||
return resolve(userCodeResponse.message);
|
||||
});
|
||||
});
|
||||
|
||||
return getUserCode.then((userCodeResponse) => {
|
||||
return authContext.acquireTokenWithDeviceCode(interactiveOptions.environment.activeDirectoryResourceId, interactiveOptions.clientId, userCodeResponse, async (error: Error, tokenResponse: any) => {
|
||||
if (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
interactiveOptions.username = tokenResponse.userId;
|
||||
interactiveOptions.authorizationScheme = tokenResponse.tokenType;
|
||||
try {
|
||||
let creds: DeviceTokenCredentials = new DeviceTokenCredentials(interactiveOptions.clientId,
|
||||
interactiveOptions.domain, interactiveOptions.userName, interactiveOptions.tokenAudience,
|
||||
interactiveOptions.environment, interactiveOptions.tokenCache);
|
||||
tenantList = await buildTenantList(creds);
|
||||
if (!(interactiveOptions.tokenAudience && interactiveOptions.tokenAudience === TokenAudience.graph)) {
|
||||
subscriptionList = await getSubscriptionsFromTenants(creds, tenantList);
|
||||
}
|
||||
return Promise.resolve({ credentials: creds, subscriptions: subscriptionList });
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function withAuthFile(): Promise<TokenCredentialsBase>;
|
||||
export function withAuthFile(options: OptionalAuthFileParameters): Promise<TokenCredentialsBase>;
|
||||
export function withAuthFile(options: OptionalAuthFileParameters, callback: Function): void
|
||||
export function withAuthFile(callback: any): void
|
||||
export function withAuthFile(options?: OptionalAuthFileParameters, callback?: Function): any {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback as Function;
|
||||
if (!callback) {
|
||||
return withAuthFileWithAuthResponse(options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withAuthFileWithAuthResponse(options))((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function interactive(): Promise<TokenCredentialsBase>;
|
||||
export function interactive(options: OptionalInteractiveParameters): Promise<TokenCredentialsBase>;
|
||||
export function interactive(options: OptionalInteractiveParameters, callback: Function): void
|
||||
export function interactive(callback: any): void
|
||||
export function interactive(options?: OptionalInteractiveParameters, callback?: Function): any {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback as Function;
|
||||
if (!callback) {
|
||||
return withInteractiveWithAuthResponse(options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withInteractiveWithAuthResponse(options))((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string): Promise<TokenCredentialsBase>;
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, options: OptionalServicePrincipalParameters): Promise<TokenCredentialsBase>;
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, options: OptionalServicePrincipalParameters, callback: Function): void
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, callback: any): void;
|
||||
export function withServicePrincipalSecret(clientId: string, secret: string, domain: string, options?: OptionalServicePrincipalParameters, callback?: Function): any {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback as Function;
|
||||
if (!callback) {
|
||||
return withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withServicePrincipalSecretWithAuthResponse(clientId, secret, domain, options))((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function withUsernamePassword(username: string, password: string): Promise<TokenCredentialsBase>;
|
||||
export function withUsernamePassword(username: string, password: string, options: OptionalUsernamePasswordParameters): Promise<TokenCredentialsBase>;
|
||||
export function withUsernamePassword(username: string, password: string, callback: any): void;
|
||||
export function withUsernamePassword(username: string, password: string, options: OptionalUsernamePasswordParameters, callback: Function): void;
|
||||
export function withUsernamePassword(username: string, password: string, options?: OptionalUsernamePasswordParameters, callback?: Function): any {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
let cb = callback as Function;
|
||||
if (!callback) {
|
||||
return withUsernamePasswordWithAuthResponse(username, password, options).then((authRes) => {
|
||||
return Promise.resolve(authRes.credentials);
|
||||
}).catch((err) => {
|
||||
return Promise.reject(err);
|
||||
});
|
||||
} else {
|
||||
msRest.promiseToCallback(withUsernamePasswordWithAuthResponse(username, password, options))((err: Error, authRes: AuthResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, authRes.credentials, authRes.subscriptions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes MSITokenCredentials class and calls getToken and returns a token response.
|
||||
*
|
||||
* @param {string} domain -- required. The tenant id.
|
||||
* @param {object} options -- Optional parameters
|
||||
* @param {string} [options.port] - port on which the MSI service is running on the host VM. Default port is 50342
|
||||
* @param {string} [options.resource] - The resource uri or token audience for which the token is needed. Default - "https://management.azure.com"
|
||||
* @param {string} [options.aadEndpoint] - The add endpoint for authentication. default - "https://login.microsoftonline.com"
|
||||
* @param {any} callback - the callback function.
|
||||
*/
|
||||
function _withMSI(domain: string, options?: OptionalMSIParameters): Promise<MSITokenResponse> {
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
const creds = new MSITokenCredentials(domain, options.port, options.resource, options.aadEndpoint);
|
||||
return creds.getToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Before using this method please install az cli from https://github.com/Azure/azure-cli/releases.
|
||||
* If you have an Azure virtual machine provisioned with az cli and has MSI enabled,
|
||||
* you can then use this method to get auth tokens from the VM.
|
||||
*
|
||||
* To create a new VM, enable MSI, please execute this command:
|
||||
* az vm create -g <resource_group_name> -n <vm_name> --assign-identity --image <os_image_name>
|
||||
* Note: the above command enables a service endpoint on the host, with a default port 50342
|
||||
*
|
||||
* To enable MSI on a already provisioned VM, execute the following command:
|
||||
* az vm --assign-identity -g <resource_group_name> -n <vm_name> --port <custom_port_number>
|
||||
*
|
||||
* To know more about this command, please execute:
|
||||
* az vm --assign-identity -h
|
||||
*
|
||||
* Authenticates using the identity service running on an Azure virtual machine.
|
||||
* This method makes a request to the authentication service hosted on the VM
|
||||
* and gets back an access token.
|
||||
*
|
||||
* @param {string} [domain] - The domain or tenant id. This is a required parameter.
|
||||
* @param {object} [options] - Optional parameters
|
||||
* @param {string} [options.port] - port on which the MSI service is running on the host VM. Default port is 50342
|
||||
* @param {string} [options.resource] - The resource uri or token audience for which the token is needed.
|
||||
* For e.g. it can be:
|
||||
* - resourcemanagement endpoint "https://management.azure.com"(default)
|
||||
* - management endpoint "https://management.core.windows.net/"
|
||||
* @param {string} [options.aadEndpoint] - The add endpoint for authentication. default - "https://login.microsoftonline.com"
|
||||
* @param {function} [optionalCallback] The optional callback.
|
||||
*
|
||||
* @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.
|
||||
* {object} [tokenResponse] - The tokenResponse (token_type and access_token are the two important properties)
|
||||
* {Promise} A promise is returned.
|
||||
* @resolve {MSITokenResponse} - The tokenResponse.
|
||||
* @reject {Error} - The error object.
|
||||
*/
|
||||
export function withMSI(domain: string): Promise<MSITokenResponse>;
|
||||
export function withMSI(domain: string, options: OptionalMSIParameters): Promise<MSITokenResponse>;
|
||||
export function withMSI(domain: string, options: OptionalMSIParameters, callback: Function): void
|
||||
export function withMSI(domain: string, callback: any): any
|
||||
export function withMSI(domain: string, options?: OptionalMSIParameters, callback?: Function): any {
|
||||
if (!callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
let cb = callback as Function;
|
||||
if (!callback) {
|
||||
return _withMSI(domain, options);
|
||||
} else {
|
||||
msRest.promiseToCallback(_withMSI(domain, options))((err: Error, tokenRes: MSITokenResponse) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
return cb(null, tokenRes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import { TokenCredentialsBase, TokenResponse } from "./credentials/tokenCredentialsBase";
|
||||
import { ApplicationTokenCredentials } from "./credentials/applicationTokenCredentials";
|
||||
import { DeviceTokenCredentials } from "./credentials/deviceTokenCredentials";
|
||||
import { UserTokenCredentials } from "./credentials/userTokenCredentials";
|
||||
import { MSITokenCredentials, MSITokenResponse } from "./credentials/msiTokenCredentials";
|
||||
import { AuthConstants, TokenAudience } from "./util/authConstants";
|
||||
import { SubscriptionInfo, User, UserType } from "./subscriptionManagement/subscriptionUtils";
|
||||
import {
|
||||
AuthResponse, OptionalAuthFileParameters, OptionalInteractiveParameters,
|
||||
OptionalMSIParameters, OptionalServicePrincipalParameters, OptionalUsernamePasswordParameters,
|
||||
interactive, withAuthFile, withAuthFileWithAuthResponse, withInteractiveWithAuthResponse,
|
||||
withMSI, withServicePrincipalSecret, withServicePrincipalSecretWithAuthResponse,
|
||||
withUsernamePassword, withUsernamePasswordWithAuthResponse
|
||||
} from "./login";
|
||||
|
||||
export {
|
||||
TokenCredentialsBase, TokenResponse, ApplicationTokenCredentials, DeviceTokenCredentials,
|
||||
UserTokenCredentials, MSITokenCredentials, MSITokenResponse, AuthConstants, TokenAudience,
|
||||
AuthResponse, OptionalAuthFileParameters, OptionalInteractiveParameters, OptionalMSIParameters,
|
||||
OptionalServicePrincipalParameters, OptionalUsernamePasswordParameters,
|
||||
interactive as interactiveLogin,
|
||||
withInteractiveWithAuthResponse as interactiveLoginWithAuthResponse,
|
||||
withUsernamePassword as loginWithUsernamePassword,
|
||||
withUsernamePasswordWithAuthResponse as loginWithUsernamePasswordWithAuthResponse,
|
||||
withServicePrincipalSecret as loginWithServicePrincipalSecret,
|
||||
withServicePrincipalSecretWithAuthResponse as loginWithServicePrincipalSecretWithAuthResponse,
|
||||
withAuthFile as loginWithAuthFile,
|
||||
withAuthFileWithAuthResponse as loginWithAuthFileWithAuthResponse,
|
||||
withMSI as loginWithMSI,
|
||||
SubscriptionInfo, User, UserType
|
||||
};
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
import * as msRest from "ms-rest-ts";
|
||||
import { TokenCredentialsBase } from "../credentials/tokenCredentialsBase";
|
||||
import { ApplicationTokenCredentials } from "../credentials/applicationTokenCredentials";
|
||||
import { AuthConstants } from "../util/authConstants"
|
||||
|
||||
/**
|
||||
* @interface UserType Provides information about user type. It can currently be "user" or "servicePrincipal".
|
||||
*/
|
||||
export type UserType = "user" | "servicePrincipal";
|
||||
|
||||
/**
|
||||
* @interface User Provides information about a user from the authentication perspective.
|
||||
*/
|
||||
export interface User {
|
||||
/**
|
||||
* @property {string} name - The user name. For ApplicationTokenCredentials it can be the clientId or SPN.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* @property {string} type - The user type. "user" | "servicePrincipal".
|
||||
*/
|
||||
type: UserType
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface SubscriptionInfo Provides information about subscription that was found
|
||||
* during the authentication process. The structure of this type is different from the
|
||||
* subscription object that one gets by making a request to the ResourceManager API.
|
||||
*/
|
||||
export interface SubscriptionInfo {
|
||||
/**
|
||||
* @property {string}
|
||||
*/
|
||||
readonly tenantId: string;
|
||||
/**
|
||||
* @property {string}
|
||||
*/
|
||||
readonly user: User;
|
||||
/**
|
||||
* @property {string} environmentName - The environment name in which the subscription exists.
|
||||
* Possible values: "Azure", "AzureChina", "AzureUSGovernment", "AzureGermanCloud" or
|
||||
* some other custom/internal environment name like "Dogfood".
|
||||
*/
|
||||
readonly environmentName: string;
|
||||
/**
|
||||
* @property {string} name - The display name of the subscription.
|
||||
*/
|
||||
readonly name: string;
|
||||
/**
|
||||
* @property {string} id - The subscription id, usually a guid.
|
||||
*/
|
||||
readonly id: string;
|
||||
/**
|
||||
* @property {any} any Placeholder for unknown properties
|
||||
*/
|
||||
readonly [x: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an array of tenantIds.
|
||||
* @param {TokenCredentialsBase} credentials
|
||||
* @param {string} apiVersion default value 2016-06-01
|
||||
* @returns {Promise<string[]>} resolves to an array of tenantIds and rejects with an error.
|
||||
*/
|
||||
export async function buildTenantList(credentials: TokenCredentialsBase, apiVersion = "2016-06-01"): Promise<string[]> {
|
||||
if (credentials.domain && credentials.domain !== AuthConstants.AAD_COMMON_TENANT) {
|
||||
return Promise.resolve([credentials.domain]);
|
||||
}
|
||||
|
||||
let client = new msRest.ServiceClient(credentials);
|
||||
let baseUrl = credentials.environment.resourceManagerEndpointUrl;
|
||||
let reqUrl = `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}tenants?api-version=${apiVersion}`;
|
||||
let req: msRest.RequestPrepareOptions = {
|
||||
url: reqUrl,
|
||||
method: "GET",
|
||||
}
|
||||
let res: msRest.HttpOperationResponse;
|
||||
try {
|
||||
res = await client.sendRequest(req);
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
let result: string[] = [];
|
||||
let tenants: any = res.bodyAsJson;
|
||||
for (let tenant in tenants.value) {
|
||||
result.push((<any>tenant).tenantId)
|
||||
}
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
|
||||
export async function getSubscriptionsFromTenants(credentials: TokenCredentialsBase, tenantList: string[], apiVersion = "2016-06-01"): Promise<SubscriptionInfo[]> {
|
||||
let subscriptions: SubscriptionInfo[] = [];
|
||||
let userType = 'user';
|
||||
let username: string;
|
||||
let originalDomain = credentials.domain;
|
||||
if (credentials instanceof ApplicationTokenCredentials) {
|
||||
userType = 'servicePrincipal';
|
||||
username = credentials.clientId;
|
||||
} else {
|
||||
username = (<any>credentials).username;
|
||||
}
|
||||
for (let tenant of tenantList) {
|
||||
credentials.domain = tenant;
|
||||
let client = new msRest.ServiceClient(credentials);
|
||||
let baseUrl = credentials.environment.resourceManagerEndpointUrl;
|
||||
let reqUrl = `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}subscriptions?api-version=${apiVersion}`;
|
||||
let req: msRest.RequestPrepareOptions = {
|
||||
url: reqUrl,
|
||||
method: "GET",
|
||||
}
|
||||
let res: msRest.HttpOperationResponse;
|
||||
try {
|
||||
res = await client.sendRequest(req);
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
|
||||
let subscriptionList: any[] = (<any>res.bodyAsJson).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;
|
||||
}));
|
||||
}
|
||||
// Reset the original domain.
|
||||
credentials.domain = originalDomain;
|
||||
return Promise.resolve(subscriptions);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// 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"
|
||||
};
|
||||
|
||||
export enum TokenAudience {
|
||||
graph,
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"name": "ms-rest-azure-ts",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation",
|
||||
"email": "azsdkteam@microsoft.com",
|
||||
"url": "https://github.com/Azure/azure-sdk-for-node"
|
||||
},
|
||||
"version": "0.1.0",
|
||||
"description": "Azure endpoints for different Azure Environments/Clouds.",
|
||||
"tags": [
|
||||
"node",
|
||||
"isomorphic",
|
||||
"microsoft",
|
||||
"autorest",
|
||||
"environment"
|
||||
],
|
||||
"keywords": [
|
||||
"node",
|
||||
"isomorphic",
|
||||
"microsoft",
|
||||
"autorest",
|
||||
"environment"
|
||||
],
|
||||
"main": "./dist/lib/msRestAzureNodeAuth.js",
|
||||
"types": "./typings/lib/msRestAzureNodeAuth.d.ts",
|
||||
"dependencies": {
|
||||
"ms-rest-azure-env": "azure/ms-rest-azure-env",
|
||||
"ms-rest-ts": "amarzavery/ms-rest#master",
|
||||
"adal-node": "^0.1.22"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^2.2.40",
|
||||
"@types/should": "^8.1.30",
|
||||
"mocha": "^3.2.0",
|
||||
"should": "5.2.0",
|
||||
"tslint": "^5.2.0",
|
||||
"typescript": "^2.5.2"
|
||||
},
|
||||
"homepage": "https://github.com/Azure/azure-sdk-for-node/runtime/ms-rest",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:Azure/azure-sdk-for-node.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://github.com/Azure/azure-sdk-for-node/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"tsc": "tsc -p tsconfig.json",
|
||||
"test": "npm install && npm -s run-script unit",
|
||||
"unit": "mocha -t 50000 dist/test",
|
||||
"build": "npm -s run-script tsc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"alwaysStrict": true,
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": true,
|
||||
"preserveConstEnums": true,
|
||||
"sourceMap": true,
|
||||
"newLine": "LF",
|
||||
"target": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"outDir": "dist/lib",
|
||||
"declaration": true,
|
||||
"declarationDir": "typings/lib",
|
||||
"allowJs": false,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"es5",
|
||||
"es6",
|
||||
"es7",
|
||||
"esnext",
|
||||
"esnext.asynciterable",
|
||||
"es2015.iterable"
|
||||
]
|
||||
},
|
||||
"compileOnSave": true,
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"include": [
|
||||
"./lib/*.ts",
|
||||
"./test/*.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"rules": {
|
||||
"class-name": true,
|
||||
"comment-format": [true,
|
||||
"check-space"
|
||||
],
|
||||
"indent": [true,
|
||||
"spaces"
|
||||
],
|
||||
"linebreak-style": [true, "LF"],
|
||||
"one-line": [true,
|
||||
"check-open-brace",
|
||||
"check-whitespace"
|
||||
],
|
||||
"no-var-keyword": true,
|
||||
"quotemark": [true,
|
||||
"double",
|
||||
"avoid-escape"
|
||||
],
|
||||
"semicolon": [true, "always", "ignore-bound-class-methods"],
|
||||
"whitespace": [true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-module",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
},
|
||||
{
|
||||
"call-signature": "onespace",
|
||||
"index-signature": "onespace",
|
||||
"parameter": "onespace",
|
||||
"property-declaration": "onespace",
|
||||
"variable-declaration": "onespace"
|
||||
}
|
||||
],
|
||||
"no-internal-module": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-inferrable-types": [true],
|
||||
"no-null-keyword": true,
|
||||
"prefer-const": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"triple-equals": true,
|
||||
"jsdoc-format": true
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче