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

Commit 7be6d5e

Browse files
authored
Merge pull request #194 from AzureAD/dev
Release 0.1.28
2 parents 62088be + 9aa5672 commit 7be6d5e

18 files changed

+108
-56
lines changed

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
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.
33

44
## Versions
5-
Current version - 0.1.27
5+
Current version - 0.1.28
66
Minimum recommended version - 0.1.22
77
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).
88

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

3030
``` $ npm install adal-node ```
3131

32+
### Configure the logging
33+
34+
```javascript
35+
var logging = require('adal-node').Logging;
36+
37+
logging.setLoggingOptions({
38+
log: function(level, message, error) {
39+
// provide your own implementation of the log function
40+
},
41+
level: logging.LOGGING_LEVEL.VERBOSE, // provide the logging level
42+
loggingWithPII: false // Determine if you want to log personal identitification information. The default value is false.
43+
});
44+
```
45+
3246
### Authorization Code
3347

3448
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.
@@ -103,7 +117,7 @@ app.get('/getAToken', function(req, res) {
103117
See the [client credentials sample](https://github.com/MSOpenTech/azure-activedirectory-library-for-nodejs/blob/master/sample/client-credentials-sample.js).
104118

105119
```javascript
106-
var adal = require('adal-node').AuthenticationContext;
120+
var AuthenticationContext = require('adal-node').AuthenticationContext;
107121

108122
var authorityHostUrl = 'https://login.windows.net';
109123
var tenant = 'myTenant.onmicrosoft.com'; // AAD Tenant name.

changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
Version 0.1.28
2+
--------------
3+
Release Date: 26 Feburary 2018
4+
* Added GDPR support per Microsoft policy.
5+
16
Version 0.1.27
27
--------------
38
Release Date: 08 January 2018

lib/adal.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ type LoggingCallback = (level: LoggingLevel, message: string, error?: Error) =>
2525
* @memberOf Logging
2626
* @property {LoggingCallback} [log] The function to call when ADAL generates a log entry.
2727
* @property {LoggingLevel} [level] The maximum level of log entries to generate.
28+
* @property {boolean} [loggingWithPII] This value indicts if personal identity related information such as token and claims should be logged. The default value is false.
2829
*/
2930
interface LoggingOptions {
3031
log?: LoggingCallback;
3132
level?: LoggingLevel;
33+
loggingWithPII?: boolean;
3234
}
3335

3436
export class Logging {

lib/authentication-parameters.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,19 +236,20 @@ exports.createAuthenticationParametersFromUrl = function(url, callback, correlat
236236
var logContext = log.createLogContext(correlationId);
237237
var logger = new log.Logger('AuthenticationParameters', logContext);
238238

239-
logger.verbose('Attempting to retrieve authentication parameters from: ' + challengeUrl);
239+
logger.verbose('Attempting to retrieve authentication parameters');
240+
logger.verbose('Attempting to retrieve authentication parameters from: ' + challengeUrl, true);
240241
var options = util.createRequestOptions( { _callContext : { _logContext: logContext } } );
241242
request.get(challengeUrl, options, function(err, response) {
242243
if (err) {
243-
logger.error('Authentication parameters http get failed.', err);
244+
logger.error('Authentication parameters http get failed.', err, true);
244245
callback(err);
245246
return;
246247
}
247248
var parameters;
248249
try {
249250
parameters = exports.createAuthenticationParametersFromResponse(response);
250251
} catch(creationErr) {
251-
logger.error('Unable to parse response in to authentication paramaters.', creationErr);
252+
logger.error('Unable to parse response in to authentication paramaters.', creationErr, true);
252253
callback(creationErr);
253254
return;
254255
}

lib/authority.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Authority.prototype._performStaticInstanceDiscovery = function() {
135135
};
136136

137137
Authority.prototype._createAuthorityUrl = function() {
138-
return 'https://' + this._url.host + '/' + this._tenant + AADConstants.AUTHORIZE_ENDPOINT_PATH;
138+
return 'https://' + this._url.host + '/' + encodeURIComponent(this._tenant) + AADConstants.AUTHORIZE_ENDPOINT_PATH;
139139
};
140140

141141
/**
@@ -166,7 +166,8 @@ Authority.prototype._performDynamicInstanceDiscovery = function(callback) {
166166

167167
var getOptions = util.createRequestOptions(self);
168168

169-
this._log.verbose('Attempting instance discover at: ' + url.format(discoveryEndpoint));
169+
this._log.verbose('Attempting instance discover');
170+
this._log.verbose('Attempting instance discover at: ' + url.format(discoveryEndpoint), true);
170171
request.get(discoveryEndpoint, getOptions, util.createRequestHandler('Instance Discovery', this._log, callback,
171172
function(response, body) {
172173
var discoveryResponse = JSON.parse(body);
@@ -227,11 +228,11 @@ Authority.prototype._getOAuthEndpoints = function(tenantDiscoveryEndpoint, callb
227228
} else {
228229
// fallback to the well known token endpoint path.
229230
if (!this._tokenEndpoint){
230-
this._tokenEndpoint = url.format('https://' + this._url.host + '/' + this._tenant) + AADConstants.TOKEN_ENDPOINT_PATH;
231+
this._tokenEndpoint = url.format('https://' + this._url.host + '/' + encodeURIComponent(this._tenant)) + AADConstants.TOKEN_ENDPOINT_PATH;
231232
}
232233

233234
if (!this._deviceCodeEndpoint){
234-
this._deviceCodeEndpoint = url.format('https://' + this._url.host + '/' + this._tenant) + AADConstants.DEVICE_ENDPOINT_PATH;
235+
this._deviceCodeEndpoint = url.format('https://' + this._url.host + '/' + encodeURIComponent(this._tenant)) + AADConstants.DEVICE_ENDPOINT_PATH;
235236
}
236237

237238
callback();
@@ -255,7 +256,8 @@ Authority.prototype.validate = function(callContext, callback) {
255256
var self = this;
256257

257258
if (!this._validated) {
258-
this._log.verbose('Performing instance discovery: ' + url.format(this._url));
259+
this._log.verbose('Performing instance discovery');
260+
this._log.verbose('Performing instance discovery: ' + url.format(this._url), true);
259261
this._validateViaInstanceDiscovery(function(err, tenantDiscoveryEndpoint) {
260262
if (err)
261263
{
@@ -267,7 +269,8 @@ Authority.prototype.validate = function(callContext, callback) {
267269
}
268270
});
269271
} else {
270-
this._log.verbose('Instance discovery/validation has either already been completed or is turned off: ' + url.format(this._url));
272+
this._log.verbose('Instance discovery/validation has either already been completed or is turned off');
273+
this._log.verbose('Instance discovery/validation has either already been completed or is turned off: ' + url.format(this._url), true);
271274
this._getOAuthEndpoints(null, callback);
272275
return;
273276
}

lib/cache-driver.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ CacheDriver.prototype._getPotentialEntries = function(query, callback) {
157157
}
158158

159159
this._log.verbose('Looking for potential cache entries:');
160-
this._log.verbose(JSON.stringify(potentialEntriesQuery));
160+
this._log.verbose(JSON.stringify(potentialEntriesQuery), true);
161161
this._find(potentialEntriesQuery, function(err, entries) {
162162
self._log.verbose('Found ' + entries.length + ' potential entries.');
163163
callback(err, entries);
@@ -225,7 +225,8 @@ CacheDriver.prototype._loadSingleEntryFromCache = function(query, callback) {
225225
}
226226
}
227227
if (returnVal) {
228-
self._log.verbose('Returning token from cache lookup, ' + createTokenIdMessage(returnVal));
228+
self._log.verbose('Returning token from cache lookup');
229+
self._log.verbose('Returning token from cache lookup, ' + createTokenIdMessage(returnVal), true);
229230
}
230231
callback(null, returnVal, isResourceTenantSpecific);
231232
});
@@ -279,7 +280,7 @@ CacheDriver.prototype._refreshExpiredEntry = function(entry, callback) {
279280
var newEntry = self._createEntryFromRefresh(entry, tokenResponse);
280281
self._replaceEntry(entry, newEntry, function(err) {
281282
if (err) {
282-
self._log.error('error refreshing expired token', err);
283+
self._log.error('error refreshing expired token', err, true);
283284
} else {
284285
self._log.info('Returning token refreshed after expiry.');
285286
}
@@ -304,7 +305,7 @@ CacheDriver.prototype._acquireNewTokenFromMrrt = function(entry, callback) {
304305
var newEntry = self._createEntryFromRefresh(entry, tokenResponse);
305306
self.add(newEntry, function(err) {
306307
if (err) {
307-
self._log.error('error refreshing mrrt', err);
308+
self._log.error('error refreshing mrrt', err, true);
308309
} else {
309310
self._log.info('Returning token derived from mrrt refresh.');
310311
}
@@ -348,7 +349,8 @@ CacheDriver.prototype._refreshEntryIfNecessary = function(entry, isResourceSpeci
348349
CacheDriver.prototype.find = function(query, callback) {
349350
var self = this;
350351
query = query || {};
351-
this._log.verbose('finding with query:' + JSON.stringify(query));
352+
this._log.verbose('finding using query');
353+
this._log.verbose('finding with query:' + JSON.stringify(query), true);
352354
this._loadSingleEntryFromCache(query, function(err, entry, isResourceTenantSpecific) {
353355
if (err) {
354356
callback(err);
@@ -499,6 +501,7 @@ CacheDriver.prototype._augmentEntryWithCacheMetadata = function(entry) {
499501
*/
500502
CacheDriver.prototype.add = function(entry, callback) {
501503
var self = this;
504+
this._log.verbose('Adding entry');
502505
this._log.verbose('Adding entry, ' + createTokenIdMessage(entry));
503506

504507
this._augmentEntryWithCacheMetadata(entry);

lib/log.js

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ var Logging = {
9292
options.level = this.LOGGING_LEVEL.ERROR;
9393
}
9494

95+
if (options.loggingWithPII != true) {
96+
options.loggingWithPII = false;
97+
}
98+
9599
this.LogOptions = options;
96100
},
97101

@@ -111,6 +115,7 @@ var Logging = {
111115
LogOptions : {
112116
log : function() {},
113117
level : 0,
118+
loggingWithPII: false
114119
}
115120
};
116121

@@ -141,8 +146,13 @@ Object.defineProperty(Logger.prototype, 'context', {
141146
* @param {string|function} message A message string, or a function that returns a message string, to log.
142147
* @param {Error} [error] If this is a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry then the caller
143148
* should pass an error object in this parameter.
149+
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
144150
*/
145-
Logger.prototype.log = function(level, message, error) {
151+
Logger.prototype.log = function (level, message, error, containsPII) {
152+
if (containsPII == true && !Logging.LogOptions.loggingWithPII) {
153+
return;
154+
}
155+
146156
if (level <= Logging.LogOptions.level) {
147157
if (_.isFunction(message)) {
148158
message = message();
@@ -163,43 +173,48 @@ Logger.prototype.log = function(level, message, error) {
163173
* Generate an {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry.
164174
* @param {string} message A message to log
165175
* @param {Error} error The Error object associated with this log entry
176+
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
166177
*/
167-
Logger.prototype.error = function(message, error) {
168-
this.log(Logging.LOGGING_LEVEL.ERROR, message, error);
178+
Logger.prototype.error = function (message, error, containsPII) {
179+
this.log(Logging.LOGGING_LEVEL.ERROR, message, error, containsPII);
169180
};
170181

171182
/**
172183
* Generate an {@link Logging.LOGGING_LEVEL.WARN|WARN} level log entry.
173184
* @param {string} message A message to log
185+
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
174186
*/
175-
Logger.prototype.warn = function(message) {
176-
this.log(Logging.LOGGING_LEVEL.WARN, message, null);
187+
Logger.prototype.warn = function (message, containsPII) {
188+
this.log(Logging.LOGGING_LEVEL.WARN, message, null, containsPII);
177189
};
178190

179191
/**
180192
* Generate an {@link Logging.LOGGING_LEVEL.INFO|INFO} level log entry.
181193
* @param {string} message A message to log
194+
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
182195
*/
183-
Logger.prototype.info = function(message) {
184-
this.log(Logging.LOGGING_LEVEL.INFO, message, null);
196+
Logger.prototype.info = function (message, containsPII) {
197+
this.log(Logging.LOGGING_LEVEL.INFO, message, null, containsPII);
185198
};
186199

187200
/**
188201
* Generate an {@link Logging.LOGGING_LEVEL.VERBOSE|VERBOSE} level log entry.
189202
* @param {string} message A message to log
203+
* @param {boolean} [containsPII] Determines if the log message contains personal information. Default value is false.
190204
*/
191-
Logger.prototype.verbose = function(message) {
192-
this.log(Logging.LOGGING_LEVEL.VERBOSE, message, null);
205+
Logger.prototype.verbose = function (message, containsPII) {
206+
this.log(Logging.LOGGING_LEVEL.VERBOSE, message, null, containsPII);
193207
};
194208

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

lib/mex.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ function Mex(callContext, url) {
4747
this._dom = null;
4848
this._mexDoc = null;
4949
this._usernamePasswordPolicy = {};
50-
this._log.verbose('Mex created with url: ' + url);
50+
this._log.verbose('Mex created');
51+
this._log.verbose('Mex created with url: ' + url, true);
5152
}
5253

5354
/**
@@ -75,6 +76,7 @@ Object.defineProperty(Mex.prototype, 'usernamePasswordPolicy', {
7576
* @param {Mex.DiscoverCallback} callback Called when discover is complete.
7677
*/
7778
Mex.prototype.discover = function (callback) {
79+
this._log.verbose('Retrieving mex');
7880
this._log.verbose('Retrieving mex at: ' + this._url);
7981
var self = this;
8082
var options = util.createRequestOptions(self, { headers : { 'Content-Type' : 'application/soap+xml'} });
@@ -89,7 +91,7 @@ Mex.prototype.discover = function (callback) {
8991
self._parse(callback);
9092
return;
9193
} catch (err) {
92-
self._log.error('Failed to parse mex response in to DOM', err);
94+
self._log.error('Failed to parse mex response in to DOM', err, true);
9395
callback(err);
9496
}
9597
})
@@ -119,12 +121,14 @@ Mex.prototype._checkPolicy = function(policyNode) {
119121
}
120122
}
121123
if (policyId) {
122-
this._log.verbose('found matching policy id: ' + policyId);
124+
this._log.verbose('found matching policy id');
125+
this._log.verbose('found matching policy id: ' + policyId, true);
123126
} else {
124127
if (!id) {
125128
id = '<no id>';
126129
}
127-
this._log.verbose('potential policy did not match required transport binding: ' + id);
130+
this._log.verbose('potential policy did not match required transport binding');
131+
this._log.verbose('potential policy did not match required transport binding: ' + id, true);
128132
}
129133
return policyId;
130134
};

lib/oauth2client.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,9 @@ OAuth2Client.prototype._parseIdToken = function(encodedIdToken) {
228228
}
229229

230230
idToken = JSON.parse(base64Decoded);
231-
} catch(err) {
232-
this._log.warn('The returned id_token could not be decoded: ' + err.stack);
231+
} catch (err) {
232+
this._log.warn('the returned id_token could not be decoded');
233+
this._log.warn('The returned id_token could not be decoded: ' + err.stack, true);
233234
return;
234235
}
235236

@@ -379,7 +380,7 @@ OAuth2Client.prototype._handleGetTokenResponse = function(response, body, callba
379380
try {
380381
tokenResponse = this._validateTokenResponse(body);
381382
} catch (e) {
382-
this._log.error('Error validating get token response', e);
383+
this._log.error('Error validating get token response', e, true);
383384
callback(e);
384385
return;
385386
}
@@ -391,7 +392,7 @@ OAuth2Client.prototype._handleGetDeviceCodeResponse = function(response, body, c
391392
try {
392393
deviceCodeResponse = this._validateDeviceCodeResponse(body);
393394
} catch (e) {
394-
this._log.error('Error validating get user code response', e);
395+
this._log.error('Error validating get user code response', e, true);
395396
callback(e);
396397
return;
397398
}
@@ -421,7 +422,7 @@ OAuth2Client.prototype._getTokenWithPolling = function (postOptions, callback) {
421422
try {
422423
tokenResponse = self._handlePollingResponse(body);
423424
} catch (e) {
424-
self._log.error('Error validating get token response', e);
425+
self._log.error('Error validating get token response', e, true);
425426
callback(null, e);
426427
return;
427428
}

lib/self-signed-jwt.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ SelfSignedJwt.prototype._createHeader = function(thumbprint) {
8787
var x5t = this._createx5tValue(thumbprint);
8888
var header = { typ: 'JWT', alg: 'RS256', x5t : x5t };
8989

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

9293
return header;
9394
};
@@ -129,7 +130,7 @@ SelfSignedJwt.prototype._signJwt = function(header, payload, certificate) {
129130
jwt = jws.sign({ header : header, payload : payload, secret : certificate });
130131
}
131132
catch (err) {
132-
this._log.error(err);
133+
this._log.error(err, true);
133134
throw this._log.createError('Failed to sign JWT.This is most likely due to an invalid certificate.');
134135
}
135136

0 commit comments

Comments
 (0)