This commit is contained in:
Amar Zavery 2017-09-08 11:25:16 -07:00
Родитель f7fab73679
Коммит aa74328046
35 изменённых файлов: 2359 добавлений и 1 удалений

37
.gitattributes поставляемый Normal file
Просмотреть файл

@ -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

7
.npmignore Normal file
Просмотреть файл

@ -0,0 +1,7 @@
.vscode/
node_modules/
samples/
test/
.travis.yml
gulpfile.js
.gitignore

17
.vscode/launch.json поставляемый Normal file
Просмотреть файл

@ -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"
]
}
]
}

19
.vscode/settings.json поставляемый Normal file
Просмотреть файл

@ -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
}
}

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

@ -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

86
dist/lib/credentials/applicationTokenCredentials.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/credentials/applicationTokenCredentials.js.map поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
{"version":3,"file":"applicationTokenCredentials.js","sourceRoot":"","sources":["../../../lib/credentials/applicationTokenCredentials.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;AAE/F,iEAA6E;AAE7E,yDAAqE;AAErE,iCAAyC,SAAQ,2CAAoB;IAGnE;;;;;;;;;;;;OAYG;IACH,YACE,QAAgB,EAChB,MAAc,EACd,MAAc,EACd,aAA6B,EAC7B,WAA8B,EAC9B,UAAgB;QAEhB,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;QACD,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,WAAkB,EAAE,UAAU,CAAC,CAAC;QAEvE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;MAGE;IACK,QAAQ;QACb,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;aAC5B,IAAI,CAAC,CAAC,aAAa,KAAK,aAAa,CAAC;aACtC,KAAK,CAAC,CAAC,KAAK;YACX,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,6BAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;gBAC/D,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,4BAA4B,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM;gBACjC,IAAI,CAAC,WAAW,CAAC,iCAAiC,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EACrF,CAAC,KAAU,EAAE,aAA4B;oBACvC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;wBACV,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACvB,CAAC;oBACD,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;gBAChC,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAES,iBAAiB;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC;QAElB,iHAAiH;QACjH,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,SAAS,CAAC;aACtC,IAAI,CAAC,CAAC,aAAa,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;aACnE,KAAK,CAAC,CAAC,KAAK;YACX,4GAA4G;YAC5G,0HAA0H;YAC1H,qDAAqD;YACrD,IAAI,CAAC,2BAA2B,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;iBAC3D,IAAI,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;iBACjC,KAAK,CAAC,CAAC,MAAM;gBACZ,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAAa,CAAC,kBAAkB,GAAG,KAAK;sBACpE,wFAAwF;sBACxF,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YACvB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,2BAA2B,CAAC,KAAa;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,CAAC,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM;YAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAY,EAAE,OAAc;gBACvD,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;oBACV,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvB,CAAC;gBAED,EAAE,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;oBAClC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACvE,CAAC;gBAAC,IAAI,CAAC,CAAC;oBACN,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA7FD,kEA6FC"}

45
dist/lib/credentials/deviceTokenCredentials.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/credentials/deviceTokenCredentials.js.map поставляемый Normal file
Просмотреть файл

@ -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"}

116
dist/lib/credentials/msiTokenCredentials.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/credentials/msiTokenCredentials.js.map поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
{"version":3,"file":"msiTokenCredentials.js","sourceRoot":"","sources":["../../../lib/credentials/msiTokenCredentials.ts"],"names":[],"mappings":"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"}

67
dist/lib/credentials/tokenCredentialsBase.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/credentials/tokenCredentialsBase.js.map поставляемый Normal file
Просмотреть файл

@ -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"}

84
dist/lib/credentials/userTokenCredentials.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/credentials/userTokenCredentials.js.map поставляемый Normal file
Просмотреть файл

@ -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"}

410
dist/lib/login.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/login.js.map поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

28
dist/lib/msRestNodeAuth.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/msRestNodeAuth.js.map поставляемый Normal file
Просмотреть файл

@ -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"}

98
dist/lib/subscriptionManagement/subscriptionUtils.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/subscriptionManagement/subscriptionUtils.js.map поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
{"version":3,"file":"subscriptionUtils.js","sourceRoot":"","sources":["../../../lib/subscriptionManagement/subscriptionUtils.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,+FAA+F;;;;;;;;;;AAE/F,qCAAqC;AAErC,4FAAyF;AACzF,yDAAqD;AAuDrD;;;;;GAKG;AACH,yBAAsC,WAAiC,EAAE,UAAU,GAAG,YAAY;;QAChG,EAAE,CAAC,CAAC,WAAW,CAAC,MAAM,IAAI,WAAW,CAAC,MAAM,KAAK,6BAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC;YACjF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,MAAM,GAAG,IAAI,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QACnD,IAAI,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,0BAA0B,CAAC;QACjE,IAAI,MAAM,GAAG,GAAG,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,uBAAuB,UAAU,EAAE,CAAC;QAC9F,IAAI,GAAG,GAAiC;YACtC,GAAG,EAAE,MAAM;YACX,MAAM,EAAE,KAAK;SACd,CAAA;QACD,IAAI,GAAiC,CAAC;QACtC,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,MAAM,GAAa,EAAE,CAAC;QAC1B,IAAI,OAAO,GAAQ,GAAG,CAAC,UAAU,CAAC;QAClC,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,IAAI,CAAO,MAAO,CAAC,QAAQ,CAAC,CAAA;QACrC,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CAAA;AAxBD,0CAwBC;AAED,qCAAkD,WAAiC,EAAE,UAAoB,EAAE,UAAU,GAAG,YAAY;;QAClI,IAAI,aAAa,GAAuB,EAAE,CAAC;QAC3C,IAAI,QAAQ,GAAG,MAAM,CAAC;QACtB,IAAI,QAAgB,CAAC;QACrB,IAAI,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC;QACxC,EAAE,CAAC,CAAC,WAAW,YAAY,yDAA2B,CAAC,CAAC,CAAC;YACvD,QAAQ,GAAG,kBAAkB,CAAC;YAC9B,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;QAClC,CAAC;QAAC,IAAI,CAAC,CAAC;YACN,QAAQ,GAAS,WAAY,CAAC,QAAQ,CAAC;QACzC,CAAC;QACD,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC;YAC9B,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC;YAC5B,IAAI,MAAM,GAAG,IAAI,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;YACnD,IAAI,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,0BAA0B,CAAC;YACjE,IAAI,MAAM,GAAG,GAAG,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,6BAA6B,UAAU,EAAE,CAAC;YACpG,IAAI,GAAG,GAAiC;gBACtC,GAAG,EAAE,MAAM;gBACX,MAAM,EAAE,KAAK;aACd,CAAA;YACD,IAAI,GAAiC,CAAC;YACtC,IAAI,CAAC;gBACH,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACtC,CAAC;YAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACb,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7B,CAAC;YAED,IAAI,gBAAgB,GAAgB,GAAG,CAAC,UAAW,CAAC,KAAK,CAAC;YAC1D,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAM;gBAC/D,CAAC,CAAC,QAAQ,GAAG,MAAM,CAAC;gBACpB,CAAC,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;gBAC5C,CAAC,CAAC,eAAe,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC;gBACjD,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC;gBACvB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,cAAc,CAAC;gBACxB,OAAO,CAAC,CAAC,WAAW,CAAC;gBACrB,OAAO,CAAC,CAAC,cAAc,CAAC;gBACxB,OAAO,CAAC,CAAC,oBAAoB,CAAC;gBAC9B,MAAM,CAAC,CAAC,CAAC;YACX,CAAC,CAAC,CAAC,CAAC;QACN,CAAC;QACD,6BAA6B;QAC7B,WAAW,CAAC,MAAM,GAAG,cAAc,CAAC;QACpC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC;CAAA;AA3CD,kEA2CC"}

16
dist/lib/util/authConstants.js поставляемый Normal file
Просмотреть файл

@ -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

1
dist/lib/util/authConstants.js.map поставляемый Normal file
Просмотреть файл

@ -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.`);
}
});
});
}
}
}

539
lib/login.ts Normal file
Просмотреть файл

@ -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);
});
}
}

34
lib/msRestNodeAuth.ts Normal file
Просмотреть файл

@ -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);
}

14
lib/util/authConstants.ts Normal file
Просмотреть файл

@ -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,
}

54
package.json Normal file
Просмотреть файл

@ -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"
}
}

40
tsconfig.json Normal file
Просмотреть файл

@ -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"
]
}

55
tslint.json Normal file
Просмотреть файл

@ -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
}
}