@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.
@@ -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
- try {
1124
- // no need for orig path since we handled the stub case
1125
- const request = {
1126
- header: options,
1127
- body: bodyString,
1128
- origPath: tokenSchema.entitypath
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 (!tokenSchema.responseDatatype || tokenSchema.responseDatatype === 'JSON') {
1152
- tokenResp.response = JSON.parse(tokenResp.response);
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
- // return the token from the token schema
1157
- let translated = null;
1158
- if (typeof tokenResp.response !== 'string') {
1159
- translated = transUtilInst.mapFromOutboundEntity(tokenResp.response, tokenSchema.responseSchema);
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
- // since this is a stub, make sure we have what we need
1165
- if (!translated.token) {
1166
- translated.token = 'garbagetoken';
1167
- }
1168
- if (!translated.tokenp2) {
1169
- translated.tokenp2 = 'garbagetoken';
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
- // if what we got back is an array, just return the first element
1173
- // should only have one token!!!
1174
- if (translated && Array.isArray(translated)) {
1175
- translated[0].front = tokenSchema.responseSchema.properties.token.front;
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
- // return the token that we find in the translated object
1181
- translated.front = tokenSchema.responseSchema.properties.token.front;
1182
- translated.end = tokenSchema.responseSchema.properties.token.end;
1183
- return callback(translated);
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
- if (useStub || reqPath === tokenPath || (tokenSchema && reqPath === tokenSchema.entitypath)) {
1187
- // do not make the call to return a token if the request is actually
1188
- // to get a token. Getting a token to get a token -- that should go
1189
- // direct to make request
1190
- return callback({ token: 'faketoken', tokenp2: 'faketoken' });
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
- log.debug(`${origin}: OPTIONS: ${JSON.stringify(options)}`);
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
- // request the token
1196
- return makeRequest(request, tokenSchema, callProperties, null, 0, (result, merror) => {
1197
- if (merror) {
1198
- return callback(null, merror);
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
- // if the request is a redirect, try to pull token but log a warning
1202
- let handleTokenRedirect = false;
1203
- if (result.code >= 300 && result.code <= 308 && numRedirects === 0) {
1204
- log.warn(`${origin}: Going to attempt to get token from redirect message!`);
1205
- handleTokenRedirect = true;
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
- // if the request failed, return the error
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
- if (!tokenSchema) {
1216
- // if no token schema, can not determine what to return
1217
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', result.code], null, null, null);
1218
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1219
- return callback(null, errorObj);
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
- // parse the token out of the result
1223
- const currResult = {
1224
- token: null,
1225
- tokenp2: null,
1226
- front: tokenSchema.responseSchema.properties.token.front,
1227
- end: tokenSchema.responseSchema.properties.token.end
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
- // process primary token from header
1231
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1232
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'HEADER') {
1233
- if (!tokenSchema.responseSchema.properties.token.external_name) {
1234
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Get Primary Token', ['Primary Token', result.code], null, null, null);
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 callback(null, errorObj);
1230
+ return reject(errorObj);
1237
1231
  }
1238
1232
 
1239
- const exName = tokenSchema.responseSchema.properties.token.external_name.toLowerCase();
1240
- const headKeys = Object.keys(result.headers);
1241
- let fullToken = null;
1242
- let setCookie = null;
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
- // go through and find the token
1245
- for (let h = 0; h < headKeys.length; h += 1) {
1246
- if (headKeys[h].toLowerCase() === exName) {
1247
- fullToken = result.headers[headKeys[h]];
1248
- currResult.token = result.headers[headKeys[h]];
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
- if (headKeys[h].toLowerCase() === 'set-cookie') {
1251
- setCookie = result.headers[headKeys[h]];
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
- // if the token is in the requestToken
1256
- if (exName === 'requestcookie' && result.requestCookie) {
1257
- currResult.token = result.requestCookie;
1258
- }
1266
+ // if the token is in the requestToken
1267
+ if (exName === 'requestcookie' && result.requestCookie) {
1268
+ currResult.token = result.requestCookie;
1269
+ }
1259
1270
 
1260
- // if the exName field is an array
1261
- if (exName === 'set-cookie' && fullToken && Array.isArray(fullToken)) {
1262
- currResult.token = fullToken[0];
1263
- for (let ex = 1; ex < fullToken.length; ex += 1) {
1264
- currResult.token += `; ${fullToken[ex]}`;
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
- // if the token has been returned in the cookie
1269
- if (exName.substring(0, 11) === 'set-cookie.') {
1270
- const fname = exName.substring(11).toLowerCase();
1271
- let thisCook = null;
1272
-
1273
- // if the cookie is an array - usual case
1274
- if (setCookie && Array.isArray(setCookie)) {
1275
- // go through the array looking for the defined token field
1276
- for (let sc = 0; sc < setCookie.length; sc += 1) {
1277
- // parses the cookie into an object
1278
- thisCook = cookieHandler.parse(setCookie[sc]);
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
- // process second token from header
1311
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1312
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'HEADER') {
1313
- if (!tokenSchema.responseSchema.properties.tokenp2.external_name) {
1314
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Get Secondary Token', ['Secondary Token', result.code], null, null, null);
1315
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1316
- return callback(null, errorObj);
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
- const exName = tokenSchema.responseSchema.properties.tokenp2.external_name.toLowerCase();
1320
- const headKeys = Object.keys(result.headers);
1321
- let fullToken = null;
1322
- let setCookie = null;
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
- // go through and find the token
1325
- for (let h = 0; h < headKeys.length; h += 1) {
1326
- if (headKeys[h].toLowerCase() === exName) {
1327
- fullToken = result.headers[headKeys[h]];
1328
- currResult.tokenp2 = result.headers[headKeys[h]];
1329
- }
1330
- if (headKeys[h].toLowerCase() === 'set-cookie') {
1331
- setCookie = result.headers[headKeys[h]];
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
- // if the token is in the requestToken
1336
- if (exName === 'requestcookie' && result.requestCookie) {
1337
- currResult.token = result.requestCookie;
1338
- }
1346
+ // if the token is in the requestToken
1347
+ if (exName === 'requestcookie' && result.requestCookie) {
1348
+ currResult.token = result.requestCookie;
1349
+ }
1339
1350
 
1340
- // if the exName field is an array
1341
- if (exName === 'set-cookie' && fullToken && Array.isArray(fullToken)) {
1342
- currResult.tokenp2 = fullToken[0];
1343
- for (let ex = 1; ex < fullToken.length; ex += 1) {
1344
- currResult.tokenp2 += `; ${fullToken[ex]}`;
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
- // if the token has been returned in the cookie
1349
- if (exName.substring(0, 11) === 'set-cookie.') {
1350
- const fname = exName.substring(11).toLowerCase();
1351
- let thisCook = null;
1352
-
1353
- // if the cookie is an array - usual case
1354
- if (setCookie && Array.isArray(setCookie)) {
1355
- // go through the array looking for the defined token field
1356
- for (let sc = 0; sc < setCookie.length; sc += 1) {
1357
- // parses the cookie into an object
1358
- thisCook = cookieHandler.parse(setCookie[sc]);
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
- // process the body
1391
- // if response is just a string
1392
- if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'PLAIN') {
1393
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1394
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
1395
- currResult.token = result.response;
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
- // if we got a stringified string - we can remove the double quotes wrapping it
1398
- if (currResult.token.substring(0, 1) === '"' && currResult.token.substring(-1, 1) === '"') {
1399
- currResult.token = currResult.token.substring(1, currResult.token.length - 1);
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
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1403
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
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
- // if we got a stringified string - we can remove the double quotes wrapping it
1407
- if (currResult.token.substring(0, 1) === '"' && currResult.token.substring(-1, 1) === '"') {
1408
- currResult.token = currResult.token.substring(1, currResult.token.length - 1);
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
- // return the string as there is no other processing needed
1413
- return callback(currResult);
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
- // return the xml as there is no other processing needed
1426
- return callback(currResult);
1427
- }
1436
+ // return the xml as there is no other processing needed
1437
+ return resolve(currResult);
1438
+ }
1428
1439
 
1429
- // if response can be put into a JSON object
1430
- let tempResult = null;
1431
- if (result.response) {
1432
- if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'XML2JSON') {
1433
- try {
1434
- const parser = new xml2js.Parser({ explicitArray: false, attrkey: '_attr' });
1435
- parser.parseString(result.response, (error, presult) => {
1436
- if (error) {
1437
- log.warn(`${origin}: Unable to parse xml to json ${error}`);
1438
- return callback(parser.toJson(presult));
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
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1449
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
1450
- currResult.tokenp2 = result.response;
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
- if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'URLENCODE') {
1455
- tempResult = querystring.parse(result.response.trim());
1456
- } else {
1457
- try {
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
- // at this point if there is nothing in tempResult nothing further to do
1466
- if (!tempResult) {
1467
- return callback(currResult);
1468
- }
1481
+ // need to see if there is a response key
1482
+ if (tokenSchema.responseObjects) {
1483
+ let tKey = null;
1469
1484
 
1470
- // need to see if there is a response key
1471
- if (tokenSchema.responseObjects) {
1472
- let tKey = null;
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
- // it should be an array - then take the first element of array
1475
- if (Array.isArray(tokenSchema.responseObjects)) {
1476
- if (tokenSchema.responseObjects[0].key) {
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
- // if we found a key, use it
1484
- if (tKey) {
1485
- tempResult = jsonQuery(tKey, { data: tempResult }).value;
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
- // the token should not be an array so if it is, return the 0 item.
1490
- if (Array.isArray(tempResult)) {
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
- // if what we got back is an array, just return the first element
1498
- // should only have one token!!!
1499
- if (translated && Array.isArray(translated)) {
1500
- translated = translated[0];
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
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1504
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
1505
- currResult.token = translated.token;
1506
- }
1507
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1508
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
1509
- currResult.tokenp2 = translated.tokenp2;
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
- // return the token that we find in the translated object
1513
- return callback(currResult);
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
- try {
1530
- // Get the entity schema from the file system
1531
- return propUtilInst.getEntitySchema('.system', 'getToken', choosepath, this.dbUtil, (tokenSchema, healthError) => {
1532
- if (healthError || !tokenSchema || Object.keys(tokenSchema).length === 0) {
1533
- log.debug(`${origin}: Using adapter properties for token information`);
1534
- tokenSchema = null;
1535
- } else {
1536
- log.debug(`${origin}: Using action and schema for token information`);
1537
- }
1538
-
1539
- // prepare the additional headers we received
1540
- let thisAHdata = null;
1541
-
1542
- if (tokenSchema) {
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
- // set up the right credentials - passed in overrides default
1550
- let useUser = username;
1551
- let usePass = password;
1564
+ // prepare the additional headers we received
1565
+ let thisAHdata = null;
1552
1566
 
1553
- if (callProperties && callProperties.authentication && callProperties.authentication.username) {
1554
- useUser = callProperties.authentication.username;
1555
- }
1556
- if (callProperties && callProperties.authentication && callProperties.authentication.password) {
1557
- usePass = callProperties.authentication.password;
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
- // if no header data passed in create empty - will add data below
1561
- if (!thisAHdata) {
1562
- thisAHdata = {};
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
- for (let h = 0; h < hKeys.length; h += 1) {
1567
- let tempStr = thisAHdata[hKeys[h]];
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
- // replace username variable
1570
- if (tempStr.indexOf('{username}') >= 0) {
1571
- tempStr = tempStr.replace('{username}', useUser);
1572
- }
1573
- // replace password variable
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
- // handle any base64 encoding required on the authStr
1580
- if (thisAHdata[hKeys[h]].indexOf('{b64}') >= 0) {
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
- // if start but no end - return an error
1586
- if (sIndex >= 0 && eIndex < sIndex + 5) {
1587
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Encode', [thisAHdata[hKeys[h]]], null, null, null);
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
- // get the string to be encoded
1593
- const bufString = thisAHdata[hKeys[h]].substring(sIndex + 5, eIndex);
1617
+ // get the string to be encoded
1618
+ const bufString = thisAHdata[hKeys[h]].substring(sIndex + 5, eIndex);
1594
1619
 
1595
- // encode the string
1596
- const encString = Buffer.from(bufString).toString('base64');
1597
- let tempAuthStr = '';
1620
+ // encode the string
1621
+ const encString = Buffer.from(bufString).toString('base64');
1622
+ let tempAuthStr = '';
1598
1623
 
1599
- // build the new auth field with the encoded string
1600
- if (sIndex > 0) {
1601
- // add the start of the string that did not need encoding
1602
- tempAuthStr = thisAHdata[hKeys[h]].substring(0, sIndex);
1603
- }
1604
- // add the encoded string
1605
- tempAuthStr += encString;
1606
- if (eIndex + 5 < thisAHdata[hKeys[h]].length) {
1607
- // add the end of the string that did not need encoding
1608
- tempAuthStr += thisAHdata[hKeys[h]].substring(eIndex + 6);
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
- // put the temp string into the auth string we will add to the request
1612
- thisAHdata[hKeys[h]] = tempAuthStr;
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
- // set the Content Type headers based on the type of request data for the call
1618
- if (thisAHdata['Content-Type'] === undefined || thisAHdata['Content-Type'] === null) {
1619
- if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'PLAIN') {
1620
- // add the Plain headers if they were not set already
1621
- thisAHdata['Content-Type'] = 'text/plain';
1622
- } else if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'XML') {
1623
- // add the XML headers if they were not set already
1624
- thisAHdata['Content-Type'] = 'application/xml';
1625
- } else if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLENCODE') {
1626
- // add the URLENCODE headers if they were not set already
1627
- thisAHdata['Content-Type'] = 'application/x-www-form-urlencoded';
1628
- } else {
1629
- // add the JSON headers if they were not set already
1630
- thisAHdata['Content-Type'] = 'application/json';
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
- // set the Accept headers based on the type of response data for the call
1634
- if (thisAHdata.Accept === undefined || thisAHdata.Accept === null) {
1635
- if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'PLAIN') {
1636
- // add the Plain headers if they were not set already
1637
- thisAHdata.Accept = 'text/plain';
1638
- } else if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'XML') {
1639
- // add the XML headers if they were not set already
1640
- thisAHdata.Accept = 'application/xml';
1641
- } else if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'URLENCODE') {
1642
- // add the URLENCODE headers if they were not set already
1643
- thisAHdata.Accept = 'application/x-www-form-urlencoded';
1644
- } else {
1645
- // add the JSON headers if they were not set already
1646
- thisAHdata.Accept = 'application/json';
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
- // specific token properties override everything (Single Sign On System)
1675
- if (sso && sso.host) {
1676
- options.hostname = sso.host;
1677
- }
1678
- if (sso && sso.port) {
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
- // If there is a token schema, need to take the data from there
1705
- if (tokenSchema) {
1706
- options.path = tokenSchema.entitypath;
1707
- options.method = tokenSchema.method;
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
- // if the path has a base path parameter in it, need to replace it
1711
- let bpathStr = '{base_path}';
1712
- if (options.path.indexOf(bpathStr) >= 0) {
1713
- // be able to support this if the base path has a slash before it or not
1714
- if (options.path.indexOf('/{base_path}') >= 0) {
1715
- bpathStr = '/{base_path}';
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
- // replace with base path if we have one, otherwise remove base path
1719
- if (callProperties && callProperties.base_path) {
1720
- // if no leading /, insert one
1721
- if (callProperties.base_path.indexOf('/') !== 0) {
1722
- options.path = options.path.replace(bpathStr, `/${callProperties.base_path}`);
1723
- } else {
1724
- options.path = options.path.replace(bpathStr, callProperties.base_path);
1725
- }
1726
- } else if (basepath) {
1727
- // if no leading /, insert one
1728
- if (basepath.indexOf('/') !== 0) {
1729
- options.path = options.path.replace(bpathStr, `/${basepath}`);
1730
- } else {
1731
- options.path = options.path.replace(bpathStr, basepath);
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
- // if the path has a version parameter in it, need to replace it
1739
- let versStr = '{version}';
1740
- if (options.path.indexOf(versStr) >= 0) {
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
- // replace with version if we have one, otherwise remove version
1747
- if (callProperties && callProperties.version) {
1748
- options.path = options.path.replace(versStr, `/${encodeURIComponent(callProperties.version)}`);
1749
- } else if (version) {
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
- // if there are URI path variables that have been provided, need to add
1757
- // them to the path
1758
- if (reqBody && reqBody.uriPathVars && reqBody.uriPathVars.length > 0) {
1759
- for (let p = 0; p < reqBody.uriPathVars.length; p += 1) {
1760
- const vnum = p + 1;
1761
- const holder = `pathv${vnum.toString()}`;
1762
- const hindex = options.path.indexOf(holder);
1763
-
1764
- // if path variable is in the url, replace it!!!
1765
- if (hindex >= 0 && reqBody.uriPathVars[p] !== null && reqBody.uriPathVars[p] !== '') {
1766
- // with the provided id
1767
- let idString = '';
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
- // otherwise add / to start
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
- // replace the id in url with the id string
1781
- options.path = options.path.replace(`{${holder}}`, idString);
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
- // need to remove all of the remaining path holders from the URI
1787
- while (options.path.indexOf('{pathv') >= 0) {
1788
- let sIndex = options.path.indexOf('{pathv');
1789
- const eIndex = options.path.indexOf('}', sIndex);
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
- // if there is a / before the {pathv} need to remove it
1792
- if (options.path[sIndex - 1] === '/' || options.path[sIndex - 1] === ':') {
1793
- sIndex -= 1;
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
- if (sIndex > 0) {
1797
- // add the start of the path
1798
- let tempStr = options.path.substring(0, sIndex);
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 (eIndex < options.path.length) {
1801
- // add the end of the path
1802
- tempStr += options.path.substring(eIndex + 1);
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
- options.path = tempStr;
1806
- } else if (eIndex > 0 && eIndex < options.path.length) {
1807
- // add the end of the path
1808
- options.path = options.path.substring(eIndex + 1);
1809
- } else {
1810
- // should not get here - there is some issue in the uripath - missing
1811
- // an end or the path is just {pathv#}
1812
- // add the specific pieces of the error object
1813
- const errorObj = this.transUtil.formatErrorObject(origin, 'Invalid Action File', ['missing entity path', '.system/getToken'], null, null, null);
1814
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1815
- return callback(null, errorObj);
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
- // only add global options if there are global options to add
1820
- if (globalRequest && globalRequest.uriOptions
1821
- && Object.keys(globalRequest.uriOptions).length > 0) {
1822
- const optionString = querystring.stringify(globalRequest.uriOptions);
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
- // if no query paramters yet - start with ?
1825
- if (options.path.indexOf('?') < 0) {
1826
- options.path += `?${optionString}`;
1827
- } else {
1828
- // if already have query parameters, add on to end
1829
- options.path += `&${optionString}`;
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
- // remove the path vars from the reqBody
1834
- const actReqBody = Object.assign({}, reqBody);
1835
- if (actReqBody && actReqBody.uriPathVars) {
1836
- delete actReqBody.uriPathVars;
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
- // if ssl enabled add the options for ssl
1840
- if (callProperties && callProperties.ssl && Object.hasOwnProperty.call(callProperties.ssl, 'enabled')) {
1841
- if (callProperties.ssl.enabled) {
1842
- if (callProperties.ssl.accept_invalid_cert) {
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(callProperties.ssl.ca_file)];
1899
+ options.ca = [fs.readFileSync(sslCAFile)];
1850
1900
  } catch (e) {
1851
- const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [callProperties.ssl.ca_file], null, null, null);
1901
+ const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslCAFile], null, null, null);
1852
1902
  log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1853
- return callback(null, errorObj);
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 (callProperties.ssl.ciphers) {
1858
- options.ciphers = callProperties.ssl.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
- // if there is a cert file, try to read in a cert file in the options
1881
- if (sslCertFile) {
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
- // if there is a key file, try to read in a key file in the options
1891
- if (sslKeyFile) {
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
- if (sslCiphers) {
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
- log.info(`${origin}: Connector SSL connections enabled`);
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
- const reqData = {};
1913
- let bodyString = null;
1914
-
1915
- // if we have been passed a schema and the Authorization is in a header
1916
- // COMMENTED OUT AND HANDLED IN IF BELOW - take stuff out of body on line 1930
1917
- // if (tokenSchema && tokenSchema.headers && tokenSchema.headers.Authorization) {
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
- // if this is a get, need to put the password on the url
1931
- if (options.path.indexOf('/{password}') >= 0) {
1932
- options.path = options.path.replace('/{password}', usePass);
1933
- } else {
1934
- options.path = options.path.replace('{password}', usePass);
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
- // if this is not a get, need to add the info to the request
1938
- if (options.method !== 'GET') {
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
- // if there is body data to add to the token request body
1963
- creds = transUtilInst.mergeObjects(actReqBody, creds);
1999
+ if (globalRequest) {
2000
+ creds = transUtilInst.mergeObjects(creds, globalRequest.authData);
2001
+ }
1964
2002
 
1965
- if (globalRequest) {
1966
- creds = transUtilInst.mergeObjects(creds, globalRequest.authData);
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
- // if there is body data to add to the token request body
1970
- if (actReqBody) {
1971
- const bodyKey = Object.keys(actReqBody);
2007
+ for (let k = 0; k < bodyKey.length; k += 1) {
2008
+ creds[bodyKey[k]] = actReqBody[bodyKey[k]];
2009
+ }
2010
+ }
1972
2011
 
1973
- for (let k = 0; k < bodyKey.length; k += 1) {
1974
- creds[bodyKey[k]] = actReqBody[bodyKey[k]];
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
- if (tokenSchema.headers && tokenSchema.headers.Authorization) {
1979
- // remove the username and password from the creds
1980
- delete creds.username;
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
- // map the data we received to an Entity - will get back the defaults
1985
- const tokenEntity = transUtilInst.mapToOutboundEntity(creds, tokenSchema.requestSchema);
1986
- bodyString = tokenEntity;
1987
-
1988
- // if it is JSON or URLENCODE need to put body into right format
1989
- if (!tokenSchema.requestDatatype || tokenSchema.requestDatatype.toUpperCase() === 'JSON' || tokenSchema.requestDatatype.toUpperCase() === 'FORM') {
1990
- bodyString = JSON.stringify(tokenEntity);
1991
- } else if (tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLENCODE') {
1992
- bodyString = querystring.stringify(tokenEntity);
1993
- } else if (tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLQUERY') {
1994
- // if the datatype is URLQUERY need to put into the query on the request
1995
- if (authQueryEncode != null) {
1996
- if (authQueryEncode === true) {
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
- } else if (encodeUri === true) {
2013
- bodyString = querystring.stringify(tokenEntity);
2014
- } else {
2015
- bodyString = '';
2016
- // if not encoding we need to build
2017
- const qkeys = Object.keys(tokenEntity);
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
- // append to the path
2030
- if (options.path.indexOf('?') < 0) {
2031
- options.path = `${options.path}?${bodyString}`;
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
- // if there is a body, set the content length of the body and add it to
2039
- // the header
2040
- if (Object.keys(tokenEntity).length > 0 || tokenSchema.sendEmpty) {
2041
- options.headers['Content-length'] = Buffer.byteLength(bodyString);
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
- // request the token
2045
- return getToken(reqPath, options, tokenSchema, bodyString, callProperties, callback);
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
- // since not a get call, convert reqData to a string and add length
2054
- bodyString = JSON.stringify(reqData);
2055
- options.headers['Content-length'] = Buffer.byteLength(bodyString);
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
- // request the token
2059
- return getToken(reqPath, options, tokenSchema, bodyString, callProperties, callback);
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
  }