Skip to content
This repository has been archived by the owner on May 5, 2023. It is now read-only.

Commit

Permalink
updates to runtime and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
amarzavery committed May 22, 2016
1 parent 105b7cd commit 931f7b3
Show file tree
Hide file tree
Showing 20 changed files with 824 additions and 136 deletions.
19 changes: 11 additions & 8 deletions Documentation/Authentication.md
Expand Up @@ -104,14 +104,17 @@ info: login command OK

## Using authentication in your node.js script
- Service Principal Authentication
This is useful in automation scenarios. The experience for loginWithServicePrincipalSecret is the same as the one described above in CLI.
```javascript
var msrestAzure = require('ms-rest-azure');
//service principal authentication
'your-client-id' - is the spn ('56894bd4-0fde-41d8-a0d7-5bsslccety2')
'your-domain' - is the tenant id (a guid) or the part **after @** in your username (user1@**contosocorp.com**) ('contosocorp.com')
'your-secret' - is the password you created for the serviceprincipal ('P@ssw0rd')
var credentials = new msRestAzure.ApplicationTokenCredentials('your-client-id', 'your-domain', 'your-secret');
```
var someAzureServiceClient = require('azure-arm-someService');
msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain, function(err, credentials) {
var client = new someAzureServiceClient(credentials, 'your-subscriptionId');
client.someOperationGroup.method(param1, param2, function(err, result) {
if (err) console.log(err);
console.log(result);
});
});
```

- Interactive Login is the simplest and the best way to authenticate.
It provides a url and code that needs to be copied and pasted in a browser and authenticated over there. If successful,
Expand All @@ -128,7 +131,7 @@ the user will get a DeviceTokenCredentials object.
```

- Login with username and password
This mechanism will only work for organizational ids and ids that are not 2FA enabled.
This mechanism will only work for non 2FA enabled organizational ids.
Otherwise it is better to use the above mechanism (interactive login).
```javascript
var someAzureServiceClient = require('azure-arm-someService');
Expand Down
22 changes: 4 additions & 18 deletions lib/services/storageManagement2/lib/operations/storageAccounts.js
Expand Up @@ -53,29 +53,15 @@ function StorageAccounts(client) {
*
* {stream} [response] - The HTTP Response stream if an error did not occur.
*/
StorageAccounts.prototype.checkNameAvailability = function(name, options, callback) {
StorageAccounts.prototype.checkNameAvailability = function (name, options, callback) {
var client = this.client;
if(!callback && typeof options === 'function') {
callback = options;
options = null;
}
if (!callback) {
var self = this;
return new Promise(function(resolve, reject) {
_checkNameAvailability.call(self, name, options, function(err, result, req, res) {
if (err) return reject(err);
if (options && options.fullResponse) {
return resolve({result: result, request: req, response: res});
}
return resolve(result);
});
});
return p;
throw new Error('callback cannot be null.');
}
return _checkNameAvailability.call(this, name, options, callback);
};

function _checkNameAvailability(name, options, callback) {
var client = this.client;
// Validate
try {
if (this.client.apiVersion === null || this.client.apiVersion === undefined || typeof this.client.apiVersion.valueOf() !== 'string') {
Expand Down Expand Up @@ -1746,4 +1732,4 @@ StorageAccounts.prototype.regenerateKey = function (resourceGroupName, accountNa
};


module.exports = StorageAccounts;
module.exports = StorageAccounts;
56 changes: 28 additions & 28 deletions runtime/NodeJSClientRuntime.sln
@@ -1,28 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "ms-rest", "ms-rest/ms-rest.njsproj", "{9A797837-B825-48E7-AECC-B195F01D47D1}"
EndProject
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "ms-rest-azure", "ms-rest-azure/ms-rest-azure.njsproj", "{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9A797837-B825-48E7-AECC-B195F01D47D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A797837-B825-48E7-AECC-B195F01D47D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A797837-B825-48E7-AECC-B195F01D47D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A797837-B825-48E7-AECC-B195F01D47D1}.Release|Any CPU.Build.0 = Release|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "ms-rest", "ms-rest/ms-rest.njsproj", "{9A797837-B825-48E7-AECC-B195F01D47D1}"
EndProject
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "ms-rest-azure", "ms-rest-azure/ms-rest-azure.njsproj", "{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9A797837-B825-48E7-AECC-B195F01D47D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A797837-B825-48E7-AECC-B195F01D47D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A797837-B825-48E7-AECC-B195F01D47D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A797837-B825-48E7-AECC-B195F01D47D1}.Release|Any CPU.Build.0 = Release|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B4432DA-CD3B-45FE-9415-BDCFEE4DD172}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
46 changes: 40 additions & 6 deletions runtime/ms-rest-azure/README.md
Expand Up @@ -2,7 +2,7 @@

Infrastructure for error handling, tracing, and http client pipeline configuration. Required by nodeJS Azure client libraries, generated using AutoRest.

- **Node.js version: 0.10.0 or higher**
- **Node.js version: 4.x.x or higher**


## How to Install
Expand All @@ -17,14 +17,48 @@ var msrestAzure = require('ms-rest-azure');
```
## Authentication

#### Interactive Login is the simplest and the best way to authenticate.
It provides a url and code that needs to be copied and pasted in a browser and authenticated over there. If successful,
the user will get a DeviceTokenCredentials object.
```javascript
//user authentication
var credentials = new msRestAzure.UserTokenCredentials('your-client-id', 'your-domain', 'your-username', 'your-password', 'your-redirect-uri');
//service principal authentication
var credentials = new msRestAzure.ApplicationTokenCredentials('your-client-id', 'your-domain', 'your-secret');
var someAzureServiceClient = require('azure-arm-someService');
msRestAzure.interactiveLogin(function(err, credentials) {
var client = new someAzureServiceClient(credentials, 'your-subscriptionId');
client.someOperationGroup.method(param1, param2, function(err, result) {
if (err) console.log(err);
console.log(result);
});
});
```

#### Login with username and password
This mechanism will only work for organizational ids and ids that are not 2FA enabled.
Otherwise it is better to use the above mechanism (interactive login).
```javascript
var someAzureServiceClient = require('azure-arm-someService');
msRestAzure.loginWithUsernamePassword(username, password, function(err, credentials) {
var client = new someAzureServiceClient(credentials, 'your-subscriptionId');
client.someOperationGroup.method(param1, param2, function(err, result) {
if (err) console.log(err);
console.log(result);
});
});
```

#### Login with service principal name and secret
```javascript
var someAzureServiceClient = require('azure-arm-someService');
msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain, function(err, credentials) {
var client = new someAzureServiceClient(credentials, 'your-subscriptionId');
client.someOperationGroup.method(param1, param2, function(err, result) {
if (err) console.log(err);
console.log(result);
});
});
```

### Non-Interactive Authentication
If you need to create an automation account for non interactive or scripting scenarios then please take a look at the documentation over [here](https://github.com/Azure/azure-sdk-for-node/blob/autorest/Documentation/Authentication.md).
If you need to create an automation account for non interactive or scripting scenarios then please take a look at the documentation over [here](https://github.com/Azure/azure-sdk-for-node/blob/master/Documentation/Authentication.md).

## Related Projects

Expand Down
8 changes: 7 additions & 1 deletion runtime/ms-rest-azure/lib/constants.js
Expand Up @@ -14,7 +14,13 @@ var Constants = {
Succeeded: 'Succeeded',
Failed: 'Failed',
Canceled: 'Canceled'
}
},

DEFAULT_ADAL_CLIENT_ID: '04b07795-8ddb-461a-bbee-02f9e1bf7b46',

AAD_COMMON_TENANT: 'common',

DEFAULT_LANGUAGE: 'en-us'
};

exports = module.exports = Constants;
Expand Up @@ -19,7 +19,7 @@ var AzureEnvironment = require('../azureEnvironment');
* @param {object} [options] Object representing optional parameters.
* @param {AzureEnvironment} [options.environment] The azure environment to authenticate with.
* @param {string} [options.authorizationScheme] The authorization scheme. Default value is 'bearer'.
* @param {object} [options.tokenCache] The token cache. Default value is null.
* @param {object} [options.tokenCache] The token cache. Default value is the MemoryCache object from adal.
*/
function ApplicationTokenCredentials(clientId, domain, secret, options) {
if (!Boolean(clientId) || typeof clientId.valueOf() !== 'string') {
Expand All @@ -39,23 +39,60 @@ function ApplicationTokenCredentials(clientId, domain, secret, options) {
}

if (!options.environment) {
this.environment = AzureEnvironment.Azure;
} else {
this.environment = options.environment;
options.environment = AzureEnvironment.Azure;
}

if (!options.authorizationScheme) {
this.authorizationScheme = 'Bearer';
} else {
this.authorizationScheme = options.authorizationScheme;
options.authorizationScheme = Constants.HeaderConstants.AUTHORIZATION_SCHEME;
}


if (!options.tokenCache) {
options.tokenCache = new adal.MemoryCache();
}

this.environment = options.environment;
this.authorizationScheme = options.authorizationScheme;
this.tokenCache = options.tokenCache;
this.clientId = clientId;
this.domain = domain;
this.secret = secret;
var authorityUrl = this.environment.activeDirectoryEndpointUrl + this.domain;
this.context = new adal.AuthenticationContext(authorityUrl, this.environment.validateAuthority, this.tokenCache);
}

function _retrieveTokenFromCache (callback) {
//For service principal userId and clientId are the same thing. Since the token has _clientId property we shall
//retrieve token using it.
this.context.acquireToken(this.environment.activeDirectoryResourceId, null, this.clientId, function (err, result) {
if (err) return callback(err);
return callback(null, result);
});
}

/**
* Tries to get the token from cache initially. If that is unsuccessfull then it tries to get the token from ADAL.
* @param {function} callback The callback in the form (err, result)
* @return {function} callback
* {Error} [err] The error if any
* {object} [tokenResponse] The tokenResponse (tokenType and accessToken are the two important properties).
*/
ApplicationTokenCredentials.prototype.getToken = function (callback) {
var self = this;
_retrieveTokenFromCache.call(this, function (err, result) {
if (err) {
//Some error occured in retrieving the token from cache. May be the cache was empty or the access token expired. Let's try again.
self.context.acquireTokenWithClientCredentials(self.environment.activeDirectoryResourceId, self.clientId, self.secret, function (err, tokenResponse) {
if (err) {
return callback(new Error('Failed to acquire token for application with the provided secret. \n' + err));
}
return callback(null, tokenResponse);
});
} else {
return callback(null, result);
}
});
};

/**
* Signs a request with the Authentication header.
*
Expand All @@ -64,18 +101,11 @@ function ApplicationTokenCredentials(clientId, domain, secret, options) {
* @return {undefined}
*/
ApplicationTokenCredentials.prototype.signRequest = function (webResource, callback) {
var self = this;
var authorityUrl = self.environment.activeDirectoryEndpointUrl + self.domain;
var context = new adal.AuthenticationContext(authorityUrl, self.environment.validateAuthority, self.tokenCache);

context.acquireTokenWithClientCredentials(self.environment.activeDirectoryResourceId, self.clientId, self.secret, function (err, result) {
if (err) {
return callback(new Error('Failed to acquire token for application. \n' + err));
}

this.getToken(function (err, result) {
if (err) return callback(err);
webResource.headers[Constants.HeaderConstants.AUTHORIZATION] =
util.format('%s %s', self.authorizationScheme, result.accessToken);
callback(null);
util.format('%s %s', result.tokenType, result.accessToken);
return callback(null);
});
};

Expand Down

0 comments on commit 931f7b3

Please sign in to comment.