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

Commit 3a2dcb9

Browse files
committed
Merge pull request #51 from AzureAD/dev
0.1.13 release merge
2 parents a8a7936 + af9240c commit 3a2dcb9

File tree

5 files changed

+74
-27
lines changed

5 files changed

+74
-27
lines changed

changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
Version 0.1.13
2+
--------------
3+
Release Date: 1 May 2015
4+
* Scrub security sensitive data in WS-Trust exchange from log messages.
5+
* Update the version of the jws dependency to the latest release.
6+
17
Version 0.1.12
28
--------------
39
Release Date: 19 February 2015

lib/log.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,16 @@ Object.defineProperty(Logger.prototype, 'context', {
138138
/**
139139
* Generates a log entry
140140
* @param {Logging.LOGGING_LEVEL} level The level of this log entry
141-
* @param {string} message A message string to log.
141+
* @param {string|function} message A message string, or a function that returns a message string, to log.
142142
* @param {Error} [error] If this is a {@link Logging.LOGGING_LEVEL.ERROR|ERROR} level log entry then the caller
143143
* should pass an error object in this parameter.
144144
*/
145145
Logger.prototype.log = function(level, message, error) {
146146
if (level <= Logging.LogOptions.level) {
147+
if (_.isFunction(message)) {
148+
message = message();
149+
}
150+
147151
var correlationId = this._logContext.correlationId || '<no correlation id>';
148152

149153
var formattedMessage = correlationId + ' - ' + this._componentName + ': ' + LEVEL_STRING_MAP[level] + ' ' + message;

lib/wstrust-request.js

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ var Logger = require('./log').Logger;
2727
var util = require('./util');
2828
var WSTrustResponse = require('./wstrust-response');
2929

30+
var USERNAME_PLACEHOLDER = '{UsernamePlaceHolder}';
31+
var PASSWORD_PLACEHOLDER = '{PasswordPlaceHolder}';
32+
3033
/**
3134
* Creates a new instance of WSTrustRequest
3235
* @constructor
@@ -42,22 +45,6 @@ function WSTrustRequest(callContext, wstrustEndpointUrl, appliesTo) {
4245
this._appliesTo = appliesTo;
4346
}
4447

45-
/**
46-
* Builds the UsernameToken XML that will carry the user creds in the RST.
47-
* @param {string} username A username
48-
* @param {string} password The password that corresponds to the username parameter.
49-
* @returns {string} A string containing the UsernameToken XML
50-
*/
51-
WSTrustRequest.prototype._buildSoapMessageCredentials = function(username, password) {
52-
var usernameTokenXml =
53-
'<wsse:UsernameToken wsu:Id=\'ADALUsernameToken\'>\
54-
<wsse:Username>' + username + '</wsse:Username>\
55-
<wsse:Password>' + password +'</wsse:Password>\
56-
</wsse:UsernameToken>';
57-
58-
return usernameTokenXml;
59-
};
60-
6148
/**
6249
* Given a Date object adds the minutes parameter and returns a new Date object.
6350
* @private
@@ -80,7 +67,7 @@ function _datePlusMinutes(date, minutes) {
8067
* @param {string} password The passowrd that corresponds to the username parameter.
8168
* @returns {string} A string that contains the soap security header.
8269
*/
83-
WSTrustRequest.prototype._buildSecurityHeader = function(username, password) {
70+
WSTrustRequest.prototype._buildSecurityHeader = function() {
8471
var timeNow = new Date();
8572
var expireTime =
8673
_datePlusMinutes(timeNow, 10);
@@ -92,13 +79,30 @@ _datePlusMinutes(timeNow, 10);
9279
<wsu:Timestamp wsu:Id=\'_0\'>\
9380
<wsu:Created>' + timeNowString + '</wsu:Created>\
9481
<wsu:Expires>' + expireTimeString + '</wsu:Expires>\
95-
</wsu:Timestamp>' +
96-
this._buildSoapMessageCredentials(username, password) +
97-
'</wsse:Security>';
82+
</wsu:Timestamp>\
83+
<wsse:UsernameToken wsu:Id=\'ADALUsernameToken\'>\
84+
<wsse:Username>' + USERNAME_PLACEHOLDER + '</wsse:Username>\
85+
<wsse:Password>' + PASSWORD_PLACEHOLDER + '</wsse:Password>\
86+
</wsse:UsernameToken>\
87+
</wsse:Security>';
9888

9989
return securityHeaderXml;
10090
};
10191

92+
/**
93+
* Replaces the placeholders in the RST template with the actual username and password values.
94+
* @private
95+
* @param {string} RSTTemplate An RST with placeholders for username and password.
96+
* @param {string} username A username
97+
* @param {string} password The passowrd that corresponds to the username parameter.
98+
* @returns {string} A string containing a complete RST soap message.
99+
*/
100+
101+
WSTrustRequest.prototype._populateRSTUsernamePassword = function(RSTTemplate, username, password) {
102+
var RST = RSTTemplate.replace(USERNAME_PLACEHOLDER, username).replace(PASSWORD_PLACEHOLDER, password);
103+
return RST;
104+
};
105+
102106
/**
103107
* Builds a WS-Trust RequestSecurityToken (RST) message using username password authentication.
104108
* @private
@@ -109,7 +113,9 @@ _datePlusMinutes(timeNow, 10);
109113
WSTrustRequest.prototype._buildRST = function(username, password) {
110114
var messageID = uuid.v4();
111115

112-
var RST =
116+
// Create a template RST with placeholders for the username and password so the
117+
// the RST can be logged without the sensitive information.
118+
var RSTTemplate =
113119
'<s:Envelope xmlns:s=\'http://www.w3.org/2003/05/soap-envelope\' xmlns:wsa=\'http://www.w3.org/2005/08/addressing\' xmlns:wsu=\'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\'>\
114120
<s:Header>\
115121
<wsa:Action s:mustUnderstand=\'1\'>http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</wsa:Action>\
@@ -118,7 +124,7 @@ WSTrustRequest.prototype._buildRST = function(username, password) {
118124
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>\
119125
</wsa:ReplyTo>\
120126
<wsa:To s:mustUnderstand=\'1\'>' + this._wstrustEndpointUrl + '</wsa:To>\
121-
' + this._buildSecurityHeader(username, password) + '\
127+
' + this._buildSecurityHeader() + '\
122128
</s:Header>\
123129
<s:Body>\
124130
<wst:RequestSecurityToken xmlns:wst=\'http://docs.oasis-open.org/ws-sx/ws-trust/200512\'>\
@@ -133,6 +139,9 @@ WSTrustRequest.prototype._buildRST = function(username, password) {
133139
</s:Body>\
134140
</s:Envelope>';
135141

142+
this._log.verbose('Created RST: \n' + RSTTemplate);
143+
144+
var RST = this._populateRSTUsernamePassword(RSTTemplate, username, password);
136145
return RST;
137146
};
138147

@@ -176,7 +185,7 @@ WSTrustRequest.prototype.acquireToken = function(username, password, callback) {
176185
}
177186
);
178187

179-
this._log.verbose('Sending RST to: ' + this._wstrustEndpointUrl + '\n' + RST);
188+
this._log.verbose('Sending RST to: ' + this._wstrustEndpointUrl);
180189

181190
request.post(this._wstrustEndpointUrl, options, util.createRequestHandler('WS-Trust RST', this._log, callback,
182191
function(response, body) {

lib/wstrust-response.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,34 @@ var Logger = require('./log').Logger;
2929
var select = xmlutil.xpathSelect;
3030
var DOMParser = xmldom.DOMParser;
3131

32+
// A regular expression for finding the SAML Assertion in an RSTR. Used to remove the SAML
33+
// assertion when logging the RSTR.
34+
var assertionRegEx = /RequestedSecurityToken.*?((<.*?:Assertion.*?>).*<\/.*?Assertion>).*?/;
35+
36+
/**
37+
* Creates a log message that contains the RSTR scrubbed of the actual SAML assertion.
38+
* @private
39+
* @return {string} A log message.
40+
*/
41+
function scrubRSTRLogMessage(RSTR) {
42+
var scrubbedRSTR = null;
43+
44+
var singleLineRSTR = RSTR.replace(/(\r\n|\n|\r)/gm,'');
45+
46+
var matchResult = assertionRegEx.exec(singleLineRSTR);
47+
if (null === matchResult) {
48+
// No Assertion was matched so just return the RSTR as is.
49+
scrubbedRSTR = singleLineRSTR;
50+
} else {
51+
var samlAssertion = matchResult[1];
52+
var samlAssertionStartTag = matchResult[2];
53+
54+
scrubbedRSTR = singleLineRSTR.replace(samlAssertion, samlAssertionStartTag + 'ASSERTION CONTENTS REDACTED</saml:Assertion>');
55+
}
56+
57+
return 'RSTR Response: ' + scrubbedRSTR;
58+
}
59+
3260
/**
3361
* Creates a new WSTrustResponse instance.
3462
* @constructor
@@ -46,7 +74,7 @@ function WSTrustResponse(callContext, response) {
4674
this._tokenType = null;
4775
this._token = null;
4876

49-
this._log.verbose('RSTR Response: ' + this._response);
77+
this._log.verbose(function(){return scrubRSTRLogMessage(response);});
5078
}
5179

5280
/**

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@
1515
"type": "git",
1616
"url": "https://github.com/MSOpenTech/azure-activedirectory-library-for-nodejs.git"
1717
},
18-
"version": "0.1.12",
18+
"version": "0.1.13",
1919
"description": "Windows Azure Active Directory Client Library for node",
2020
"keywords": [ "node", "azure", "AAD", "adal", "adfs", "oauth" ],
2121
"main": "./lib/adal.js",
2222
"engines": { "node": ">= 0.6.15" },
2323
"licenses": [ { "type": "Apache 2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0" } ],
2424
"dependencies": {
2525
"date-utils": "*",
26-
"jws": "1.x.x",
26+
"jws": "3.x.x",
2727
"node-uuid": "1.4.1",
2828
"request": ">= 2.9.203",
2929
"underscore": ">= 1.3.1",

0 commit comments

Comments
 (0)