Skip to content
This repository has been archived by the owner on Aug 7, 2021. It is now read-only.

Commit

Permalink
gdpr work
Browse files Browse the repository at this point in the history
  • Loading branch information
lovemaths committed Feb 27, 2018
1 parent 606fa2a commit 6e6fa70
Show file tree
Hide file tree
Showing 18 changed files with 104 additions and 52 deletions.
16 changes: 15 additions & 1 deletion README.md
Expand Up @@ -2,7 +2,7 @@
The ADAL for node.js library makes it easy for node.js applications to authenticate to AAD in order to access AAD protected web resources. It supports 3 authentication modes shown in the quickstart code below.

## Versions
Current version - 0.1.27
Current version - 0.1.28
Minimum recommended version - 0.1.22
You can find the changes for each version in the [change log](https://github.com/AzureAD/azure-activedirectory-library-for-nodejs/blob/master/changelog.txt).

Expand All @@ -29,6 +29,20 @@ All code is licensed under the Apache 2.0 license and we triage actively on GitH

``` $ npm install adal-node ```

### Configure the logging

```javascript
var logging = require('adal-node').Logging;

logging.setLoggingOptions({
log: function(level, message, error) {
// provide your own implementation of the log function
},
level: logging.LOGGING_LEVEL.VERBOSE, // provide the logging level
loggingWithPII: false // Determine if you want to log personal identitification information. The default value is false.
});
```

### Authorization Code

See the [website sample](https://github.com/MSOpenTech/azure-activedirectory-library-for-nodejs/blob/master/sample/website-sample.js) for a complete bare bones express based web site that makes use of the code below.
Expand Down
5 changes: 5 additions & 0 deletions changelog.md
@@ -1,3 +1,8 @@
Version 0.1.28
--------------
Release Date: 26 Feburary 2018
* Added GDPR support per Microsoft policy.

Version 0.1.27
--------------
Release Date: 08 January 2018
Expand Down
2 changes: 2 additions & 0 deletions lib/adal.d.ts
Expand Up @@ -25,10 +25,12 @@ type LoggingCallback = (level: LoggingLevel, message: string, error?: Error) =>
* @memberOf Logging
* @property {LoggingCallback} [log] The function to call when ADAL generates a log entry.
* @property {LoggingLevel} [level] The maximum level of log entries to generate.
* @property {boolean} [loggingWithPII] This value indicts if personal identity related information such as token and claims should be logged. The default value is false.
*/
interface LoggingOptions {
log?: LoggingCallback;
level?: LoggingLevel;
loggingWithPII?: boolean;
}

export class Logging {
Expand Down
7 changes: 4 additions & 3 deletions lib/authentication-parameters.js
Expand Up @@ -236,19 +236,20 @@ exports.createAuthenticationParametersFromUrl = function(url, callback, correlat
var logContext = log.createLogContext(correlationId);
var logger = new log.Logger('AuthenticationParameters', logContext);

logger.verbose('Attempting to retrieve authentication parameters from: ' + challengeUrl);
logger.verbose('Attempting to retrieve authentication parameters');
logger.verbose('Attempting to retrieve authentication parameters from: ' + challengeUrl, true);
var options = util.createRequestOptions( { _callContext : { _logContext: logContext } } );
request.get(challengeUrl, options, function(err, response) {
if (err) {
logger.error('Authentication parameters http get failed.', err);
logger.error('Authentication parameters http get failed.', err, true);
callback(err);
return;
}
var parameters;
try {
parameters = exports.createAuthenticationParametersFromResponse(response);
} catch(creationErr) {
logger.error('Unable to parse response in to authentication paramaters.', creationErr);
logger.error('Unable to parse response in to authentication paramaters.', creationErr, true);
callback(creationErr);
return;
}
Expand Down
9 changes: 6 additions & 3 deletions lib/authority.js
Expand Up @@ -166,7 +166,8 @@ Authority.prototype._performDynamicInstanceDiscovery = function(callback) {

var getOptions = util.createRequestOptions(self);

this._log.verbose('Attempting instance discover at: ' + url.format(discoveryEndpoint));
this._log.verbose('Attempting instance discover');
this._log.verbose('Attempting instance discover at: ' + url.format(discoveryEndpoint), true);
request.get(discoveryEndpoint, getOptions, util.createRequestHandler('Instance Discovery', this._log, callback,
function(response, body) {
var discoveryResponse = JSON.parse(body);
Expand Down Expand Up @@ -255,7 +256,8 @@ Authority.prototype.validate = function(callContext, callback) {
var self = this;

if (!this._validated) {
this._log.verbose('Performing instance discovery: ' + url.format(this._url));
this._log.verbose('Performing instance discovery');
this._log.verbose('Performing instance discovery: ' + url.format(this._url), true);
this._validateViaInstanceDiscovery(function(err, tenantDiscoveryEndpoint) {
if (err)
{
Expand All @@ -267,7 +269,8 @@ Authority.prototype.validate = function(callContext, callback) {
}
});
} else {
this._log.verbose('Instance discovery/validation has either already been completed or is turned off: ' + url.format(this._url));
this._log.verbose('Instance discovery/validation has either already been completed or is turned off');
this._log.verbose('Instance discovery/validation has either already been completed or is turned off: ' + url.format(this._url), true);
this._getOAuthEndpoints(null, callback);
return;
}
Expand Down
13 changes: 8 additions & 5 deletions lib/cache-driver.js
Expand Up @@ -157,7 +157,7 @@ CacheDriver.prototype._getPotentialEntries = function(query, callback) {
}

this._log.verbose('Looking for potential cache entries:');
this._log.verbose(JSON.stringify(potentialEntriesQuery));
this._log.verbose(JSON.stringify(potentialEntriesQuery), true);
this._find(potentialEntriesQuery, function(err, entries) {
self._log.verbose('Found ' + entries.length + ' potential entries.');
callback(err, entries);
Expand Down Expand Up @@ -225,7 +225,8 @@ CacheDriver.prototype._loadSingleEntryFromCache = function(query, callback) {
}
}
if (returnVal) {
self._log.verbose('Returning token from cache lookup, ' + createTokenIdMessage(returnVal));
self._log.verbose('Returning token from cache lookup');
self._log.verbose('Returning token from cache lookup, ' + createTokenIdMessage(returnVal), true);
}
callback(null, returnVal, isResourceTenantSpecific);
});
Expand Down Expand Up @@ -279,7 +280,7 @@ CacheDriver.prototype._refreshExpiredEntry = function(entry, callback) {
var newEntry = self._createEntryFromRefresh(entry, tokenResponse);
self._replaceEntry(entry, newEntry, function(err) {
if (err) {
self._log.error('error refreshing expired token', err);
self._log.error('error refreshing expired token', err, true);
} else {
self._log.info('Returning token refreshed after expiry.');
}
Expand All @@ -304,7 +305,7 @@ CacheDriver.prototype._acquireNewTokenFromMrrt = function(entry, callback) {
var newEntry = self._createEntryFromRefresh(entry, tokenResponse);
self.add(newEntry, function(err) {
if (err) {
self._log.error('error refreshing mrrt', err);
self._log.error('error refreshing mrrt', err, true);
} else {
self._log.info('Returning token derived from mrrt refresh.');
}
Expand Down Expand Up @@ -348,7 +349,8 @@ CacheDriver.prototype._refreshEntryIfNecessary = function(entry, isResourceSpeci
CacheDriver.prototype.find = function(query, callback) {
var self = this;
query = query || {};
this._log.verbose('finding with query:' + JSON.stringify(query));
this._log.verbose('finding using query');
this._log.verbose('finding with query:' + JSON.stringify(query), true);
this._loadSingleEntryFromCache(query, function(err, entry, isResourceTenantSpecific) {
if (err) {
callback(err);
Expand Down Expand Up @@ -499,6 +501,7 @@ CacheDriver.prototype._augmentEntryWithCacheMetadata = function(entry) {
*/
CacheDriver.prototype.add = function(entry, callback) {
var self = this;
this._log.verbose('Adding entry');
this._log.verbose('Adding entry, ' + createTokenIdMessage(entry));

this._augmentEntryWithCacheMetadata(entry);
Expand Down
37 changes: 26 additions & 11 deletions lib/log.js
Expand Up @@ -92,6 +92,10 @@ var Logging = {
options.level = this.LOGGING_LEVEL.ERROR;
}

if (options.loggingWithPII != true) {
options.loggingWithPII = false;
}

this.LogOptions = options;
},

Expand All @@ -111,6 +115,7 @@ var Logging = {
LogOptions : {
log : function() {},
level : 0,
loggingWithPII: false
}
};

Expand Down Expand Up @@ -141,8 +146,13 @@ Object.defineProperty(Logger.prototype, 'context', {
* @param {string|function} message A message string, or a function that returns a message string, to log.
* @param {Error} [error] If this is a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry then the caller
* should pass an error object in this parameter.
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
*/
Logger.prototype.log = function(level, message, error) {
Logger.prototype.log = function (level, message, error, containsPII) {
if (containsPII == true && !Logging.LogOptions.loggingWithPII) {
return;
}

if (level <= Logging.LogOptions.level) {
if (_.isFunction(message)) {
message = message();
Expand All @@ -163,43 +173,48 @@ Logger.prototype.log = function(level, message, error) {
* Generate an {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry.
* @param {string} message A message to log
* @param {Error} error The Error object associated with this log entry
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
*/
Logger.prototype.error = function(message, error) {
this.log(Logging.LOGGING_LEVEL.ERROR, message, error);
Logger.prototype.error = function (message, error, containsPII) {
this.log(Logging.LOGGING_LEVEL.ERROR, message, error, containsPII);
};

/**
* Generate an {@link Logging.LOGGING_LEVEL.WARN|WARN} level log entry.
* @param {string} message A message to log
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
*/
Logger.prototype.warn = function(message) {
this.log(Logging.LOGGING_LEVEL.WARN, message, null);
Logger.prototype.warn = function (message, containsPII) {
this.log(Logging.LOGGING_LEVEL.WARN, message, null, containsPII);
};

/**
* Generate an {@link Logging.LOGGING_LEVEL.INFO|INFO} level log entry.
* @param {string} message A message to log
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
*/
Logger.prototype.info = function(message) {
this.log(Logging.LOGGING_LEVEL.INFO, message, null);
Logger.prototype.info = function (message, containsPII) {
this.log(Logging.LOGGING_LEVEL.INFO, message, null, containsPII);
};

/**
* Generate an {@link Logging.LOGGING_LEVEL.VERBOSE|VERBOSE} level log entry.
* @param {string} message A message to log
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
*/
Logger.prototype.verbose = function(message) {
this.log(Logging.LOGGING_LEVEL.VERBOSE, message, null);
Logger.prototype.verbose = function (message, containsPII) {
this.log(Logging.LOGGING_LEVEL.VERBOSE, message, null, containsPII);
};

/**
* Generate a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry, as well as an
* Error object to go with it. This is a convenience method for throwing logged errors.
* @param {string} message A message to log
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
*/
Logger.prototype.createError = function(message) {
Logger.prototype.createError = function(message, containsPII) {
var err = new Error(message);
this.error(message, err);
this.error(message, err, containsPII);
return err;
};

Expand Down
12 changes: 8 additions & 4 deletions lib/mex.js
Expand Up @@ -47,7 +47,8 @@ function Mex(callContext, url) {
this._dom = null;
this._mexDoc = null;
this._usernamePasswordPolicy = {};
this._log.verbose('Mex created with url: ' + url);
this._log.verbose('Mex created');
this._log.verbose('Mex created with url: ' + url, true);
}

/**
Expand Down Expand Up @@ -75,6 +76,7 @@ Object.defineProperty(Mex.prototype, 'usernamePasswordPolicy', {
* @param {Mex.DiscoverCallback} callback Called when discover is complete.
*/
Mex.prototype.discover = function (callback) {
this._log.verbose('Retrieving mex');
this._log.verbose('Retrieving mex at: ' + this._url);
var self = this;
var options = util.createRequestOptions(self, { headers : { 'Content-Type' : 'application/soap+xml'} });
Expand All @@ -89,7 +91,7 @@ Mex.prototype.discover = function (callback) {
self._parse(callback);
return;
} catch (err) {
self._log.error('Failed to parse mex response in to DOM', err);
self._log.error('Failed to parse mex response in to DOM', err, true);
callback(err);
}
})
Expand Down Expand Up @@ -119,12 +121,14 @@ Mex.prototype._checkPolicy = function(policyNode) {
}
}
if (policyId) {
this._log.verbose('found matching policy id: ' + policyId);
this._log.verbose('found matching policy id');
this._log.verbose('found matching policy id: ' + policyId, true);
} else {
if (!id) {
id = '<no id>';
}
this._log.verbose('potential policy did not match required transport binding: ' + id);
this._log.verbose('potential policy did not match required transport binding');
this._log.verbose('potential policy did not match required transport binding: ' + id, true);
}
return policyId;
};
Expand Down
11 changes: 6 additions & 5 deletions lib/oauth2client.js
Expand Up @@ -228,8 +228,9 @@ OAuth2Client.prototype._parseIdToken = function(encodedIdToken) {
}

idToken = JSON.parse(base64Decoded);
} catch(err) {
this._log.warn('The returned id_token could not be decoded: ' + err.stack);
} catch (err) {
this._log.warn('the returned id_token could not be decoded');
this._log.warn('The returned id_token could not be decoded: ' + err.stack, true);
return;
}

Expand Down Expand Up @@ -379,7 +380,7 @@ OAuth2Client.prototype._handleGetTokenResponse = function(response, body, callba
try {
tokenResponse = this._validateTokenResponse(body);
} catch (e) {
this._log.error('Error validating get token response', e);
this._log.error('Error validating get token response', e, true);
callback(e);
return;
}
Expand All @@ -391,7 +392,7 @@ OAuth2Client.prototype._handleGetDeviceCodeResponse = function(response, body, c
try {
deviceCodeResponse = this._validateDeviceCodeResponse(body);
} catch (e) {
this._log.error('Error validating get user code response', e);
this._log.error('Error validating get user code response', e, true);
callback(e);
return;
}
Expand Down Expand Up @@ -421,7 +422,7 @@ OAuth2Client.prototype._getTokenWithPolling = function (postOptions, callback) {
try {
tokenResponse = self._handlePollingResponse(body);
} catch (e) {
self._log.error('Error validating get token response', e);
self._log.error('Error validating get token response', e, true);
callback(null, e);
return;
}
Expand Down
5 changes: 3 additions & 2 deletions lib/self-signed-jwt.js
Expand Up @@ -87,7 +87,8 @@ SelfSignedJwt.prototype._createHeader = function(thumbprint) {
var x5t = this._createx5tValue(thumbprint);
var header = { typ: 'JWT', alg: 'RS256', x5t : x5t };

this._log.verbose('Creating self signed JWT header. x5t: ' + x5t);
this._log.verbose('Creating self signed JWT header');
this._log.verbose('Creating self signed JWT header. x5t: ' + x5t, true);

return header;
};
Expand Down Expand Up @@ -129,7 +130,7 @@ SelfSignedJwt.prototype._signJwt = function(header, payload, certificate) {
jwt = jws.sign({ header : header, payload : payload, secret : certificate });
}
catch (err) {
this._log.error(err);
this._log.error(err, true);
throw this._log.createError('Failed to sign JWT.This is most likely due to an invalid certificate.');
}

Expand Down
8 changes: 5 additions & 3 deletions lib/token-request.js
Expand Up @@ -139,7 +139,8 @@ TokenRequest.prototype._getTokenWithCacheWrapper = function(callback, getTokenFu
var cacheQuery = this._createCacheQuery();
this._cacheDriver.find(cacheQuery, function(err, token) {
if (err) {
self._log.warn('Attempt to look for token in cache resulted in Error: ' + err.stack);
self._log.warn('Attempt to look for token in cahce resulted in Error');
self._log.warn('Attempt to look for token in cache resulted in Error: ' + err.stack, true);
}

if (!token) {
Expand Down Expand Up @@ -290,7 +291,7 @@ TokenRequest.prototype._performWSTrustExchange = function(wstrustEndpoint, wstru
}

if (!response.token) {
var rstrErr = self._log.createError('Unsucessful RSTR.\n\terror code: ' + response.errorCode + '\n\tfaultMessage: ' + response.faultMessage);
var rstrErr = self._log.createError('Unsucessful RSTR.\n\terror code: ' + response.errorCode + '\n\tfaultMessage: ' + response.faultMessage, true);
callback(rstrErr);
return;
}
Expand Down Expand Up @@ -350,7 +351,8 @@ TokenRequest.prototype._getTokenUsernamePasswordFederated = function(username, p
return;
} else {
var mexEndpoint = this._userRealm.federationMetadataUrl;
this._log.verbose('Attempting mex at: ' + mexEndpoint);
this._log.verbose('Attempting mex');
this._log.verbose('Attempting mex at: ' + mexEndpoint, true);
var mex = this._createMex(mexEndpoint);
mex.discover(function(mexErr) {
var wstrustEndpoint;
Expand Down

0 comments on commit 6e6fa70

Please sign in to comment.