Skip to content

Commit

Permalink
updates to node.js clientruntime (Azure#1070)
Browse files Browse the repository at this point in the history
* inital commit

* minor update

* some more updates

* UserTokenCredentials use the token cache to retrieve tokens

* updates to node.js clientruntime

* update readme
  • Loading branch information
amarzavery committed May 22, 2016
1 parent 3cb1bec commit f9a1606
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace Microsoft.Rest.Generator.Azure.NodeJS
{
public class AzureNodeJSCodeGenerator : NodeJSCodeGenerator
{
private const string ClientRuntimePackage = "ms-rest-azure version 1.14.0";
private const string ClientRuntimePackage = "ms-rest-azure version 1.14.2";

// List of models with paging extensions.
private IList<PageTemplateModel> pageModels;
Expand Down
2 changes: 1 addition & 1 deletion AutoRest/Generators/NodeJS/NodeJS/NodeJSCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Microsoft.Rest.Generator.NodeJS
{
public class NodeJSCodeGenerator : CodeGenerator
{
private const string ClientRuntimePackage = "ms-rest version 1.14.0";
private const string ClientRuntimePackage = "ms-rest version 1.14.2";

public NodeJsCodeNamer Namer { get; private set; }

Expand Down
12 changes: 10 additions & 2 deletions ClientRuntimes/NodeJS/ms-rest-azure/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,18 @@ Otherwise it is better to use the above mechanism (interactive login).
});
```

### ServicePrincipal authentication
#### Login with service principal name and secret
```javascript
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);
});
});
```

### 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/master/Documentation/Authentication.md).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,39 @@ function ApplicationTokenCredentials(clientId, domain, secret, options) {
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 @@ -68,15 +101,11 @@ function ApplicationTokenCredentials(clientId, domain, secret, options) {
* @return {undefined}
*/
ApplicationTokenCredentials.prototype.signRequest = function (webResource, callback) {
var self = this;
self.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
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,35 @@ function UserTokenCredentials(clientId, domain, username, password, options) {
this.context = new adal.AuthenticationContext(authorityUrl, this.environment.validateAuthority, this.tokenCache);
}

UserTokenCredentials.prototype.retrieveTokenFromCache = function (callback) {
var self = this;
self.context.acquireToken(self.environment.activeDirectoryResourceId, self.username, self.clientId, function (err, result) {
function _retrieveTokenFromCache(callback) {
this.context.acquireToken(this.environment.activeDirectoryResourceId, this.username, this.clientId, function (err, result) {
if (err) return callback(err);
return callback(null, result.tokenType, result.accessToken);
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).
*/
UserTokenCredentials.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. Let's try again.
self.context.acquireTokenWithUsernamePassword(self.environment.activeDirectoryResourceId, self.username,
self.password, self.clientId, function (err, tokenResponse) {
if (err) {
return callback(new Error('Failed to acquire token for the user. \n' + err));
}
return callback(null, tokenResponse);
});
} else {
return callback(null, result);
}
});
};

Expand All @@ -83,9 +107,10 @@ UserTokenCredentials.prototype.retrieveTokenFromCache = function (callback) {
* @return {undefined}
*/
UserTokenCredentials.prototype.signRequest = function (webResource, callback) {
return this.retrieveTokenFromCache(function(err, scheme, token) {
this.getToken(function (err, result) {
if (err) return callback(err);
webResource.headers[Constants.HeaderConstants.AUTHORIZATION] = util.format('%s %s', scheme, token);
webResource.headers[Constants.HeaderConstants.AUTHORIZATION] =
util.format('%s %s', result.tokenType, result.accessToken);
return callback(null);
});
};
Expand Down
102 changes: 98 additions & 4 deletions ClientRuntimes/NodeJS/ms-rest-azure/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,40 @@ export interface AzureTokenCredentialsOptions {
*/
authorizationScheme?: string;

// TODO: What type should this really have? How is it used?
/**
* The token cache. Default value is null.
* The token cache. Default value is MemoryCache from adal.
*/
tokenCache?: any;
}

export interface LoginWithUsernamePasswordOptions extends AzureTokenCredentialsOptions {
/**
* The domain or tenant id containing this application. Default value is 'common'.
*/
domain?: string;

/**
* 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.
*/
clientId?: string
}

export interface DeviceTokenCredentialsOptions extends LoginWithUsernamePasswordOptions {
/**
* The user name for account in the form: 'user@example.com'. Default value is 'user@example.com'.
*/
username?: string;
}

export interface InteractiveLoginOptions extends DeviceTokenCredentialsOptions {
/**
* The language code specifying how the message should be localized to. Default value 'en-us'.
*/
language?: string;
}

export class ApplicationTokenCredentials extends msRest.ServiceClientCredentials {
/**
* Creates a new ApplicationTokenCredentials object.
Expand All @@ -179,12 +206,79 @@ export class UserTokenCredentials extends msRest.ServiceClientCredentials {
* @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} clientRedirectUri The Uri where the user will be redirected after authenticating with AD.
* @param {AzureTokenCredentialsOptions} options Object representing optional parameters.
*/
constructor(clientId: string, domain: string, username: string, password: string, clientRedirectUri: string, options?: AzureTokenCredentialsOptions);
constructor(clientId: string, domain: string, username: string, password: string, options?: AzureTokenCredentialsOptions);
}

export class DeviceTokenCredentials extends msRest.ServiceClientCredentials {
/**
* Creates a new DeviceTokenCredentials object.
* @param {DeviceTokenCredentialsOptions} options Object representing optional parameters.
*/
constructor(options?: DeviceTokenCredentialsOptions);
}

// TODO: WHAT SHOULD WE EXPOSE HERE?
export class BaseResource {
}

/**
* Provides a url and code that needs to be copy and pasted in a browser and authenticated over there. If successful, the user will get a
* DeviceTokenCredentials object
*
* @param {InteractiveLoginOptions} [options] The parameter options.
*
* @param {function} callback
*
* @returns {function} callback(err, credentials)
*
* {Error} [err] - The Error object if an error occurred, null otherwise.
*
* {DeviceTokenCredentials} [credentials] - The DeviceTokenCredentials object
*/
export function interactiveLogin (options?: InteractiveLoginOptions, callback);

/**
* Provides a UserTokenCredentials object. This method is applicable only for organizational ids that are not 2FA enabled.
* Otherwise please use interactive login.
*
* @param {string} username The user name for the Organization Id account.
*
* @param {string} password The password for the Organization Id account.
*
* @param {LoginWithUsernamePasswordOptions} [options] The parameter options.
*
* @param {function} callback
*
* @returns {function} callback(err, credentials)
*
* {Error} [err] - The Error object if an error occurred, null otherwise.
*
* {UserTokenCredentials} [credentials] - The UserTokenCredentials object
*/
export function loginWithUsernamePassword (username: string, password: string, options?: LoginWithUsernamePasswordOptions, callback);


/**
* Provides an ApplicationTokenCredentials object.
*
* @param {string} clientId The active directory application client id also known as the SPN (ServicePrincipal Name).
* See {@link https://azure.microsoft.com/en-us/documentation/articles/active-directory-devquickstarts-dotnet/ Active Directory Quickstart for .Net}
* for an example.
*
* @param {string} secret The application secret for the service principal.
*
* @param {string} domain The domain or tenant id containing this application.
*
* @param {AzureTokenCredentialsOptions} [options] The parameter options.
*
* @param {function} callback
*
* @returns {function} callback(err, credentials)
*
* {Error} [err] - The Error object if an error occurred, null otherwise.
*
* {ApplicationTokenCredentials} [credentials] - The ApplicationTokenCredentials object
*/
export function loginWithServicePrincipalSecret (clientId: string, secret: string, domain: string, options?: AzureTokenCredentialsOptions, callback);
Loading

0 comments on commit f9a1606

Please sign in to comment.