@itentialopensource/adapter-utils 4.48.5 → 4.48.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/MFA.md +43 -0
- package/lib/connectorRest.js +1104 -754
- package/lib/propertyUtil.js +1 -1
- package/package.json +4 -3
- package/schemas/propertiesSchema.json +2 -1
package/lib/connectorRest.js
CHANGED
|
@@ -47,6 +47,7 @@ let basepath = null;
|
|
|
47
47
|
let version = null;
|
|
48
48
|
let choosepath = null;
|
|
49
49
|
let authMethod = null;
|
|
50
|
+
let multiStepAuthCalls = null;
|
|
50
51
|
let authField = null;
|
|
51
52
|
let authFormat = null;
|
|
52
53
|
let authLogging = false;
|
|
@@ -78,6 +79,7 @@ let sslCAFile = null;
|
|
|
78
79
|
let sslKeyFile = null;
|
|
79
80
|
let sslCertFile = null;
|
|
80
81
|
let sslCiphers = null;
|
|
82
|
+
let sslPassphrase = null;
|
|
81
83
|
let secureProtocol = null;
|
|
82
84
|
let proxyEnabled = false;
|
|
83
85
|
let proxyHost = null;
|
|
@@ -116,6 +118,8 @@ let cacheHHead = null;
|
|
|
116
118
|
let cacheHSchema = null;
|
|
117
119
|
let cacheHPay = null;
|
|
118
120
|
|
|
121
|
+
const mfaStepsResults = []; // keeps requested result for each step
|
|
122
|
+
|
|
119
123
|
/* CONNECTOR ENGINE INTERNAL FUNCTIONS */
|
|
120
124
|
/** Wait for adapter-mongo to be available.
|
|
121
125
|
* @summary adapter may load before adapter-mongo but it requires UPDATE: test if dbUtil object can connect.
|
|
@@ -1083,7 +1087,6 @@ function findExpireInResult(result) {
|
|
|
1083
1087
|
const origin = `${id}-connectorRest-findExpireInResult`;
|
|
1084
1088
|
log.trace(origin);
|
|
1085
1089
|
let expire = null;
|
|
1086
|
-
|
|
1087
1090
|
if (!result) {
|
|
1088
1091
|
return expire;
|
|
1089
1092
|
}
|
|
@@ -1116,884 +1119,932 @@ function findExpireInResult(result) {
|
|
|
1116
1119
|
* INTERNAL FUNCTION: makes the request and processes the response
|
|
1117
1120
|
* for the request to get the token
|
|
1118
1121
|
*/
|
|
1119
|
-
function getToken(reqPath, options, tokenSchema, bodyString, callProperties, callback) {
|
|
1122
|
+
async function getToken(reqPath, options, tokenSchema, bodyString, callProperties, callback) {
|
|
1120
1123
|
const origin = `${id}-connectorRest-getToken`;
|
|
1121
1124
|
log.trace(origin);
|
|
1122
1125
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
// set stub if that is the mode we are in
|
|
1132
|
-
let useStub = false;
|
|
1133
|
-
if (callProperties && Object.hasOwnProperty.call(callProperties, 'stub')) {
|
|
1134
|
-
useStub = callProperties.stub;
|
|
1135
|
-
} else if (stub) {
|
|
1136
|
-
useStub = stub;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
// if there is a mock result, return that
|
|
1140
|
-
if (useStub && tokenSchema) {
|
|
1141
|
-
// get the data from the mock data file
|
|
1142
|
-
const tokenResp = returnStub(request, tokenSchema, callProperties);
|
|
1143
|
-
|
|
1144
|
-
// if the request failed, return the error
|
|
1145
|
-
if (tokenResp.code < 200 || tokenResp.code > 299) {
|
|
1146
|
-
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', tokenResp.code], null, null, null);
|
|
1147
|
-
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1148
|
-
return callback(null, errorObj);
|
|
1149
|
-
}
|
|
1126
|
+
const p = new Promise((resolve, reject) => {
|
|
1127
|
+
try {
|
|
1128
|
+
// no need for orig path since we handled the stub case
|
|
1129
|
+
const request = {
|
|
1130
|
+
header: options,
|
|
1131
|
+
body: bodyString,
|
|
1132
|
+
origPath: tokenSchema.entitypath
|
|
1133
|
+
};
|
|
1150
1134
|
|
|
1151
|
-
if
|
|
1152
|
-
|
|
1135
|
+
// set stub if that is the mode we are in
|
|
1136
|
+
let useStub = false;
|
|
1137
|
+
if (callProperties && Object.hasOwnProperty.call(callProperties, 'stub')) {
|
|
1138
|
+
useStub = callProperties.stub;
|
|
1139
|
+
} else if (stub) {
|
|
1140
|
+
useStub = stub;
|
|
1153
1141
|
}
|
|
1154
|
-
log.debug(`${origin}: ${JSON.stringify(tokenResp.response)}`);
|
|
1155
1142
|
|
|
1156
|
-
//
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
} else {
|
|
1161
|
-
translated = tokenResp.response;
|
|
1162
|
-
}
|
|
1143
|
+
// if there is a mock result, return that
|
|
1144
|
+
if (useStub && tokenSchema) {
|
|
1145
|
+
// get the data from the mock data file
|
|
1146
|
+
const tokenResp = returnStub(request, tokenSchema, callProperties);
|
|
1163
1147
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
}
|
|
1148
|
+
// if the request failed, return the error
|
|
1149
|
+
if (tokenResp.code < 200 || tokenResp.code > 299) {
|
|
1150
|
+
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', tokenResp.code], null, null, null);
|
|
1151
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1152
|
+
return reject(errorObj);
|
|
1153
|
+
}
|
|
1171
1154
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
translated[0].end = tokenSchema.responseSchema.properties.token.end;
|
|
1177
|
-
return callback(translated[0]);
|
|
1178
|
-
}
|
|
1155
|
+
if (!tokenSchema.responseDatatype || tokenSchema.responseDatatype === 'JSON') {
|
|
1156
|
+
tokenResp.response = JSON.parse(tokenResp.response);
|
|
1157
|
+
}
|
|
1158
|
+
log.debug(`${origin}: ${JSON.stringify(tokenResp.response)}`);
|
|
1179
1159
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1160
|
+
// return the token from the token schema
|
|
1161
|
+
let translated = null;
|
|
1162
|
+
if (typeof tokenResp.response !== 'string') {
|
|
1163
|
+
translated = transUtilInst.mapFromOutboundEntity(tokenResp.response, tokenSchema.responseSchema);
|
|
1164
|
+
} else {
|
|
1165
|
+
translated = tokenResp.response;
|
|
1166
|
+
}
|
|
1185
1167
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1168
|
+
// since this is a stub, make sure we have what we need
|
|
1169
|
+
if (!translated.token) {
|
|
1170
|
+
translated.token = 'garbagetoken';
|
|
1171
|
+
}
|
|
1172
|
+
if (!translated.tokenp2) {
|
|
1173
|
+
translated.tokenp2 = 'garbagetoken';
|
|
1174
|
+
}
|
|
1192
1175
|
|
|
1193
|
-
|
|
1176
|
+
// if what we got back is an array, just return the first element
|
|
1177
|
+
// should only have one token!!!
|
|
1178
|
+
if (translated && Array.isArray(translated)) {
|
|
1179
|
+
translated[0].front = tokenSchema.responseSchema.properties.token.front;
|
|
1180
|
+
translated[0].end = tokenSchema.responseSchema.properties.token.end;
|
|
1181
|
+
return resolve(translated[0]);
|
|
1182
|
+
}
|
|
1194
1183
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
return
|
|
1184
|
+
// return the token that we find in the translated object
|
|
1185
|
+
translated.front = tokenSchema.responseSchema.properties.token.front;
|
|
1186
|
+
translated.end = tokenSchema.responseSchema.properties.token.end;
|
|
1187
|
+
return resolve(translated);
|
|
1199
1188
|
}
|
|
1200
1189
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1190
|
+
if (useStub || reqPath === tokenPath || (tokenSchema && reqPath === tokenSchema.entitypath)) {
|
|
1191
|
+
// do not make the call to return a token if the request is actually
|
|
1192
|
+
// to get a token. Getting a token to get a token -- that should go
|
|
1193
|
+
// direct to make request
|
|
1194
|
+
return resolve({ token: 'faketoken', tokenp2: 'faketoken' });
|
|
1206
1195
|
}
|
|
1207
1196
|
|
|
1208
|
-
|
|
1209
|
-
if ((result.code < 200 || result.code > 299) && !handleTokenRedirect) {
|
|
1210
|
-
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', result.code], null, null, null);
|
|
1211
|
-
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1212
|
-
return callback(null, errorObj);
|
|
1213
|
-
}
|
|
1197
|
+
log.debug(`${origin}: OPTIONS: ${JSON.stringify(options)}`);
|
|
1214
1198
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
}
|
|
1199
|
+
// request the token
|
|
1200
|
+
return makeRequest(request, tokenSchema, callProperties, null, 0, (result, merror) => {
|
|
1201
|
+
if (merror) {
|
|
1202
|
+
return reject(merror);
|
|
1203
|
+
}
|
|
1221
1204
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
};
|
|
1205
|
+
// if the request is a redirect, try to pull token but log a warning
|
|
1206
|
+
let handleTokenRedirect = false;
|
|
1207
|
+
if (result.code >= 300 && result.code <= 308 && numRedirects === 0) {
|
|
1208
|
+
log.warn(`${origin}: Going to attempt to get token from redirect message!`);
|
|
1209
|
+
handleTokenRedirect = true;
|
|
1210
|
+
}
|
|
1229
1211
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1212
|
+
// if the request failed, return the error
|
|
1213
|
+
if ((result.code < 200 || result.code > 299) && !handleTokenRedirect) {
|
|
1214
|
+
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', result.code], null, null, null);
|
|
1215
|
+
if (callProperties && callProperties.mfa && callProperties.mfa.successfullResponseCode) { // MFA call
|
|
1216
|
+
if (callProperties.mfa.successfullResponseCode !== result.code) {
|
|
1217
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1218
|
+
return reject(errorObj);
|
|
1219
|
+
}
|
|
1220
|
+
} else { // non-MFA call
|
|
1221
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1222
|
+
return reject(errorObj);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
if (!tokenSchema) {
|
|
1227
|
+
// if no token schema, can not determine what to return
|
|
1228
|
+
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', result.code], null, null, null);
|
|
1235
1229
|
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1236
|
-
return
|
|
1230
|
+
return reject(errorObj);
|
|
1237
1231
|
}
|
|
1238
1232
|
|
|
1239
|
-
|
|
1240
|
-
const
|
|
1241
|
-
|
|
1242
|
-
|
|
1233
|
+
// parse the token out of the result
|
|
1234
|
+
const currResult = {
|
|
1235
|
+
token: null,
|
|
1236
|
+
tokenp2: null,
|
|
1237
|
+
front: tokenSchema.responseSchema.properties.token.front,
|
|
1238
|
+
end: tokenSchema.responseSchema.properties.token.end
|
|
1239
|
+
};
|
|
1243
1240
|
|
|
1244
|
-
//
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1241
|
+
// process primary token from header
|
|
1242
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
|
|
1243
|
+
&& tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'HEADER') {
|
|
1244
|
+
if (!tokenSchema.responseSchema.properties.token.external_name) {
|
|
1245
|
+
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Get Primary Token', ['Primary Token', result.code], null, null, null);
|
|
1246
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1247
|
+
return reject(errorObj);
|
|
1249
1248
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1249
|
+
|
|
1250
|
+
const exName = tokenSchema.responseSchema.properties.token.external_name.toLowerCase();
|
|
1251
|
+
const headKeys = Object.keys(result.headers);
|
|
1252
|
+
let fullToken = null;
|
|
1253
|
+
let setCookie = null;
|
|
1254
|
+
|
|
1255
|
+
// go through and find the token
|
|
1256
|
+
for (let h = 0; h < headKeys.length; h += 1) {
|
|
1257
|
+
if (headKeys[h].toLowerCase() === exName) {
|
|
1258
|
+
fullToken = result.headers[headKeys[h]];
|
|
1259
|
+
currResult.token = result.headers[headKeys[h]];
|
|
1260
|
+
}
|
|
1261
|
+
if (headKeys[h].toLowerCase() === 'set-cookie') {
|
|
1262
|
+
setCookie = result.headers[headKeys[h]];
|
|
1263
|
+
}
|
|
1252
1264
|
}
|
|
1253
|
-
}
|
|
1254
1265
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1266
|
+
// if the token is in the requestToken
|
|
1267
|
+
if (exName === 'requestcookie' && result.requestCookie) {
|
|
1268
|
+
currResult.token = result.requestCookie;
|
|
1269
|
+
}
|
|
1259
1270
|
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1271
|
+
// if the exName field is an array
|
|
1272
|
+
if (exName === 'set-cookie' && fullToken && Array.isArray(fullToken)) {
|
|
1273
|
+
currResult.token = fullToken[0];
|
|
1274
|
+
for (let ex = 1; ex < fullToken.length; ex += 1) {
|
|
1275
|
+
currResult.token += `; ${fullToken[ex]}`;
|
|
1276
|
+
}
|
|
1265
1277
|
}
|
|
1266
|
-
}
|
|
1267
1278
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
+
// if the token has been returned in the cookie
|
|
1280
|
+
if (exName.substring(0, 11) === 'set-cookie.') {
|
|
1281
|
+
const fname = exName.substring(11).toLowerCase();
|
|
1282
|
+
let thisCook = null;
|
|
1283
|
+
|
|
1284
|
+
// if the cookie is an array - usual case
|
|
1285
|
+
if (setCookie && Array.isArray(setCookie)) {
|
|
1286
|
+
// go through the array looking for the defined token field
|
|
1287
|
+
for (let sc = 0; sc < setCookie.length; sc += 1) {
|
|
1288
|
+
// parses the cookie into an object
|
|
1289
|
+
thisCook = cookieHandler.parse(setCookie[sc]);
|
|
1290
|
+
const cookKeys = Object.keys(thisCook);
|
|
1291
|
+
let set = false;
|
|
1292
|
+
|
|
1293
|
+
// go through the cookie to find the token
|
|
1294
|
+
for (let h = 0; h < cookKeys.length; h += 1) {
|
|
1295
|
+
if (cookKeys[h].toLowerCase() === fname) {
|
|
1296
|
+
currResult.token = thisCook[cookKeys[h]];
|
|
1297
|
+
set = true;
|
|
1298
|
+
break;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
if (set) {
|
|
1302
|
+
break;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
} else if (setCookie) {
|
|
1306
|
+
// if the cookie is just one string, parse into an object
|
|
1307
|
+
thisCook = cookieHandler.parse(setCookie);
|
|
1279
1308
|
const cookKeys = Object.keys(thisCook);
|
|
1280
|
-
let set = false;
|
|
1281
1309
|
|
|
1282
1310
|
// go through the cookie to find the token
|
|
1283
1311
|
for (let h = 0; h < cookKeys.length; h += 1) {
|
|
1284
1312
|
if (cookKeys[h].toLowerCase() === fname) {
|
|
1285
1313
|
currResult.token = thisCook[cookKeys[h]];
|
|
1286
|
-
set = true;
|
|
1287
1314
|
break;
|
|
1288
1315
|
}
|
|
1289
1316
|
}
|
|
1290
|
-
if (set) {
|
|
1291
|
-
break;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
} else if (setCookie) {
|
|
1295
|
-
// if the cookie is just one string, parse into an object
|
|
1296
|
-
thisCook = cookieHandler.parse(setCookie);
|
|
1297
|
-
const cookKeys = Object.keys(thisCook);
|
|
1298
|
-
|
|
1299
|
-
// go through the cookie to find the token
|
|
1300
|
-
for (let h = 0; h < cookKeys.length; h += 1) {
|
|
1301
|
-
if (cookKeys[h].toLowerCase() === fname) {
|
|
1302
|
-
currResult.token = thisCook[cookKeys[h]];
|
|
1303
|
-
break;
|
|
1304
|
-
}
|
|
1305
1317
|
}
|
|
1306
1318
|
}
|
|
1307
1319
|
}
|
|
1308
|
-
}
|
|
1309
1320
|
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1321
|
+
// process second token from header
|
|
1322
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
|
|
1323
|
+
&& tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'HEADER') {
|
|
1324
|
+
if (!tokenSchema.responseSchema.properties.tokenp2.external_name) {
|
|
1325
|
+
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Get Secondary Token', ['Secondary Token', result.code], null, null, null);
|
|
1326
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1327
|
+
return reject(errorObj);
|
|
1328
|
+
}
|
|
1318
1329
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1330
|
+
const exName = tokenSchema.responseSchema.properties.tokenp2.external_name.toLowerCase();
|
|
1331
|
+
const headKeys = Object.keys(result.headers);
|
|
1332
|
+
let fullToken = null;
|
|
1333
|
+
let setCookie = null;
|
|
1323
1334
|
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1335
|
+
// go through and find the token
|
|
1336
|
+
for (let h = 0; h < headKeys.length; h += 1) {
|
|
1337
|
+
if (headKeys[h].toLowerCase() === exName) {
|
|
1338
|
+
fullToken = result.headers[headKeys[h]];
|
|
1339
|
+
currResult.tokenp2 = result.headers[headKeys[h]];
|
|
1340
|
+
}
|
|
1341
|
+
if (headKeys[h].toLowerCase() === 'set-cookie') {
|
|
1342
|
+
setCookie = result.headers[headKeys[h]];
|
|
1343
|
+
}
|
|
1332
1344
|
}
|
|
1333
|
-
}
|
|
1334
1345
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1346
|
+
// if the token is in the requestToken
|
|
1347
|
+
if (exName === 'requestcookie' && result.requestCookie) {
|
|
1348
|
+
currResult.token = result.requestCookie;
|
|
1349
|
+
}
|
|
1339
1350
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1351
|
+
// if the exName field is an array
|
|
1352
|
+
if (exName === 'set-cookie' && fullToken && Array.isArray(fullToken)) {
|
|
1353
|
+
currResult.tokenp2 = fullToken[0];
|
|
1354
|
+
for (let ex = 1; ex < fullToken.length; ex += 1) {
|
|
1355
|
+
currResult.tokenp2 += `; ${fullToken[ex]}`;
|
|
1356
|
+
}
|
|
1345
1357
|
}
|
|
1346
|
-
}
|
|
1347
1358
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
+
// if the token has been returned in the cookie
|
|
1360
|
+
if (exName.substring(0, 11) === 'set-cookie.') {
|
|
1361
|
+
const fname = exName.substring(11).toLowerCase();
|
|
1362
|
+
let thisCook = null;
|
|
1363
|
+
|
|
1364
|
+
// if the cookie is an array - usual case
|
|
1365
|
+
if (setCookie && Array.isArray(setCookie)) {
|
|
1366
|
+
// go through the array looking for the defined token field
|
|
1367
|
+
for (let sc = 0; sc < setCookie.length; sc += 1) {
|
|
1368
|
+
// parses the cookie into an object
|
|
1369
|
+
thisCook = cookieHandler.parse(setCookie[sc]);
|
|
1370
|
+
const cookKeys = Object.keys(thisCook);
|
|
1371
|
+
let set = false;
|
|
1372
|
+
|
|
1373
|
+
// go through the cookie to find the token
|
|
1374
|
+
for (let h = 0; h < cookKeys.length; h += 1) {
|
|
1375
|
+
if (cookKeys[h].toLowerCase() === fname) {
|
|
1376
|
+
currResult.tokenp2 = thisCook[cookKeys[h]];
|
|
1377
|
+
set = true;
|
|
1378
|
+
break;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
if (set) {
|
|
1382
|
+
break;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
} else if (setCookie) {
|
|
1386
|
+
// if the cookie is just one string, parse into an object
|
|
1387
|
+
thisCook = cookieHandler.parse(setCookie);
|
|
1359
1388
|
const cookKeys = Object.keys(thisCook);
|
|
1360
|
-
let set = false;
|
|
1361
1389
|
|
|
1362
1390
|
// go through the cookie to find the token
|
|
1363
1391
|
for (let h = 0; h < cookKeys.length; h += 1) {
|
|
1364
1392
|
if (cookKeys[h].toLowerCase() === fname) {
|
|
1365
1393
|
currResult.tokenp2 = thisCook[cookKeys[h]];
|
|
1366
|
-
set = true;
|
|
1367
1394
|
break;
|
|
1368
1395
|
}
|
|
1369
1396
|
}
|
|
1370
|
-
if (set) {
|
|
1371
|
-
break;
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
} else if (setCookie) {
|
|
1375
|
-
// if the cookie is just one string, parse into an object
|
|
1376
|
-
thisCook = cookieHandler.parse(setCookie);
|
|
1377
|
-
const cookKeys = Object.keys(thisCook);
|
|
1378
|
-
|
|
1379
|
-
// go through the cookie to find the token
|
|
1380
|
-
for (let h = 0; h < cookKeys.length; h += 1) {
|
|
1381
|
-
if (cookKeys[h].toLowerCase() === fname) {
|
|
1382
|
-
currResult.tokenp2 = thisCook[cookKeys[h]];
|
|
1383
|
-
break;
|
|
1384
|
-
}
|
|
1385
1397
|
}
|
|
1386
1398
|
}
|
|
1387
1399
|
}
|
|
1388
|
-
}
|
|
1389
1400
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1401
|
+
// process the body
|
|
1402
|
+
// if response is just a string
|
|
1403
|
+
if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'PLAIN') {
|
|
1404
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
|
|
1405
|
+
&& tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
|
|
1406
|
+
currResult.token = result.response;
|
|
1396
1407
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1408
|
+
// if we got a stringified string - we can remove the double quotes wrapping it
|
|
1409
|
+
if (currResult.token.substring(0, 1) === '"' && currResult.token.substring(-1, 1) === '"') {
|
|
1410
|
+
currResult.token = currResult.token.substring(1, currResult.token.length - 1);
|
|
1411
|
+
}
|
|
1400
1412
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
currResult.tokenp2 = result.response;
|
|
1413
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
|
|
1414
|
+
&& tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
|
|
1415
|
+
currResult.tokenp2 = result.response;
|
|
1405
1416
|
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1417
|
+
// if we got a stringified string - we can remove the double quotes wrapping it
|
|
1418
|
+
if (currResult.token.substring(0, 1) === '"' && currResult.token.substring(-1, 1) === '"') {
|
|
1419
|
+
currResult.token = currResult.token.substring(1, currResult.token.length - 1);
|
|
1420
|
+
}
|
|
1409
1421
|
}
|
|
1410
|
-
}
|
|
1411
1422
|
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
}
|
|
1415
|
-
if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'XML') {
|
|
1416
|
-
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
|
|
1417
|
-
&& tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
|
|
1418
|
-
currResult.token = result.response;
|
|
1419
|
-
}
|
|
1420
|
-
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
|
|
1421
|
-
&& tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
|
|
1422
|
-
currResult.tokenp2 = result.response;
|
|
1423
|
+
// return the string as there is no other processing needed
|
|
1424
|
+
return resolve(currResult);
|
|
1423
1425
|
}
|
|
1426
|
+
if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'XML') {
|
|
1427
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
|
|
1428
|
+
&& tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
|
|
1429
|
+
currResult.token = result.response;
|
|
1430
|
+
}
|
|
1431
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
|
|
1432
|
+
&& tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
|
|
1433
|
+
currResult.tokenp2 = result.response;
|
|
1434
|
+
}
|
|
1424
1435
|
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1436
|
+
// return the xml as there is no other processing needed
|
|
1437
|
+
return resolve(currResult);
|
|
1438
|
+
}
|
|
1428
1439
|
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1440
|
+
// if response can be put into a JSON object
|
|
1441
|
+
let tempResult = null;
|
|
1442
|
+
if (result.response) {
|
|
1443
|
+
if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'XML2JSON') {
|
|
1444
|
+
try {
|
|
1445
|
+
const parser = new xml2js.Parser({ explicitArray: false, attrkey: '_attr' });
|
|
1446
|
+
parser.parseString(result.response, (error, presult) => {
|
|
1447
|
+
if (error) {
|
|
1448
|
+
log.warn(`${origin}: Unable to parse xml to json ${error}`);
|
|
1449
|
+
return resolve(parser.toJson(presult));
|
|
1450
|
+
}
|
|
1451
|
+
tempResult = presult;
|
|
1452
|
+
});
|
|
1453
|
+
} catch (ex) {
|
|
1454
|
+
log.warn(`${origin}: Unable to get json from xml ${ex}`);
|
|
1455
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
|
|
1456
|
+
&& tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
|
|
1457
|
+
currResult.token = result.response;
|
|
1458
|
+
}
|
|
1459
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
|
|
1460
|
+
&& tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
|
|
1461
|
+
currResult.tokenp2 = result.response;
|
|
1439
1462
|
}
|
|
1440
|
-
tempResult = presult;
|
|
1441
|
-
});
|
|
1442
|
-
} catch (ex) {
|
|
1443
|
-
log.warn(`${origin}: Unable to get json from xml ${ex}`);
|
|
1444
|
-
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
|
|
1445
|
-
&& tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
|
|
1446
|
-
currResult.token = result.response;
|
|
1447
1463
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1464
|
+
}
|
|
1465
|
+
if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'URLENCODE') {
|
|
1466
|
+
tempResult = querystring.parse(result.response.trim());
|
|
1467
|
+
} else {
|
|
1468
|
+
try {
|
|
1469
|
+
tempResult = JSON.parse(result.response.trim());
|
|
1470
|
+
} catch (exc) {
|
|
1471
|
+
log.warn(exc);
|
|
1451
1472
|
}
|
|
1452
1473
|
}
|
|
1453
1474
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
tempResult = JSON.parse(result.response.trim());
|
|
1459
|
-
} catch (exc) {
|
|
1460
|
-
log.warn(exc);
|
|
1461
|
-
}
|
|
1475
|
+
|
|
1476
|
+
// at this point if there is nothing in tempResult nothing further to do
|
|
1477
|
+
if (!tempResult) {
|
|
1478
|
+
return resolve(currResult);
|
|
1462
1479
|
}
|
|
1463
|
-
}
|
|
1464
1480
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
}
|
|
1481
|
+
// need to see if there is a response key
|
|
1482
|
+
if (tokenSchema.responseObjects) {
|
|
1483
|
+
let tKey = null;
|
|
1469
1484
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1485
|
+
// it should be an array - then take the first element of array
|
|
1486
|
+
if (Array.isArray(tokenSchema.responseObjects)) {
|
|
1487
|
+
if (tokenSchema.responseObjects[0].key) {
|
|
1488
|
+
tKey = tokenSchema.responseObjects[0].key;
|
|
1489
|
+
}
|
|
1490
|
+
} else if (tokenSchema.responseObjects.key) {
|
|
1491
|
+
tKey = tokenSchema.responseObjects.key;
|
|
1492
|
+
}
|
|
1473
1493
|
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
tKey = tokenSchema.responseObjects[0].key;
|
|
1494
|
+
// if we found a key, use it
|
|
1495
|
+
if (tKey) {
|
|
1496
|
+
tempResult = jsonQuery(tKey, { data: tempResult }).value;
|
|
1478
1497
|
}
|
|
1479
|
-
} else if (tokenSchema.responseObjects.key) {
|
|
1480
|
-
tKey = tokenSchema.responseObjects.key;
|
|
1481
1498
|
}
|
|
1482
1499
|
|
|
1483
|
-
//
|
|
1484
|
-
if (
|
|
1485
|
-
tempResult =
|
|
1500
|
+
// the token should not be an array so if it is, return the 0 item.
|
|
1501
|
+
if (Array.isArray(tempResult)) {
|
|
1502
|
+
tempResult = tempResult[0];
|
|
1486
1503
|
}
|
|
1487
|
-
}
|
|
1488
1504
|
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
tempResult = tempResult[0];
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
// return the token from the token schema
|
|
1495
|
-
let translated = transUtilInst.mapFromOutboundEntity(tempResult, tokenSchema.responseSchema);
|
|
1505
|
+
// return the token from the token schema
|
|
1506
|
+
let translated = transUtilInst.mapFromOutboundEntity(tempResult, tokenSchema.responseSchema);
|
|
1496
1507
|
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1508
|
+
// if what we got back is an array, just return the first element
|
|
1509
|
+
// should only have one token!!!
|
|
1510
|
+
if (translated && Array.isArray(translated)) {
|
|
1511
|
+
translated = translated[0];
|
|
1512
|
+
}
|
|
1502
1513
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1514
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
|
|
1515
|
+
&& tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
|
|
1516
|
+
currResult.token = translated.token;
|
|
1517
|
+
}
|
|
1518
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
|
|
1519
|
+
&& tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
|
|
1520
|
+
currResult.tokenp2 = translated.tokenp2;
|
|
1521
|
+
}
|
|
1522
|
+
if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.expires
|
|
1523
|
+
&& tokenSchema.responseSchema.properties.expires.placement && tokenSchema.responseSchema.properties.expires.placement.toUpperCase() === 'BODY') {
|
|
1524
|
+
currResult.expires = translated.expires;
|
|
1525
|
+
}
|
|
1526
|
+
// return the token that we find in the translated object
|
|
1527
|
+
return resolve(currResult);
|
|
1528
|
+
});
|
|
1529
|
+
} catch (e) {
|
|
1530
|
+
// handle any exception
|
|
1531
|
+
const errorObj = transUtilInst.checkAndReturn(e, origin, 'Issue retrieving a token');
|
|
1532
|
+
return reject(errorObj);
|
|
1533
|
+
}
|
|
1534
|
+
});
|
|
1511
1535
|
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
});
|
|
1515
|
-
} catch (e) {
|
|
1516
|
-
// handle any exception
|
|
1517
|
-
const errorObj = transUtilInst.checkAndReturn(e, origin, 'Issue retrieving a token');
|
|
1518
|
-
return callback(null, errorObj);
|
|
1536
|
+
if (typeof callback === 'function') {
|
|
1537
|
+
return p.then((result) => callback(result)).catch((error) => callback(null, error));
|
|
1519
1538
|
}
|
|
1539
|
+
return p;
|
|
1520
1540
|
}
|
|
1521
1541
|
|
|
1522
1542
|
/*
|
|
1523
1543
|
* INTERNAL FUNCTION: prepares a request to get a token from the system
|
|
1524
1544
|
*/
|
|
1525
|
-
function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
|
|
1545
|
+
async function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
|
|
1526
1546
|
const origin = `${id}-connectorRest-buildTokenRequest`;
|
|
1527
1547
|
log.trace(origin);
|
|
1528
1548
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
if (
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
thisAHdata = transUtilInst.mergeObjects(thisAHdata, tokenSchema.headers);
|
|
1544
|
-
}
|
|
1545
|
-
if (globalRequest) {
|
|
1546
|
-
thisAHdata = transUtilInst.mergeObjects(thisAHdata, globalRequest.addlHeaders);
|
|
1547
|
-
}
|
|
1549
|
+
const promise = new Promise((resolve, reject) => {
|
|
1550
|
+
try {
|
|
1551
|
+
let entity = 'getToken';
|
|
1552
|
+
if (callProperties && callProperties.mfa) {
|
|
1553
|
+
entity = callProperties.mfa.stepAtionName;
|
|
1554
|
+
}
|
|
1555
|
+
// Get the entity schema from the file system
|
|
1556
|
+
return propUtilInst.getEntitySchema('.system', entity, choosepath, this.dbUtil, async (tokenSchema, healthError) => {
|
|
1557
|
+
if (healthError || !tokenSchema || Object.keys(tokenSchema).length === 0) {
|
|
1558
|
+
log.debug(`${origin}: Using adapter properties for token information`);
|
|
1559
|
+
tokenSchema = null;
|
|
1560
|
+
} else {
|
|
1561
|
+
log.debug(`${origin}: Using action and schema for token information`);
|
|
1562
|
+
}
|
|
1548
1563
|
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
let usePass = password;
|
|
1564
|
+
// prepare the additional headers we received
|
|
1565
|
+
let thisAHdata = null;
|
|
1552
1566
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1567
|
+
if (tokenSchema) {
|
|
1568
|
+
thisAHdata = transUtilInst.mergeObjects(thisAHdata, tokenSchema.headers);
|
|
1569
|
+
}
|
|
1570
|
+
if (globalRequest) {
|
|
1571
|
+
thisAHdata = transUtilInst.mergeObjects(thisAHdata, globalRequest.addlHeaders);
|
|
1572
|
+
}
|
|
1559
1573
|
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
} else {
|
|
1564
|
-
const hKeys = Object.keys(thisAHdata);
|
|
1574
|
+
// set up the right credentials - passed in overrides default
|
|
1575
|
+
let useUser = username;
|
|
1576
|
+
let usePass = password;
|
|
1565
1577
|
|
|
1566
|
-
|
|
1567
|
-
|
|
1578
|
+
if (callProperties && callProperties.authentication && callProperties.authentication.username) {
|
|
1579
|
+
useUser = callProperties.authentication.username;
|
|
1580
|
+
}
|
|
1581
|
+
if (callProperties && callProperties.authentication && callProperties.authentication.password) {
|
|
1582
|
+
usePass = callProperties.authentication.password;
|
|
1583
|
+
}
|
|
1568
1584
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
if (tempStr.indexOf('{password}') >= 0) {
|
|
1575
|
-
tempStr = tempStr.replace('{password}', usePass);
|
|
1576
|
-
}
|
|
1577
|
-
thisAHdata[hKeys[h]] = tempStr;
|
|
1585
|
+
// if no header data passed in create empty - will add data below
|
|
1586
|
+
if (!thisAHdata) {
|
|
1587
|
+
thisAHdata = {};
|
|
1588
|
+
} else {
|
|
1589
|
+
const hKeys = Object.keys(thisAHdata);
|
|
1578
1590
|
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
// get the range to be encoded
|
|
1582
|
-
const sIndex = thisAHdata[hKeys[h]].indexOf('{b64}');
|
|
1583
|
-
const eIndex = thisAHdata[hKeys[h]].indexOf('{/b64}');
|
|
1591
|
+
for (let h = 0; h < hKeys.length; h += 1) {
|
|
1592
|
+
let tempStr = thisAHdata[hKeys[h]];
|
|
1584
1593
|
|
|
1585
|
-
//
|
|
1586
|
-
if (
|
|
1587
|
-
|
|
1588
|
-
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1589
|
-
return callback(null, errorObj);
|
|
1594
|
+
// replace username variable
|
|
1595
|
+
if (tempStr.indexOf('{username}') >= 0) {
|
|
1596
|
+
tempStr = tempStr.replace('{username}', useUser);
|
|
1590
1597
|
}
|
|
1598
|
+
// replace password variable
|
|
1599
|
+
if (tempStr.indexOf('{password}') >= 0) {
|
|
1600
|
+
tempStr = tempStr.replace('{password}', usePass);
|
|
1601
|
+
}
|
|
1602
|
+
thisAHdata[hKeys[h]] = tempStr;
|
|
1603
|
+
|
|
1604
|
+
// handle any base64 encoding required on the authStr
|
|
1605
|
+
if (thisAHdata[hKeys[h]].indexOf('{b64}') >= 0) {
|
|
1606
|
+
// get the range to be encoded
|
|
1607
|
+
const sIndex = thisAHdata[hKeys[h]].indexOf('{b64}');
|
|
1608
|
+
const eIndex = thisAHdata[hKeys[h]].indexOf('{/b64}');
|
|
1609
|
+
|
|
1610
|
+
// if start but no end - return an error
|
|
1611
|
+
if (sIndex >= 0 && eIndex < sIndex + 5) {
|
|
1612
|
+
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Encode', [thisAHdata[hKeys[h]]], null, null, null);
|
|
1613
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1614
|
+
return reject(errorObj);
|
|
1615
|
+
}
|
|
1591
1616
|
|
|
1592
|
-
|
|
1593
|
-
|
|
1617
|
+
// get the string to be encoded
|
|
1618
|
+
const bufString = thisAHdata[hKeys[h]].substring(sIndex + 5, eIndex);
|
|
1594
1619
|
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1620
|
+
// encode the string
|
|
1621
|
+
const encString = Buffer.from(bufString).toString('base64');
|
|
1622
|
+
let tempAuthStr = '';
|
|
1598
1623
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1624
|
+
// build the new auth field with the encoded string
|
|
1625
|
+
if (sIndex > 0) {
|
|
1626
|
+
// add the start of the string that did not need encoding
|
|
1627
|
+
tempAuthStr = thisAHdata[hKeys[h]].substring(0, sIndex);
|
|
1628
|
+
}
|
|
1629
|
+
// add the encoded string
|
|
1630
|
+
tempAuthStr += encString;
|
|
1631
|
+
if (eIndex + 5 < thisAHdata[hKeys[h]].length) {
|
|
1632
|
+
// add the end of the string that did not need encoding
|
|
1633
|
+
tempAuthStr += thisAHdata[hKeys[h]].substring(eIndex + 6);
|
|
1634
|
+
}
|
|
1610
1635
|
|
|
1611
|
-
|
|
1612
|
-
|
|
1636
|
+
// put the temp string into the auth string we will add to the request
|
|
1637
|
+
thisAHdata[hKeys[h]] = tempAuthStr;
|
|
1638
|
+
}
|
|
1613
1639
|
}
|
|
1614
1640
|
}
|
|
1615
|
-
}
|
|
1616
1641
|
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1642
|
+
// set the Content Type headers based on the type of request data for the call
|
|
1643
|
+
if (thisAHdata['Content-Type'] === undefined || thisAHdata['Content-Type'] === null) {
|
|
1644
|
+
if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'PLAIN') {
|
|
1645
|
+
// add the Plain headers if they were not set already
|
|
1646
|
+
thisAHdata['Content-Type'] = 'text/plain';
|
|
1647
|
+
} else if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'XML') {
|
|
1648
|
+
// add the XML headers if they were not set already
|
|
1649
|
+
thisAHdata['Content-Type'] = 'application/xml';
|
|
1650
|
+
} else if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLENCODE') {
|
|
1651
|
+
// add the URLENCODE headers if they were not set already
|
|
1652
|
+
thisAHdata['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
1653
|
+
} else {
|
|
1654
|
+
// add the JSON headers if they were not set already
|
|
1655
|
+
thisAHdata['Content-Type'] = 'application/json';
|
|
1656
|
+
}
|
|
1631
1657
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1658
|
+
// set the Accept headers based on the type of response data for the call
|
|
1659
|
+
if (thisAHdata.Accept === undefined || thisAHdata.Accept === null) {
|
|
1660
|
+
if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'PLAIN') {
|
|
1661
|
+
// add the Plain headers if they were not set already
|
|
1662
|
+
thisAHdata.Accept = 'text/plain';
|
|
1663
|
+
} else if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'XML') {
|
|
1664
|
+
// add the XML headers if they were not set already
|
|
1665
|
+
thisAHdata.Accept = 'application/xml';
|
|
1666
|
+
} else if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'URLENCODE') {
|
|
1667
|
+
// add the URLENCODE headers if they were not set already
|
|
1668
|
+
thisAHdata.Accept = 'application/x-www-form-urlencoded';
|
|
1669
|
+
} else {
|
|
1670
|
+
// add the JSON headers if they were not set already
|
|
1671
|
+
thisAHdata.Accept = 'application/json';
|
|
1672
|
+
}
|
|
1647
1673
|
}
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
if (thisAHdata.Accept === '') {
|
|
1651
|
-
delete thisAHdata.Accept;
|
|
1652
|
-
}
|
|
1653
|
-
if (thisAHdata['Content-Type'] === '') {
|
|
1654
|
-
delete thisAHdata['Content-Type'];
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
// set up the options for the call to get incidents - default is all
|
|
1658
|
-
const options = {
|
|
1659
|
-
hostname: host,
|
|
1660
|
-
port,
|
|
1661
|
-
path: tokenPath,
|
|
1662
|
-
method: 'POST',
|
|
1663
|
-
headers: thisAHdata
|
|
1664
|
-
};
|
|
1665
|
-
|
|
1666
|
-
// passed in properties override defaults
|
|
1667
|
-
if (callProperties && callProperties.host) {
|
|
1668
|
-
options.hostname = callProperties.host;
|
|
1669
|
-
}
|
|
1670
|
-
if (callProperties && callProperties.port) {
|
|
1671
|
-
options.port = callProperties.port;
|
|
1672
|
-
}
|
|
1673
1674
|
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
options.port = sso.port;
|
|
1680
|
-
}
|
|
1681
|
-
if (sso && sso.protocol) {
|
|
1682
|
-
// need to put protocol in token schema
|
|
1683
|
-
if (!tokenSchema) {
|
|
1684
|
-
tokenSchema = {
|
|
1685
|
-
sso: {
|
|
1686
|
-
protocol: sso.protocol
|
|
1687
|
-
}
|
|
1688
|
-
};
|
|
1689
|
-
} else if (tokenSchema && !tokenSchema.sso) {
|
|
1690
|
-
tokenSchema.sso = {
|
|
1691
|
-
protocol: sso.protocol
|
|
1692
|
-
};
|
|
1693
|
-
} else if (tokenSchema && tokenSchema.sso && !tokenSchema.sso.protocol) {
|
|
1694
|
-
tokenSchema.sso.protocol = sso.protocol;
|
|
1675
|
+
if (thisAHdata.Accept === '') {
|
|
1676
|
+
delete thisAHdata.Accept;
|
|
1677
|
+
}
|
|
1678
|
+
if (thisAHdata['Content-Type'] === '') {
|
|
1679
|
+
delete thisAHdata['Content-Type'];
|
|
1695
1680
|
}
|
|
1696
|
-
}
|
|
1697
|
-
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.host) {
|
|
1698
|
-
options.hostname = tokenSchema.sso.host;
|
|
1699
|
-
}
|
|
1700
|
-
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.port) {
|
|
1701
|
-
options.port = tokenSchema.sso.port;
|
|
1702
|
-
}
|
|
1703
1681
|
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1682
|
+
// set up the options for the call to get incidents - default is all
|
|
1683
|
+
const options = {
|
|
1684
|
+
hostname: host,
|
|
1685
|
+
port,
|
|
1686
|
+
path: tokenPath,
|
|
1687
|
+
method: 'POST',
|
|
1688
|
+
headers: thisAHdata
|
|
1689
|
+
};
|
|
1709
1690
|
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
if (
|
|
1715
|
-
|
|
1691
|
+
// passed in properties override defaults
|
|
1692
|
+
if (callProperties && callProperties.host) {
|
|
1693
|
+
options.hostname = callProperties.host;
|
|
1694
|
+
}
|
|
1695
|
+
if (callProperties && callProperties.port) {
|
|
1696
|
+
options.port = callProperties.port;
|
|
1716
1697
|
}
|
|
1717
1698
|
|
|
1718
|
-
//
|
|
1719
|
-
if (
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1699
|
+
// specific token properties override everything (Single Sign On System)
|
|
1700
|
+
if (sso && sso.host) {
|
|
1701
|
+
options.hostname = sso.host;
|
|
1702
|
+
}
|
|
1703
|
+
if (sso && sso.port) {
|
|
1704
|
+
options.port = sso.port;
|
|
1705
|
+
}
|
|
1706
|
+
if (sso && sso.protocol) {
|
|
1707
|
+
// need to put protocol in token schema
|
|
1708
|
+
if (!tokenSchema) {
|
|
1709
|
+
tokenSchema = {
|
|
1710
|
+
sso: {
|
|
1711
|
+
protocol: sso.protocol
|
|
1712
|
+
}
|
|
1713
|
+
};
|
|
1714
|
+
} else if (tokenSchema && !tokenSchema.sso) {
|
|
1715
|
+
tokenSchema.sso = {
|
|
1716
|
+
protocol: sso.protocol
|
|
1717
|
+
};
|
|
1718
|
+
} else if (tokenSchema && tokenSchema.sso && !tokenSchema.sso.protocol) {
|
|
1719
|
+
tokenSchema.sso.protocol = sso.protocol;
|
|
1732
1720
|
}
|
|
1733
|
-
} else {
|
|
1734
|
-
options.path = options.path.replace(bpathStr, '');
|
|
1735
1721
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
// be able to support this if the version has a slash before it or not
|
|
1742
|
-
if (options.path.indexOf('/{version}') >= 0) {
|
|
1743
|
-
versStr = '/{version}';
|
|
1722
|
+
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.host) {
|
|
1723
|
+
options.hostname = tokenSchema.sso.host;
|
|
1724
|
+
}
|
|
1725
|
+
if (tokenSchema && tokenSchema.sso && tokenSchema.sso.port) {
|
|
1726
|
+
options.port = tokenSchema.sso.port;
|
|
1744
1727
|
}
|
|
1745
1728
|
|
|
1746
|
-
//
|
|
1747
|
-
if (
|
|
1748
|
-
options.path =
|
|
1749
|
-
|
|
1750
|
-
options.path = options.path.replace(versStr, `/${encodeURIComponent(version)}`);
|
|
1751
|
-
} else {
|
|
1752
|
-
options.path = options.path.replace(versStr, '');
|
|
1729
|
+
// If there is a token schema, need to take the data from there
|
|
1730
|
+
if (tokenSchema) {
|
|
1731
|
+
options.path = tokenSchema.entitypath;
|
|
1732
|
+
options.method = tokenSchema.method;
|
|
1753
1733
|
}
|
|
1754
|
-
}
|
|
1755
1734
|
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
//
|
|
1765
|
-
if (
|
|
1766
|
-
//
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
// check if the current URI path ends with a slash (may require
|
|
1770
|
-
// slash at end)
|
|
1771
|
-
if (options.path[hindex - 2] === '/' || options.path[hindex - 2] === ':') {
|
|
1772
|
-
// ends with a slash need to add slash to end
|
|
1773
|
-
idString = encodeURIComponent(reqBody.uriPathVars[p]);
|
|
1735
|
+
// if the path has a base path parameter in it, need to replace it
|
|
1736
|
+
let bpathStr = '{base_path}';
|
|
1737
|
+
if (options.path.indexOf(bpathStr) >= 0) {
|
|
1738
|
+
// be able to support this if the base path has a slash before it or not
|
|
1739
|
+
if (options.path.indexOf('/{base_path}') >= 0) {
|
|
1740
|
+
bpathStr = '/{base_path}';
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
// replace with base path if we have one, otherwise remove base path
|
|
1744
|
+
if (callProperties && callProperties.base_path) {
|
|
1745
|
+
// if no leading /, insert one
|
|
1746
|
+
if (callProperties.base_path.indexOf('/') !== 0) {
|
|
1747
|
+
options.path = options.path.replace(bpathStr, `/${callProperties.base_path}`);
|
|
1774
1748
|
} else {
|
|
1775
|
-
|
|
1776
|
-
idString = '/';
|
|
1777
|
-
idString += encodeURIComponent(reqBody.uriPathVars[p]);
|
|
1749
|
+
options.path = options.path.replace(bpathStr, callProperties.base_path);
|
|
1778
1750
|
}
|
|
1751
|
+
} else if (basepath) {
|
|
1752
|
+
// if no leading /, insert one
|
|
1753
|
+
if (basepath.indexOf('/') !== 0) {
|
|
1754
|
+
options.path = options.path.replace(bpathStr, `/${basepath}`);
|
|
1755
|
+
} else {
|
|
1756
|
+
options.path = options.path.replace(bpathStr, basepath);
|
|
1757
|
+
}
|
|
1758
|
+
} else {
|
|
1759
|
+
options.path = options.path.replace(bpathStr, '');
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
// if the path has a version parameter in it, need to replace it
|
|
1764
|
+
let versStr = '{version}';
|
|
1765
|
+
if (options.path.indexOf(versStr) >= 0) {
|
|
1766
|
+
// be able to support this if the version has a slash before it or not
|
|
1767
|
+
if (options.path.indexOf('/{version}') >= 0) {
|
|
1768
|
+
versStr = '/{version}';
|
|
1769
|
+
}
|
|
1779
1770
|
|
|
1780
|
-
|
|
1781
|
-
|
|
1771
|
+
// replace with version if we have one, otherwise remove version
|
|
1772
|
+
if (callProperties && callProperties.version) {
|
|
1773
|
+
options.path = options.path.replace(versStr, `/${encodeURIComponent(callProperties.version)}`);
|
|
1774
|
+
} else if (version) {
|
|
1775
|
+
options.path = options.path.replace(versStr, `/${encodeURIComponent(version)}`);
|
|
1776
|
+
} else {
|
|
1777
|
+
options.path = options.path.replace(versStr, '');
|
|
1782
1778
|
}
|
|
1783
1779
|
}
|
|
1784
|
-
}
|
|
1785
1780
|
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1781
|
+
// if there are URI path variables that have been provided, need to add
|
|
1782
|
+
// them to the path
|
|
1783
|
+
if (reqBody && reqBody.uriPathVars && reqBody.uriPathVars.length > 0) {
|
|
1784
|
+
for (let p = 0; p < reqBody.uriPathVars.length; p += 1) {
|
|
1785
|
+
const vnum = p + 1;
|
|
1786
|
+
const holder = `pathv${vnum.toString()}`;
|
|
1787
|
+
const hindex = options.path.indexOf(holder);
|
|
1788
|
+
|
|
1789
|
+
// if path variable is in the url, replace it!!!
|
|
1790
|
+
if (hindex >= 0 && reqBody.uriPathVars[p] !== null && reqBody.uriPathVars[p] !== '') {
|
|
1791
|
+
// with the provided id
|
|
1792
|
+
let idString = '';
|
|
1793
|
+
|
|
1794
|
+
// check if the current URI path ends with a slash (may require
|
|
1795
|
+
// slash at end)
|
|
1796
|
+
if (options.path[hindex - 2] === '/' || options.path[hindex - 2] === ':') {
|
|
1797
|
+
// ends with a slash need to add slash to end
|
|
1798
|
+
idString = encodeURIComponent(reqBody.uriPathVars[p]);
|
|
1799
|
+
} else {
|
|
1800
|
+
// otherwise add / to start
|
|
1801
|
+
idString = '/';
|
|
1802
|
+
idString += encodeURIComponent(reqBody.uriPathVars[p]);
|
|
1803
|
+
}
|
|
1790
1804
|
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1805
|
+
// replace the id in url with the id string
|
|
1806
|
+
options.path = options.path.replace(`{${holder}}`, idString);
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1794
1809
|
}
|
|
1795
1810
|
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
let
|
|
1811
|
+
// need to remove all of the remaining path holders from the URI
|
|
1812
|
+
while (options.path.indexOf('{pathv') >= 0) {
|
|
1813
|
+
let sIndex = options.path.indexOf('{pathv');
|
|
1814
|
+
const eIndex = options.path.indexOf('}', sIndex);
|
|
1799
1815
|
|
|
1800
|
-
if
|
|
1801
|
-
|
|
1802
|
-
|
|
1816
|
+
// if there is a / before the {pathv} need to remove it
|
|
1817
|
+
if (options.path[sIndex - 1] === '/' || options.path[sIndex - 1] === ':') {
|
|
1818
|
+
sIndex -= 1;
|
|
1803
1819
|
}
|
|
1804
1820
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1821
|
+
if (sIndex > 0) {
|
|
1822
|
+
// add the start of the path
|
|
1823
|
+
let tempStr = options.path.substring(0, sIndex);
|
|
1824
|
+
|
|
1825
|
+
if (eIndex < options.path.length) {
|
|
1826
|
+
// add the end of the path
|
|
1827
|
+
tempStr += options.path.substring(eIndex + 1);
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
options.path = tempStr;
|
|
1831
|
+
} else if (eIndex > 0 && eIndex < options.path.length) {
|
|
1832
|
+
// add the end of the path
|
|
1833
|
+
options.path = options.path.substring(eIndex + 1);
|
|
1834
|
+
} else {
|
|
1835
|
+
// should not get here - there is some issue in the uripath - missing
|
|
1836
|
+
// an end or the path is just {pathv#}
|
|
1837
|
+
// add the specific pieces of the error object
|
|
1838
|
+
const errorObj = this.transUtil.formatErrorObject(origin, 'Invalid Action File', ['missing entity path', '.system/getToken'], null, null, null);
|
|
1839
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1840
|
+
return reject(errorObj);
|
|
1841
|
+
}
|
|
1816
1842
|
}
|
|
1817
|
-
}
|
|
1818
1843
|
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1844
|
+
// only add global options if there are global options to add
|
|
1845
|
+
if (globalRequest && globalRequest.uriOptions
|
|
1846
|
+
&& Object.keys(globalRequest.uriOptions).length > 0) {
|
|
1847
|
+
const optionString = querystring.stringify(globalRequest.uriOptions);
|
|
1823
1848
|
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1849
|
+
// if no query paramters yet - start with ?
|
|
1850
|
+
if (options.path.indexOf('?') < 0) {
|
|
1851
|
+
options.path += `?${optionString}`;
|
|
1852
|
+
} else {
|
|
1853
|
+
// if already have query parameters, add on to end
|
|
1854
|
+
options.path += `&${optionString}`;
|
|
1855
|
+
}
|
|
1830
1856
|
}
|
|
1831
|
-
}
|
|
1832
1857
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1858
|
+
// remove the path vars from the reqBody
|
|
1859
|
+
const actReqBody = Object.assign({}, reqBody);
|
|
1860
|
+
if (actReqBody && actReqBody.uriPathVars) {
|
|
1861
|
+
delete actReqBody.uriPathVars;
|
|
1862
|
+
}
|
|
1838
1863
|
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1864
|
+
// if ssl enabled add the options for ssl
|
|
1865
|
+
if (callProperties && callProperties.ssl && Object.hasOwnProperty.call(callProperties.ssl, 'enabled')) {
|
|
1866
|
+
if (callProperties.ssl.enabled) {
|
|
1867
|
+
if (callProperties.ssl.accept_invalid_cert) {
|
|
1868
|
+
// if we are accepting invalid certificates (ok for lab not so much production)
|
|
1869
|
+
options.rejectUnauthorized = false;
|
|
1870
|
+
} else {
|
|
1871
|
+
// if we are not accepting invalid certs, need the ca file in the options
|
|
1872
|
+
try {
|
|
1873
|
+
options.rejectUnauthorized = true;
|
|
1874
|
+
options.ca = [fs.readFileSync(callProperties.ssl.ca_file)];
|
|
1875
|
+
} catch (e) {
|
|
1876
|
+
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [callProperties.ssl.ca_file], null, null, null);
|
|
1877
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1878
|
+
return reject(errorObj);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
if (callProperties.ssl.ciphers) {
|
|
1883
|
+
options.ciphers = callProperties.ssl.ciphers;
|
|
1884
|
+
}
|
|
1885
|
+
if (callProperties.ssl.secure_protocol) {
|
|
1886
|
+
options.secureProtocol = callProperties.ssl.secure_protocol;
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
log.info(`${origin}: Connector SSL connections enabled`);
|
|
1890
|
+
}
|
|
1891
|
+
} else if (sslEnabled) {
|
|
1892
|
+
if (sslAcceptInvalid) {
|
|
1843
1893
|
// if we are accepting invalid certificates (ok for lab not so much production)
|
|
1844
1894
|
options.rejectUnauthorized = false;
|
|
1845
1895
|
} else {
|
|
1846
1896
|
// if we are not accepting invalid certs, need the ca file in the options
|
|
1847
1897
|
try {
|
|
1848
1898
|
options.rejectUnauthorized = true;
|
|
1849
|
-
options.ca = [fs.readFileSync(
|
|
1899
|
+
options.ca = [fs.readFileSync(sslCAFile)];
|
|
1850
1900
|
} catch (e) {
|
|
1851
|
-
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [
|
|
1901
|
+
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslCAFile], null, null, null);
|
|
1852
1902
|
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1853
|
-
return
|
|
1903
|
+
return reject(errorObj);
|
|
1904
|
+
}
|
|
1905
|
+
// if there is a cert file, try to read in a cert file in the options
|
|
1906
|
+
if (sslCertFile) {
|
|
1907
|
+
try {
|
|
1908
|
+
options.cert = [fs.readFileSync(sslCertFile)];
|
|
1909
|
+
} catch (e) {
|
|
1910
|
+
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslCertFile], null, null, null);
|
|
1911
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1912
|
+
return reject(errorObj);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
// if there is a key file, try to read in a key file in the options
|
|
1916
|
+
if (sslKeyFile) {
|
|
1917
|
+
try {
|
|
1918
|
+
options.key = [fs.readFileSync(sslKeyFile)];
|
|
1919
|
+
} catch (e) {
|
|
1920
|
+
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslKeyFile], null, null, null);
|
|
1921
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1922
|
+
return reject(errorObj);
|
|
1923
|
+
}
|
|
1854
1924
|
}
|
|
1855
1925
|
}
|
|
1856
1926
|
|
|
1857
|
-
if (
|
|
1858
|
-
options.ciphers =
|
|
1859
|
-
}
|
|
1860
|
-
if (callProperties.ssl.secure_protocol) {
|
|
1861
|
-
options.secureProtocol = callProperties.ssl.secure_protocol;
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
log.info(`${origin}: Connector SSL connections enabled`);
|
|
1865
|
-
}
|
|
1866
|
-
} else if (sslEnabled) {
|
|
1867
|
-
if (sslAcceptInvalid) {
|
|
1868
|
-
// if we are accepting invalid certificates (ok for lab not so much production)
|
|
1869
|
-
options.rejectUnauthorized = false;
|
|
1870
|
-
} else {
|
|
1871
|
-
// if we are not accepting invalid certs, need the ca file in the options
|
|
1872
|
-
try {
|
|
1873
|
-
options.rejectUnauthorized = true;
|
|
1874
|
-
options.ca = [fs.readFileSync(sslCAFile)];
|
|
1875
|
-
} catch (e) {
|
|
1876
|
-
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslCAFile], null, null, null);
|
|
1877
|
-
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1878
|
-
return callback(null, errorObj);
|
|
1927
|
+
if (sslCiphers) {
|
|
1928
|
+
options.ciphers = sslCiphers;
|
|
1879
1929
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
try {
|
|
1883
|
-
options.cert = [fs.readFileSync(sslCertFile)];
|
|
1884
|
-
} catch (e) {
|
|
1885
|
-
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslCertFile], null, null, null);
|
|
1886
|
-
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1887
|
-
return callback(null, errorObj);
|
|
1888
|
-
}
|
|
1930
|
+
if (sslPassphrase) {
|
|
1931
|
+
options.passphrase = sslPassphrase;
|
|
1889
1932
|
}
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
try {
|
|
1893
|
-
options.key = [fs.readFileSync(sslKeyFile)];
|
|
1894
|
-
} catch (e) {
|
|
1895
|
-
const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslKeyFile], null, null, null);
|
|
1896
|
-
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
1897
|
-
return callback(null, errorObj);
|
|
1898
|
-
}
|
|
1933
|
+
if (secureProtocol) {
|
|
1934
|
+
options.secureProtocol = secureProtocol;
|
|
1899
1935
|
}
|
|
1900
|
-
}
|
|
1901
1936
|
|
|
1902
|
-
|
|
1903
|
-
options.ciphers = sslCiphers;
|
|
1904
|
-
}
|
|
1905
|
-
if (secureProtocol) {
|
|
1906
|
-
options.secureProtocol = secureProtocol;
|
|
1937
|
+
log.info(`${origin}: Connector SSL connections enabled`);
|
|
1907
1938
|
}
|
|
1908
1939
|
|
|
1909
|
-
|
|
1910
|
-
|
|
1940
|
+
const reqData = {};
|
|
1941
|
+
let bodyString = null;
|
|
1942
|
+
|
|
1943
|
+
// if we have been passed a schema and the Authorization is in a header
|
|
1944
|
+
// COMMENTED OUT AND HANDLED IN IF BELOW - take stuff out of body on line 1930
|
|
1945
|
+
// if (tokenSchema && tokenSchema.headers && tokenSchema.headers.Authorization) {
|
|
1946
|
+
// // request the token
|
|
1947
|
+
// options.headers['Content-length'] = 0;
|
|
1948
|
+
// return getToken(reqPath, options, tokenSchema, '', callProperties, callback);
|
|
1949
|
+
// }
|
|
1950
|
+
if (tokenSchema) {
|
|
1951
|
+
// if this is a get, need to put the username on the url
|
|
1952
|
+
if (options.path.indexOf('/{username}') >= 0) {
|
|
1953
|
+
options.path = options.path.replace('/{username}', useUser);
|
|
1954
|
+
} else {
|
|
1955
|
+
options.path = options.path.replace('{username}', useUser);
|
|
1956
|
+
}
|
|
1911
1957
|
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
// // request the token
|
|
1919
|
-
// options.headers['Content-length'] = 0;
|
|
1920
|
-
// return getToken(reqPath, options, tokenSchema, '', callProperties, callback);
|
|
1921
|
-
// }
|
|
1922
|
-
if (tokenSchema) {
|
|
1923
|
-
// if this is a get, need to put the username on the url
|
|
1924
|
-
if (options.path.indexOf('/{username}') >= 0) {
|
|
1925
|
-
options.path = options.path.replace('/{username}', useUser);
|
|
1926
|
-
} else {
|
|
1927
|
-
options.path = options.path.replace('{username}', useUser);
|
|
1928
|
-
}
|
|
1958
|
+
// if this is a get, need to put the password on the url
|
|
1959
|
+
if (options.path.indexOf('/{password}') >= 0) {
|
|
1960
|
+
options.path = options.path.replace('/{password}', usePass);
|
|
1961
|
+
} else {
|
|
1962
|
+
options.path = options.path.replace('{password}', usePass);
|
|
1963
|
+
}
|
|
1929
1964
|
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
options.
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1965
|
+
// if this is not a get, need to add the info to the request
|
|
1966
|
+
let creds = {};
|
|
1967
|
+
if (options.method !== 'GET') {
|
|
1968
|
+
if (authMethod === 'multi_step_authentication') {
|
|
1969
|
+
const { stepBody, stepHeaders } = callProperties.mfa;
|
|
1970
|
+
Object.assign(creds, stepBody);
|
|
1971
|
+
Object.assign(options.headers, stepHeaders);
|
|
1972
|
+
} else {
|
|
1973
|
+
creds = {
|
|
1974
|
+
username: useUser,
|
|
1975
|
+
password: usePass
|
|
1976
|
+
};
|
|
1977
|
+
if (clientId) {
|
|
1978
|
+
creds.client_id = clientId;
|
|
1979
|
+
}
|
|
1980
|
+
if (clientSecret) {
|
|
1981
|
+
creds.client_secret = clientSecret;
|
|
1982
|
+
}
|
|
1983
|
+
if (grantType) {
|
|
1984
|
+
creds.grant_type = grantType;
|
|
1985
|
+
}
|
|
1986
|
+
if (callProperties && callProperties.authentication && callProperties.authentication.client_id) {
|
|
1987
|
+
creds.client_id = callProperties.authentication.client_id;
|
|
1988
|
+
}
|
|
1989
|
+
if (callProperties && callProperties.authentication && callProperties.authentication.client_secret) {
|
|
1990
|
+
creds.client_secret = callProperties.authentication.client_secret;
|
|
1991
|
+
}
|
|
1992
|
+
if (callProperties && callProperties.authentication && callProperties.authentication.grant_type) {
|
|
1993
|
+
creds.grant_type = callProperties.authentication.grant_type;
|
|
1994
|
+
}
|
|
1936
1995
|
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
let creds = {
|
|
1940
|
-
username: useUser,
|
|
1941
|
-
password: usePass
|
|
1942
|
-
};
|
|
1943
|
-
if (clientId) {
|
|
1944
|
-
creds.client_id = clientId;
|
|
1945
|
-
}
|
|
1946
|
-
if (clientSecret) {
|
|
1947
|
-
creds.client_secret = clientSecret;
|
|
1948
|
-
}
|
|
1949
|
-
if (grantType) {
|
|
1950
|
-
creds.grant_type = grantType;
|
|
1951
|
-
}
|
|
1952
|
-
if (callProperties && callProperties.authentication && callProperties.authentication.client_id) {
|
|
1953
|
-
creds.client_id = callProperties.authentication.client_id;
|
|
1954
|
-
}
|
|
1955
|
-
if (callProperties && callProperties.authentication && callProperties.authentication.client_secret) {
|
|
1956
|
-
creds.client_secret = callProperties.authentication.client_secret;
|
|
1957
|
-
}
|
|
1958
|
-
if (callProperties && callProperties.authentication && callProperties.authentication.grant_type) {
|
|
1959
|
-
creds.grant_type = callProperties.authentication.grant_type;
|
|
1960
|
-
}
|
|
1996
|
+
// if there is body data to add to the token request body
|
|
1997
|
+
creds = transUtilInst.mergeObjects(actReqBody, creds);
|
|
1961
1998
|
|
|
1962
|
-
|
|
1963
|
-
|
|
1999
|
+
if (globalRequest) {
|
|
2000
|
+
creds = transUtilInst.mergeObjects(creds, globalRequest.authData);
|
|
2001
|
+
}
|
|
1964
2002
|
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2003
|
+
// if there is body data to add to the token request body
|
|
2004
|
+
if (actReqBody) {
|
|
2005
|
+
const bodyKey = Object.keys(actReqBody);
|
|
1968
2006
|
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2007
|
+
for (let k = 0; k < bodyKey.length; k += 1) {
|
|
2008
|
+
creds[bodyKey[k]] = actReqBody[bodyKey[k]];
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
1972
2011
|
|
|
1973
|
-
|
|
1974
|
-
|
|
2012
|
+
if (tokenSchema.headers && tokenSchema.headers.Authorization) {
|
|
2013
|
+
// remove the username and password from the creds
|
|
2014
|
+
delete creds.username;
|
|
2015
|
+
delete creds.password;
|
|
2016
|
+
}
|
|
1975
2017
|
}
|
|
1976
|
-
}
|
|
1977
2018
|
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
delete creds.password;
|
|
1982
|
-
}
|
|
2019
|
+
// map the data we received to an Entity - will get back the defaults
|
|
2020
|
+
const tokenEntity = transUtilInst.mapToOutboundEntity(creds, tokenSchema.requestSchema);
|
|
2021
|
+
bodyString = tokenEntity;
|
|
1983
2022
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
2023
|
+
// if it is JSON or URLENCODE need to put body into right format
|
|
2024
|
+
if (!tokenSchema.requestDatatype || tokenSchema.requestDatatype.toUpperCase() === 'JSON' || tokenSchema.requestDatatype.toUpperCase() === 'FORM') {
|
|
2025
|
+
bodyString = JSON.stringify(tokenEntity);
|
|
2026
|
+
} else if (tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLENCODE') {
|
|
2027
|
+
bodyString = querystring.stringify(tokenEntity);
|
|
2028
|
+
} else if (tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLQUERY') {
|
|
2029
|
+
// if the datatype is URLQUERY need to put into the query on the request
|
|
2030
|
+
if (authQueryEncode != null) {
|
|
2031
|
+
if (authQueryEncode === true) {
|
|
2032
|
+
bodyString = querystring.stringify(tokenEntity);
|
|
2033
|
+
} else {
|
|
2034
|
+
bodyString = '';
|
|
2035
|
+
// if not encoding we need to build
|
|
2036
|
+
const qkeys = Object.keys(tokenEntity);
|
|
2037
|
+
// add each query parameter and its value
|
|
2038
|
+
for (let k = 0; k < qkeys.length; k += 1) {
|
|
2039
|
+
// need to add separator for everything after the first one
|
|
2040
|
+
if (k > 0) {
|
|
2041
|
+
bodyString += '&';
|
|
2042
|
+
}
|
|
2043
|
+
// adds key=value
|
|
2044
|
+
bodyString += `${qkeys[k]}=${tokenEntity[qkeys[k]]}`;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
} else if (encodeUri === true) {
|
|
1997
2048
|
bodyString = querystring.stringify(tokenEntity);
|
|
1998
2049
|
} else {
|
|
1999
2050
|
bodyString = '';
|
|
@@ -2009,60 +2060,58 @@ function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
|
|
|
2009
2060
|
bodyString += `${qkeys[k]}=${tokenEntity[qkeys[k]]}`;
|
|
2010
2061
|
}
|
|
2011
2062
|
}
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
// add each query parameter and its value
|
|
2019
|
-
for (let k = 0; k < qkeys.length; k += 1) {
|
|
2020
|
-
// need to add separator for everything after the first one
|
|
2021
|
-
if (k > 0) {
|
|
2022
|
-
bodyString += '&';
|
|
2023
|
-
}
|
|
2024
|
-
// adds key=value
|
|
2025
|
-
bodyString += `${qkeys[k]}=${tokenEntity[qkeys[k]]}`;
|
|
2063
|
+
|
|
2064
|
+
// append to the path
|
|
2065
|
+
if (options.path.indexOf('?') < 0) {
|
|
2066
|
+
options.path = `${options.path}?${bodyString}`;
|
|
2067
|
+
} else {
|
|
2068
|
+
options.path = `${options.path}&${bodyString}`;
|
|
2026
2069
|
}
|
|
2070
|
+
bodyString = '';
|
|
2027
2071
|
}
|
|
2028
|
-
|
|
2029
|
-
//
|
|
2030
|
-
if (
|
|
2031
|
-
options.
|
|
2032
|
-
} else {
|
|
2033
|
-
options.path = `${options.path}&${bodyString}`;
|
|
2072
|
+
// if there is a body, set the content length of the body and add it to
|
|
2073
|
+
// the header
|
|
2074
|
+
if (Object.keys(tokenEntity).length > 0 || tokenSchema.sendEmpty) {
|
|
2075
|
+
options.headers['Content-length'] = Buffer.byteLength(bodyString);
|
|
2034
2076
|
}
|
|
2035
|
-
bodyString = '';
|
|
2036
|
-
}
|
|
2037
2077
|
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2078
|
+
// request the token
|
|
2079
|
+
await getToken(reqPath, options, tokenSchema, bodyString, callProperties).then((result) => {
|
|
2080
|
+
resolve(result);
|
|
2081
|
+
}).catch((error) => {
|
|
2082
|
+
reject(error);
|
|
2083
|
+
});
|
|
2084
|
+
return;
|
|
2042
2085
|
}
|
|
2043
|
-
|
|
2044
|
-
//
|
|
2045
|
-
|
|
2086
|
+
} else {
|
|
2087
|
+
// set the user and password for the token request
|
|
2088
|
+
reqData[tokenUserField] = useUser;
|
|
2089
|
+
reqData[tokenPwdField] = usePass;
|
|
2090
|
+
bodyString = reqData;
|
|
2091
|
+
|
|
2092
|
+
// since not a get call, convert reqData to a string and add length
|
|
2093
|
+
bodyString = JSON.stringify(reqData);
|
|
2094
|
+
options.headers['Content-length'] = Buffer.byteLength(bodyString);
|
|
2046
2095
|
}
|
|
2047
|
-
} else {
|
|
2048
|
-
// set the user and password for the token request
|
|
2049
|
-
reqData[tokenUserField] = useUser;
|
|
2050
|
-
reqData[tokenPwdField] = usePass;
|
|
2051
|
-
bodyString = reqData;
|
|
2052
2096
|
|
|
2053
|
-
//
|
|
2054
|
-
bodyString
|
|
2055
|
-
|
|
2056
|
-
|
|
2097
|
+
// request the token
|
|
2098
|
+
await getToken(reqPath, options, tokenSchema, bodyString, callProperties).then((result) => {
|
|
2099
|
+
resolve(result);
|
|
2100
|
+
}).catch((error) => {
|
|
2101
|
+
reject(error);
|
|
2102
|
+
});
|
|
2103
|
+
});
|
|
2104
|
+
} catch (e) {
|
|
2105
|
+
// handle any exception
|
|
2106
|
+
const errorObj = transUtilInst.checkAndReturn(e, origin, 'Issue requesting token');
|
|
2107
|
+
return reject(errorObj);
|
|
2108
|
+
}
|
|
2109
|
+
});
|
|
2057
2110
|
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
});
|
|
2061
|
-
} catch (e) {
|
|
2062
|
-
// handle any exception
|
|
2063
|
-
const errorObj = transUtilInst.checkAndReturn(e, origin, 'Issue requesting token');
|
|
2064
|
-
return callback(null, errorObj);
|
|
2111
|
+
if (typeof callback === 'function') {
|
|
2112
|
+
return promise.then((result) => callback(result)).catch((error) => callback(null, error));
|
|
2065
2113
|
}
|
|
2114
|
+
return promise;
|
|
2066
2115
|
}
|
|
2067
2116
|
|
|
2068
2117
|
/*
|
|
@@ -2409,6 +2458,264 @@ function addAuthToRequest(request, authStrs, callProperties, callback) {
|
|
|
2409
2458
|
}
|
|
2410
2459
|
}
|
|
2411
2460
|
|
|
2461
|
+
/* */
|
|
2462
|
+
function buildAuthDataMfa(finalTokens, callProperties) {
|
|
2463
|
+
const authStrs = [];
|
|
2464
|
+
if (callProperties && callProperties.authentication && callProperties.authentication.auth_field_format) {
|
|
2465
|
+
if (Array.isArray(callProperties.authentication.auth_field_format)) {
|
|
2466
|
+
for (let a = 0; a < callProperties.authentication.auth_field_format.length; a += 1) {
|
|
2467
|
+
let authStr = callProperties.authentication.auth_field_format[a].replace('{token}', finalTokens.token);
|
|
2468
|
+
authStr = authStr.replace('{tokenp2}', finalTokens.tokenp2);
|
|
2469
|
+
authStrs.push(authStr);
|
|
2470
|
+
}
|
|
2471
|
+
} else {
|
|
2472
|
+
let authStr = callProperties.authentication.auth_field_format.replace('{token}', finalTokens.token);
|
|
2473
|
+
authStr = authStr.replace('{tokenp2}', finalTokens.tokenp2);
|
|
2474
|
+
authStrs.push(authStr);
|
|
2475
|
+
}
|
|
2476
|
+
} else {
|
|
2477
|
+
for (let a = 0; a < authFormat.length; a += 1) {
|
|
2478
|
+
let authStr = authFormat[a].replace('{token}', finalTokens.token);
|
|
2479
|
+
authStr = authStr.replace('{tokenp2}', finalTokens.tokenp2);
|
|
2480
|
+
// if authFormat needs referenced value from previous steps (e.g., Bearer {getSession.responseFields.session})
|
|
2481
|
+
if (!authFormat[a].includes('{token}') && !authFormat[a].includes('{tokenp2}')) {
|
|
2482
|
+
const matching = searchTextInCurlyBraces(authStr);
|
|
2483
|
+
let propertyValue = authFormat[a];
|
|
2484
|
+
if (matching) {
|
|
2485
|
+
const matchedText = matching[0];
|
|
2486
|
+
propertyValue = matching[1];
|
|
2487
|
+
const resolvedValue = getReferencedMfaValue(propertyValue);
|
|
2488
|
+
authStr = authStr.replace(matchedText, resolvedValue);
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
authStrs.push(authStr);
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
return authStrs;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
/* */
|
|
2498
|
+
const searchTextInCurlyBraces = (text) => {
|
|
2499
|
+
const rxp = /{([^}]+)}/g;
|
|
2500
|
+
const matching = rxp.exec(text);
|
|
2501
|
+
return matching;
|
|
2502
|
+
};
|
|
2503
|
+
|
|
2504
|
+
/* */
|
|
2505
|
+
function buildMfaHeader(prop, mfaStepConfiguration, callProperties) {
|
|
2506
|
+
const origin = `${id}-connectorRest-buildMfaHeader`;
|
|
2507
|
+
log.trace(origin);
|
|
2508
|
+
const fullPropertyValue = mfaStepConfiguration.requestFields[prop];
|
|
2509
|
+
// Check if fullPropertyValue has reference in curly braces (e.g., Bearer {getSession.responseFields.session})
|
|
2510
|
+
let propertyValue = fullPropertyValue;
|
|
2511
|
+
const matching = searchTextInCurlyBraces(fullPropertyValue);
|
|
2512
|
+
const headerName = prop.split('.')[1];
|
|
2513
|
+
if (matching) {
|
|
2514
|
+
const matchedText = matching[0];
|
|
2515
|
+
propertyValue = matching[1];
|
|
2516
|
+
const resolvedValue = getReferencedMfaValue(propertyValue);
|
|
2517
|
+
callProperties.mfa.stepHeaders[headerName] = fullPropertyValue.replace(matchedText, resolvedValue);
|
|
2518
|
+
} else {
|
|
2519
|
+
callProperties.mfa.stepHeaders[headerName] = mfaStepConfiguration.requestFields[prop];
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
/* */
|
|
2524
|
+
function buildMfaBody(prop, mfaStepConfiguration, callProperties) {
|
|
2525
|
+
const origin = `${id}-connectorRest-buildMfaBody`;
|
|
2526
|
+
log.trace(origin);
|
|
2527
|
+
const fullPropertyValue = mfaStepConfiguration.requestFields[prop];
|
|
2528
|
+
// Check if fullPropertyValue has reference in curly braces (e.g., {getSubToken.responseFields.token})
|
|
2529
|
+
let propertyValue = fullPropertyValue;
|
|
2530
|
+
const matching = searchTextInCurlyBraces(fullPropertyValue);
|
|
2531
|
+
if (matching) {
|
|
2532
|
+
const matchedText = matching[0];
|
|
2533
|
+
propertyValue = matching[1];
|
|
2534
|
+
const resolvedValue = getReferencedMfaValue(propertyValue);
|
|
2535
|
+
callProperties.mfa.stepBody[prop] = fullPropertyValue.replace(matchedText, resolvedValue);
|
|
2536
|
+
} else {
|
|
2537
|
+
callProperties.mfa.stepBody[prop] = mfaStepConfiguration.requestFields[prop];
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
/* */
|
|
2541
|
+
function getReferencedMfaValue(propertyValue) {
|
|
2542
|
+
const origin = `${id}-connectorRest-getReferencedMfaValue`;
|
|
2543
|
+
log.trace(origin);
|
|
2544
|
+
let stepRequestField = null;
|
|
2545
|
+
// e.g. prop value is: 'getSession.responseFields.session'
|
|
2546
|
+
const referencedStepName = propertyValue.split('.')[0]; // getSession
|
|
2547
|
+
const referencedPropertyName = propertyValue.split('.')[2]; // session
|
|
2548
|
+
const referencedMfaCallConfig = multiStepAuthCalls.find((item) => item.name === referencedStepName);
|
|
2549
|
+
const referencedMfaCallResult = mfaStepsResults.find((item) => item.name === referencedStepName);
|
|
2550
|
+
if (referencedMfaCallConfig.responseFields[referencedPropertyName]) {
|
|
2551
|
+
stepRequestField = referencedMfaCallResult.result[referencedPropertyName];
|
|
2552
|
+
}
|
|
2553
|
+
return stepRequestField;
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
/* */
|
|
2557
|
+
function buildMfaStepData(step, callProperties) {
|
|
2558
|
+
const origin = `${id}-connectorRest-buildMfaStepData`;
|
|
2559
|
+
log.trace(origin);
|
|
2560
|
+
const mfaStepConfiguration = multiStepAuthCalls[step];
|
|
2561
|
+
callProperties.mfa.stepBody = {};
|
|
2562
|
+
callProperties.mfa.stepHeaders = {};
|
|
2563
|
+
if (mfaStepConfiguration.requestFields) {
|
|
2564
|
+
Object.keys(mfaStepConfiguration.requestFields).forEach((prop) => {
|
|
2565
|
+
if (prop.startsWith('header')) {
|
|
2566
|
+
buildMfaHeader(prop, mfaStepConfiguration, callProperties);
|
|
2567
|
+
} else {
|
|
2568
|
+
buildMfaBody(prop, mfaStepConfiguration, callProperties);
|
|
2569
|
+
}
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
/* */
|
|
2575
|
+
async function translateMfaStepResult(step, stepResult, callProperties) {
|
|
2576
|
+
const origin = `${id}-connectorRest-translateMfaStepResult`;
|
|
2577
|
+
const mfaStepConfiguration = multiStepAuthCalls[step];
|
|
2578
|
+
const entity = callProperties.mfa.stepAtionName;
|
|
2579
|
+
// define the fields that are not mapped to its external name but keep its name
|
|
2580
|
+
// needed as 'expires' handling is hardcoded in findExpireInResult()
|
|
2581
|
+
const immutableFields = ['expires'];
|
|
2582
|
+
return new Promise((resolve, reject) => {
|
|
2583
|
+
// Get the entity schema from the file system
|
|
2584
|
+
propUtilInst.getEntitySchema('.system', entity, choosepath, this.dbUtil, async (tokenSchema, healthError) => {
|
|
2585
|
+
if (healthError) return reject(healthError);
|
|
2586
|
+
const allProperties = Object.keys(tokenSchema.responseSchema.properties);
|
|
2587
|
+
allProperties.forEach((prop) => {
|
|
2588
|
+
if (Object.prototype.hasOwnProperty.call(stepResult, prop)) {
|
|
2589
|
+
const externalName = tokenSchema.responseSchema.properties[prop].external_name;
|
|
2590
|
+
if (!stepResult[prop]) {
|
|
2591
|
+
log.error(`No step-${step + 1} result for responseSchema (prop=>external_name): (${prop}=>${externalName}) found in step response`);
|
|
2592
|
+
return reject(new Error(`Response schema for step-${step + 1} misconfiguration`));
|
|
2593
|
+
}
|
|
2594
|
+
// map response schema attribute name to MFA configured response field name
|
|
2595
|
+
let responseFieldName = Object.keys(mfaStepConfiguration.responseFields).find((key) => mfaStepConfiguration.responseFields[key] === externalName);
|
|
2596
|
+
if (!responseFieldName) {
|
|
2597
|
+
log.warn(`${origin}-Unable to map property: '${prop}' to external name: '${externalName}'. Check your mfa step ${step} configuration`);
|
|
2598
|
+
responseFieldName = prop;
|
|
2599
|
+
}
|
|
2600
|
+
if (!responseFieldName) {
|
|
2601
|
+
log.warn(`${origin}-Unable to map property: '${prop}'. Check your mfa step ${step} configuration`);
|
|
2602
|
+
}
|
|
2603
|
+
stepResult[responseFieldName] = stepResult[prop];
|
|
2604
|
+
// remove original property from response after mapping
|
|
2605
|
+
if (prop !== externalName && responseFieldName !== prop && immutableFields.indexOf(prop) === -1) delete stepResult[prop];
|
|
2606
|
+
}
|
|
2607
|
+
});
|
|
2608
|
+
return resolve(stepResult);
|
|
2609
|
+
});
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
/* Promisification of called callback-based function */
|
|
2614
|
+
function getCachedMfaToken(cachedTokenIdentifier, invalidToken) {
|
|
2615
|
+
const origin = `${id}-connectorRest-getCachedMfaToken`;
|
|
2616
|
+
log.trace(origin);
|
|
2617
|
+
|
|
2618
|
+
return new Promise((resolve, reject) => {
|
|
2619
|
+
validToken(id, cachedTokenIdentifier, invalidToken, (retToken, verror) => {
|
|
2620
|
+
if (verror) {
|
|
2621
|
+
reject(verror);
|
|
2622
|
+
} else {
|
|
2623
|
+
resolve(retToken);
|
|
2624
|
+
}
|
|
2625
|
+
});
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
/* Promisification of called callback-based function */
|
|
2630
|
+
function cacheMfaToken(cachedTokenIdentifier, token) {
|
|
2631
|
+
const origin = `${id}-connectorRest-cacheMfaToken`;
|
|
2632
|
+
log.trace(origin);
|
|
2633
|
+
|
|
2634
|
+
let timeout = tokenTimeout;
|
|
2635
|
+
// if we should use the timeout from the token request
|
|
2636
|
+
if (timeout === 0) {
|
|
2637
|
+
timeout = findExpireInResult(token);
|
|
2638
|
+
} else {
|
|
2639
|
+
// otherwise add the timeout to the current time
|
|
2640
|
+
timeout += new Date().getTime();
|
|
2641
|
+
}
|
|
2642
|
+
return new Promise((resolve, reject) => {
|
|
2643
|
+
addTokenItem(id, cachedTokenIdentifier, token, timeout, (addedtoken, error) => {
|
|
2644
|
+
if (error) {
|
|
2645
|
+
reject(error);
|
|
2646
|
+
} else {
|
|
2647
|
+
resolve(addedtoken);
|
|
2648
|
+
}
|
|
2649
|
+
});
|
|
2650
|
+
});
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
/* */
|
|
2654
|
+
async function getMfaFinalTokens(request, callProperties, invalidToken) {
|
|
2655
|
+
const origin = `${id}-connectorRest-getMfaFinalTokens`;
|
|
2656
|
+
let finalTokens = null; // final authentication token of the last step
|
|
2657
|
+
let stepToken = null; // result of given step request
|
|
2658
|
+
// token locked function
|
|
2659
|
+
const f = async () => {
|
|
2660
|
+
// retrieve token from cache and return it if still valid
|
|
2661
|
+
// adapter's Id and 1st item of MFA config is used as token identifier in cache
|
|
2662
|
+
const cachedTokenIdentifier = multiStepAuthCalls[0];
|
|
2663
|
+
const cachedToken = await getCachedMfaToken(cachedTokenIdentifier, invalidToken)
|
|
2664
|
+
.catch((error) => {
|
|
2665
|
+
log.error(error);
|
|
2666
|
+
throw error;
|
|
2667
|
+
});
|
|
2668
|
+
if (cachedToken) {
|
|
2669
|
+
log.debug(`${origin}-returning cached MFA token`);
|
|
2670
|
+
finalTokens = cachedToken;
|
|
2671
|
+
return;
|
|
2672
|
+
} mfaStepsResults.length = 0;
|
|
2673
|
+
// no cached token found, trigger auth steps to obtain new token
|
|
2674
|
+
for (let step = 0; step < multiStepAuthCalls.length; step += 1) {
|
|
2675
|
+
const stepAtionName = `MFA_Step_${step + 1}`;
|
|
2676
|
+
log.debug(`${origin}-Executing MFA step-${step + 1}, action: ${stepAtionName}`);
|
|
2677
|
+
if (!callProperties) {
|
|
2678
|
+
callProperties = {};
|
|
2679
|
+
}
|
|
2680
|
+
callProperties.mfa = { stepAtionName };
|
|
2681
|
+
if (multiStepAuthCalls[step].successfullResponseCode) {
|
|
2682
|
+
callProperties.mfa.successfullResponseCode = multiStepAuthCalls[step].successfullResponseCode;
|
|
2683
|
+
}
|
|
2684
|
+
buildMfaStepData(step, callProperties);
|
|
2685
|
+
stepToken = await buildTokenRequest(request.header.path, request.authData, callProperties).catch((error) => { // eslint-disable-line no-await-in-loop
|
|
2686
|
+
log.error(error);
|
|
2687
|
+
throw error;
|
|
2688
|
+
});
|
|
2689
|
+
log.debug(`${origin}-MFA result for step-${step + 1}, stepToken: ${JSON.stringify(stepToken)}`);
|
|
2690
|
+
// one of steps failing results in whole authentication chain failure
|
|
2691
|
+
if (!stepToken) {
|
|
2692
|
+
finalTokens = null;
|
|
2693
|
+
break;
|
|
2694
|
+
}
|
|
2695
|
+
const translatedStepResult = await translateMfaStepResult(step, stepToken, callProperties) // eslint-disable-line no-await-in-loop
|
|
2696
|
+
.catch((error) => {
|
|
2697
|
+
log.error(error);
|
|
2698
|
+
throw error;
|
|
2699
|
+
});
|
|
2700
|
+
mfaStepsResults.push({
|
|
2701
|
+
name: multiStepAuthCalls[step].name,
|
|
2702
|
+
result: translatedStepResult
|
|
2703
|
+
});
|
|
2704
|
+
// result of last MFA step request shall contain the final token used to authenticate subsequent requests
|
|
2705
|
+
finalTokens = stepToken;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// save final MFA token to cache for reuse in subsequent requests
|
|
2709
|
+
if (finalTokens) {
|
|
2710
|
+
await cacheMfaToken(cachedTokenIdentifier, finalTokens).catch((error) => log.error(error));
|
|
2711
|
+
}
|
|
2712
|
+
};
|
|
2713
|
+
// Aquire token lock across all MFA steps,
|
|
2714
|
+
// release it when final token is obtained or one of the steps fails
|
|
2715
|
+
await tlock.acquire(tokenlock, f);
|
|
2716
|
+
|
|
2717
|
+
return finalTokens;
|
|
2718
|
+
}
|
|
2412
2719
|
/*
|
|
2413
2720
|
* INTERNAL FUNCTION: requestAuthenticate determines the authentication for System,
|
|
2414
2721
|
* and takes appropriate action to authenticate and then makes the request
|
|
@@ -2429,6 +2736,34 @@ function requestAuthenticate(request, entitySchema, invalidToken, callProperties
|
|
|
2429
2736
|
usePass = callProperties.authentication.password;
|
|
2430
2737
|
}
|
|
2431
2738
|
|
|
2739
|
+
if (authMethod === 'multi_step_authentication') {
|
|
2740
|
+
// set MFA configuration out of adapter's configuration
|
|
2741
|
+
multiStepAuthCalls = props.authentication.multiStepAuthCalls;
|
|
2742
|
+
return getMfaFinalTokens(request, callProperties, invalidToken).then((finalTokens) => {
|
|
2743
|
+
if (!finalTokens) {
|
|
2744
|
+
const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Get Token', [useUser], null, null, null);
|
|
2745
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
2746
|
+
return callback(null, errorObj);
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
const authStrs = buildAuthDataMfa(finalTokens, callProperties);
|
|
2750
|
+
|
|
2751
|
+
return addAuthToRequest(request, authStrs, callProperties, (authReq, aerror) => {
|
|
2752
|
+
if (aerror) {
|
|
2753
|
+
return callback(aerror);
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
request.tokenUsed = authReq.token;
|
|
2757
|
+
|
|
2758
|
+
// actually make the request now that the authentication has been added
|
|
2759
|
+
return makeRequest(request, entitySchema, callProperties, null, 0, callback);
|
|
2760
|
+
});
|
|
2761
|
+
}).catch((error) => {
|
|
2762
|
+
log.error(`${origin}-${JSON.stringify(error)}`);
|
|
2763
|
+
return callback(null, error);
|
|
2764
|
+
});
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2432
2767
|
if (authMethod === 'request_token') {
|
|
2433
2768
|
// are we working with reusing tokens until they expire?
|
|
2434
2769
|
if (tokenTimeout >= 0) {
|
|
@@ -3403,6 +3738,10 @@ class ConnectorRest {
|
|
|
3403
3738
|
authMethod = props.authentication.auth_method;
|
|
3404
3739
|
}
|
|
3405
3740
|
|
|
3741
|
+
if (Array.isArray(props.authentication.multiStepAuthCalls)) {
|
|
3742
|
+
multiStepAuthCalls = props.authentication.multiStepAuthCalls;
|
|
3743
|
+
}
|
|
3744
|
+
|
|
3406
3745
|
// set the username (required - default is null)
|
|
3407
3746
|
if (typeof props.authentication.username === 'string') {
|
|
3408
3747
|
username = props.authentication.username;
|
|
@@ -3662,6 +4001,11 @@ class ConnectorRest {
|
|
|
3662
4001
|
sslCiphers = props.ssl.ciphers;
|
|
3663
4002
|
}
|
|
3664
4003
|
|
|
4004
|
+
// set the ssl passphrase (optional - default is null)
|
|
4005
|
+
if (typeof props.ssl.passphrase === 'string') {
|
|
4006
|
+
sslPassphrase = props.ssl.passphrase;
|
|
4007
|
+
}
|
|
4008
|
+
|
|
3665
4009
|
// set the ssl ciphers (optional - default is null)
|
|
3666
4010
|
if (typeof props.ssl.secure_protocol === 'string') {
|
|
3667
4011
|
secureProtocol = props.ssl.secure_protocol;
|
|
@@ -3949,6 +4293,9 @@ class ConnectorRest {
|
|
|
3949
4293
|
if (sslCiphers) {
|
|
3950
4294
|
options.ciphers = sslCiphers;
|
|
3951
4295
|
}
|
|
4296
|
+
if (sslPassphrase) {
|
|
4297
|
+
options.passphrase = sslPassphrase;
|
|
4298
|
+
}
|
|
3952
4299
|
if (secureProtocol) {
|
|
3953
4300
|
options.secureProtocol = secureProtocol;
|
|
3954
4301
|
}
|
|
@@ -4133,6 +4480,9 @@ class ConnectorRest {
|
|
|
4133
4480
|
if (sslCiphers) {
|
|
4134
4481
|
options.ciphers = sslCiphers;
|
|
4135
4482
|
}
|
|
4483
|
+
if (sslPassphrase) {
|
|
4484
|
+
options.passphrase = sslPassphrase;
|
|
4485
|
+
}
|
|
4136
4486
|
if (secureProtocol) {
|
|
4137
4487
|
options.secureProtocol = secureProtocol;
|
|
4138
4488
|
}
|