@itentialopensource/adapter-utils 4.48.6 → 4.48.8

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;
@@ -117,6 +118,8 @@ let cacheHHead = null;
117
118
  let cacheHSchema = null;
118
119
  let cacheHPay = null;
119
120
 
121
+ const mfaStepsResults = []; // keeps requested result for each step
122
+
120
123
  /* CONNECTOR ENGINE INTERNAL FUNCTIONS */
121
124
  /** Wait for adapter-mongo to be available.
122
125
  * @summary adapter may load before adapter-mongo but it requires UPDATE: test if dbUtil object can connect.
@@ -1084,7 +1087,6 @@ function findExpireInResult(result) {
1084
1087
  const origin = `${id}-connectorRest-findExpireInResult`;
1085
1088
  log.trace(origin);
1086
1089
  let expire = null;
1087
-
1088
1090
  if (!result) {
1089
1091
  return expire;
1090
1092
  }
@@ -1117,887 +1119,932 @@ function findExpireInResult(result) {
1117
1119
  * INTERNAL FUNCTION: makes the request and processes the response
1118
1120
  * for the request to get the token
1119
1121
  */
1120
- function getToken(reqPath, options, tokenSchema, bodyString, callProperties, callback) {
1122
+ async function getToken(reqPath, options, tokenSchema, bodyString, callProperties, callback) {
1121
1123
  const origin = `${id}-connectorRest-getToken`;
1122
1124
  log.trace(origin);
1123
1125
 
1124
- try {
1125
- // no need for orig path since we handled the stub case
1126
- const request = {
1127
- header: options,
1128
- body: bodyString,
1129
- origPath: tokenSchema.entitypath
1130
- };
1131
-
1132
- // set stub if that is the mode we are in
1133
- let useStub = false;
1134
- if (callProperties && Object.hasOwnProperty.call(callProperties, 'stub')) {
1135
- useStub = callProperties.stub;
1136
- } else if (stub) {
1137
- useStub = stub;
1138
- }
1139
-
1140
- // if there is a mock result, return that
1141
- if (useStub && tokenSchema) {
1142
- // get the data from the mock data file
1143
- const tokenResp = returnStub(request, tokenSchema, callProperties);
1144
-
1145
- // if the request failed, return the error
1146
- if (tokenResp.code < 200 || tokenResp.code > 299) {
1147
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', tokenResp.code], null, null, null);
1148
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1149
- return callback(null, errorObj);
1150
- }
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
+ };
1151
1134
 
1152
- if (!tokenSchema.responseDatatype || tokenSchema.responseDatatype === 'JSON') {
1153
- 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;
1154
1141
  }
1155
- log.debug(`${origin}: ${JSON.stringify(tokenResp.response)}`);
1156
1142
 
1157
- // return the token from the token schema
1158
- let translated = null;
1159
- if (typeof tokenResp.response !== 'string') {
1160
- translated = transUtilInst.mapFromOutboundEntity(tokenResp.response, tokenSchema.responseSchema);
1161
- } else {
1162
- translated = tokenResp.response;
1163
- }
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);
1164
1147
 
1165
- // since this is a stub, make sure we have what we need
1166
- if (!translated.token) {
1167
- translated.token = 'garbagetoken';
1168
- }
1169
- if (!translated.tokenp2) {
1170
- translated.tokenp2 = 'garbagetoken';
1171
- }
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
+ }
1172
1154
 
1173
- // if what we got back is an array, just return the first element
1174
- // should only have one token!!!
1175
- if (translated && Array.isArray(translated)) {
1176
- translated[0].front = tokenSchema.responseSchema.properties.token.front;
1177
- translated[0].end = tokenSchema.responseSchema.properties.token.end;
1178
- return callback(translated[0]);
1179
- }
1155
+ if (!tokenSchema.responseDatatype || tokenSchema.responseDatatype === 'JSON') {
1156
+ tokenResp.response = JSON.parse(tokenResp.response);
1157
+ }
1158
+ log.debug(`${origin}: ${JSON.stringify(tokenResp.response)}`);
1180
1159
 
1181
- // return the token that we find in the translated object
1182
- translated.front = tokenSchema.responseSchema.properties.token.front;
1183
- translated.end = tokenSchema.responseSchema.properties.token.end;
1184
- return callback(translated);
1185
- }
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
+ }
1186
1167
 
1187
- if (useStub || reqPath === tokenPath || (tokenSchema && reqPath === tokenSchema.entitypath)) {
1188
- // do not make the call to return a token if the request is actually
1189
- // to get a token. Getting a token to get a token -- that should go
1190
- // direct to make request
1191
- return callback({ token: 'faketoken', tokenp2: 'faketoken' });
1192
- }
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
+ }
1193
1175
 
1194
- 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
+ }
1195
1183
 
1196
- // request the token
1197
- return makeRequest(request, tokenSchema, callProperties, null, 0, (result, merror) => {
1198
- if (merror) {
1199
- 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);
1200
1188
  }
1201
1189
 
1202
- // if the request is a redirect, try to pull token but log a warning
1203
- let handleTokenRedirect = false;
1204
- if (result.code >= 300 && result.code <= 308 && numRedirects === 0) {
1205
- log.warn(`${origin}: Going to attempt to get token from redirect message!`);
1206
- 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' });
1207
1195
  }
1208
1196
 
1209
- // if the request failed, return the error
1210
- if ((result.code < 200 || result.code > 299) && !handleTokenRedirect) {
1211
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', result.code], null, null, null);
1212
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1213
- return callback(null, errorObj);
1214
- }
1197
+ log.debug(`${origin}: OPTIONS: ${JSON.stringify(options)}`);
1215
1198
 
1216
- if (!tokenSchema) {
1217
- // if no token schema, can not determine what to return
1218
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Authenticate', ['Token', result.code], null, null, null);
1219
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1220
- return callback(null, errorObj);
1221
- }
1199
+ // request the token
1200
+ return makeRequest(request, tokenSchema, callProperties, null, 0, (result, merror) => {
1201
+ if (merror) {
1202
+ return reject(merror);
1203
+ }
1222
1204
 
1223
- // parse the token out of the result
1224
- const currResult = {
1225
- token: null,
1226
- tokenp2: null,
1227
- front: tokenSchema.responseSchema.properties.token.front,
1228
- end: tokenSchema.responseSchema.properties.token.end
1229
- };
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
+ }
1230
1211
 
1231
- // process primary token from header
1232
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1233
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'HEADER') {
1234
- if (!tokenSchema.responseSchema.properties.token.external_name) {
1235
- 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);
1236
1229
  log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1237
- return callback(null, errorObj);
1230
+ return reject(errorObj);
1238
1231
  }
1239
1232
 
1240
- const exName = tokenSchema.responseSchema.properties.token.external_name.toLowerCase();
1241
- const headKeys = Object.keys(result.headers);
1242
- let fullToken = null;
1243
- 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
+ };
1244
1240
 
1245
- // go through and find the token
1246
- for (let h = 0; h < headKeys.length; h += 1) {
1247
- if (headKeys[h].toLowerCase() === exName) {
1248
- fullToken = result.headers[headKeys[h]];
1249
- 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);
1250
1248
  }
1251
- if (headKeys[h].toLowerCase() === 'set-cookie') {
1252
- 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
+ }
1253
1264
  }
1254
- }
1255
1265
 
1256
- // if the token is in the requestToken
1257
- if (exName === 'requestcookie' && result.requestCookie) {
1258
- currResult.token = result.requestCookie;
1259
- }
1266
+ // if the token is in the requestToken
1267
+ if (exName === 'requestcookie' && result.requestCookie) {
1268
+ currResult.token = result.requestCookie;
1269
+ }
1260
1270
 
1261
- // if the exName field is an array
1262
- if (exName === 'set-cookie' && fullToken && Array.isArray(fullToken)) {
1263
- currResult.token = fullToken[0];
1264
- for (let ex = 1; ex < fullToken.length; ex += 1) {
1265
- 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
+ }
1266
1277
  }
1267
- }
1268
1278
 
1269
- // if the token has been returned in the cookie
1270
- if (exName.substring(0, 11) === 'set-cookie.') {
1271
- const fname = exName.substring(11).toLowerCase();
1272
- let thisCook = null;
1273
-
1274
- // if the cookie is an array - usual case
1275
- if (setCookie && Array.isArray(setCookie)) {
1276
- // go through the array looking for the defined token field
1277
- for (let sc = 0; sc < setCookie.length; sc += 1) {
1278
- // parses the cookie into an object
1279
- 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);
1280
1308
  const cookKeys = Object.keys(thisCook);
1281
- let set = false;
1282
1309
 
1283
1310
  // go through the cookie to find the token
1284
1311
  for (let h = 0; h < cookKeys.length; h += 1) {
1285
1312
  if (cookKeys[h].toLowerCase() === fname) {
1286
1313
  currResult.token = thisCook[cookKeys[h]];
1287
- set = true;
1288
1314
  break;
1289
1315
  }
1290
1316
  }
1291
- if (set) {
1292
- break;
1293
- }
1294
- }
1295
- } else if (setCookie) {
1296
- // if the cookie is just one string, parse into an object
1297
- thisCook = cookieHandler.parse(setCookie);
1298
- const cookKeys = Object.keys(thisCook);
1299
-
1300
- // go through the cookie to find the token
1301
- for (let h = 0; h < cookKeys.length; h += 1) {
1302
- if (cookKeys[h].toLowerCase() === fname) {
1303
- currResult.token = thisCook[cookKeys[h]];
1304
- break;
1305
- }
1306
1317
  }
1307
1318
  }
1308
1319
  }
1309
- }
1310
1320
 
1311
- // process second token from header
1312
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1313
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'HEADER') {
1314
- if (!tokenSchema.responseSchema.properties.tokenp2.external_name) {
1315
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Get Secondary Token', ['Secondary Token', result.code], null, null, null);
1316
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1317
- return callback(null, errorObj);
1318
- }
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
+ }
1319
1329
 
1320
- const exName = tokenSchema.responseSchema.properties.tokenp2.external_name.toLowerCase();
1321
- const headKeys = Object.keys(result.headers);
1322
- let fullToken = null;
1323
- 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;
1324
1334
 
1325
- // go through and find the token
1326
- for (let h = 0; h < headKeys.length; h += 1) {
1327
- if (headKeys[h].toLowerCase() === exName) {
1328
- fullToken = result.headers[headKeys[h]];
1329
- currResult.tokenp2 = result.headers[headKeys[h]];
1330
- }
1331
- if (headKeys[h].toLowerCase() === 'set-cookie') {
1332
- 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
+ }
1333
1344
  }
1334
- }
1335
1345
 
1336
- // if the token is in the requestToken
1337
- if (exName === 'requestcookie' && result.requestCookie) {
1338
- currResult.token = result.requestCookie;
1339
- }
1346
+ // if the token is in the requestToken
1347
+ if (exName === 'requestcookie' && result.requestCookie) {
1348
+ currResult.token = result.requestCookie;
1349
+ }
1340
1350
 
1341
- // if the exName field is an array
1342
- if (exName === 'set-cookie' && fullToken && Array.isArray(fullToken)) {
1343
- currResult.tokenp2 = fullToken[0];
1344
- for (let ex = 1; ex < fullToken.length; ex += 1) {
1345
- 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
+ }
1346
1357
  }
1347
- }
1348
1358
 
1349
- // if the token has been returned in the cookie
1350
- if (exName.substring(0, 11) === 'set-cookie.') {
1351
- const fname = exName.substring(11).toLowerCase();
1352
- let thisCook = null;
1353
-
1354
- // if the cookie is an array - usual case
1355
- if (setCookie && Array.isArray(setCookie)) {
1356
- // go through the array looking for the defined token field
1357
- for (let sc = 0; sc < setCookie.length; sc += 1) {
1358
- // parses the cookie into an object
1359
- 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);
1360
1388
  const cookKeys = Object.keys(thisCook);
1361
- let set = false;
1362
1389
 
1363
1390
  // go through the cookie to find the token
1364
1391
  for (let h = 0; h < cookKeys.length; h += 1) {
1365
1392
  if (cookKeys[h].toLowerCase() === fname) {
1366
1393
  currResult.tokenp2 = thisCook[cookKeys[h]];
1367
- set = true;
1368
1394
  break;
1369
1395
  }
1370
1396
  }
1371
- if (set) {
1372
- break;
1373
- }
1374
- }
1375
- } else if (setCookie) {
1376
- // if the cookie is just one string, parse into an object
1377
- thisCook = cookieHandler.parse(setCookie);
1378
- const cookKeys = Object.keys(thisCook);
1379
-
1380
- // go through the cookie to find the token
1381
- for (let h = 0; h < cookKeys.length; h += 1) {
1382
- if (cookKeys[h].toLowerCase() === fname) {
1383
- currResult.tokenp2 = thisCook[cookKeys[h]];
1384
- break;
1385
- }
1386
1397
  }
1387
1398
  }
1388
1399
  }
1389
- }
1390
1400
 
1391
- // process the body
1392
- // if response is just a string
1393
- if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'PLAIN') {
1394
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1395
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
1396
- 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;
1397
1407
 
1398
- // if we got a stringified string - we can remove the double quotes wrapping it
1399
- if (currResult.token.substring(0, 1) === '"' && currResult.token.substring(-1, 1) === '"') {
1400
- 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
+ }
1401
1412
  }
1402
- }
1403
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1404
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
1405
- 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;
1406
1416
 
1407
- // if we got a stringified string - we can remove the double quotes wrapping it
1408
- if (currResult.token.substring(0, 1) === '"' && currResult.token.substring(-1, 1) === '"') {
1409
- 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
+ }
1410
1421
  }
1411
- }
1412
1422
 
1413
- // return the string as there is no other processing needed
1414
- return callback(currResult);
1415
- }
1416
- if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'XML') {
1417
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1418
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
1419
- currResult.token = result.response;
1420
- }
1421
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1422
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
1423
- currResult.tokenp2 = result.response;
1423
+ // return the string as there is no other processing needed
1424
+ return resolve(currResult);
1424
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
+ }
1425
1435
 
1426
- // return the xml as there is no other processing needed
1427
- return callback(currResult);
1428
- }
1436
+ // return the xml as there is no other processing needed
1437
+ return resolve(currResult);
1438
+ }
1429
1439
 
1430
- // if response can be put into a JSON object
1431
- let tempResult = null;
1432
- if (result.response) {
1433
- if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'XML2JSON') {
1434
- try {
1435
- const parser = new xml2js.Parser({ explicitArray: false, attrkey: '_attr' });
1436
- parser.parseString(result.response, (error, presult) => {
1437
- if (error) {
1438
- log.warn(`${origin}: Unable to parse xml to json ${error}`);
1439
- 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;
1440
1462
  }
1441
- tempResult = presult;
1442
- });
1443
- } catch (ex) {
1444
- log.warn(`${origin}: Unable to get json from xml ${ex}`);
1445
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1446
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
1447
- currResult.token = result.response;
1448
1463
  }
1449
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1450
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
1451
- 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);
1452
1472
  }
1453
1473
  }
1454
1474
  }
1455
- if (Object.hasOwnProperty.call(tokenSchema, 'responseDatatype') && tokenSchema.responseDatatype.toUpperCase() === 'URLENCODE') {
1456
- tempResult = querystring.parse(result.response.trim());
1457
- } else {
1458
- try {
1459
- tempResult = JSON.parse(result.response.trim());
1460
- } catch (exc) {
1461
- log.warn(exc);
1462
- }
1475
+
1476
+ // at this point if there is nothing in tempResult nothing further to do
1477
+ if (!tempResult) {
1478
+ return resolve(currResult);
1463
1479
  }
1464
- }
1465
1480
 
1466
- // at this point if there is nothing in tempResult nothing further to do
1467
- if (!tempResult) {
1468
- return callback(currResult);
1469
- }
1481
+ // need to see if there is a response key
1482
+ if (tokenSchema.responseObjects) {
1483
+ let tKey = null;
1470
1484
 
1471
- // need to see if there is a response key
1472
- if (tokenSchema.responseObjects) {
1473
- 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
+ }
1474
1493
 
1475
- // it should be an array - then take the first element of array
1476
- if (Array.isArray(tokenSchema.responseObjects)) {
1477
- if (tokenSchema.responseObjects[0].key) {
1478
- tKey = tokenSchema.responseObjects[0].key;
1494
+ // if we found a key, use it
1495
+ if (tKey) {
1496
+ tempResult = jsonQuery(tKey, { data: tempResult }).value;
1479
1497
  }
1480
- } else if (tokenSchema.responseObjects.key) {
1481
- tKey = tokenSchema.responseObjects.key;
1482
1498
  }
1483
1499
 
1484
- // if we found a key, use it
1485
- if (tKey) {
1486
- 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];
1487
1503
  }
1488
- }
1489
-
1490
- // the token should not be an array so if it is, return the 0 item.
1491
- if (Array.isArray(tempResult)) {
1492
- tempResult = tempResult[0];
1493
- }
1494
1504
 
1495
- // return the token from the token schema
1496
- let translated = transUtilInst.mapFromOutboundEntity(tempResult, tokenSchema.responseSchema);
1505
+ // return the token from the token schema
1506
+ let translated = transUtilInst.mapFromOutboundEntity(tempResult, tokenSchema.responseSchema);
1497
1507
 
1498
- // if what we got back is an array, just return the first element
1499
- // should only have one token!!!
1500
- if (translated && Array.isArray(translated)) {
1501
- translated = translated[0];
1502
- }
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
+ }
1503
1513
 
1504
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.token
1505
- && tokenSchema.responseSchema.properties.token.placement && tokenSchema.responseSchema.properties.token.placement.toUpperCase() === 'BODY') {
1506
- currResult.token = translated.token;
1507
- }
1508
- if (tokenSchema.responseSchema && tokenSchema.responseSchema.properties && tokenSchema.responseSchema.properties.tokenp2
1509
- && tokenSchema.responseSchema.properties.tokenp2.placement && tokenSchema.responseSchema.properties.tokenp2.placement.toUpperCase() === 'BODY') {
1510
- currResult.tokenp2 = translated.tokenp2;
1511
- }
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
+ });
1512
1535
 
1513
- // return the token that we find in the translated object
1514
- return callback(currResult);
1515
- });
1516
- } catch (e) {
1517
- // handle any exception
1518
- const errorObj = transUtilInst.checkAndReturn(e, origin, 'Issue retrieving a token');
1519
- return callback(null, errorObj);
1536
+ if (typeof callback === 'function') {
1537
+ return p.then((result) => callback(result)).catch((error) => callback(null, error));
1520
1538
  }
1539
+ return p;
1521
1540
  }
1522
1541
 
1523
1542
  /*
1524
1543
  * INTERNAL FUNCTION: prepares a request to get a token from the system
1525
1544
  */
1526
- function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
1545
+ async function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
1527
1546
  const origin = `${id}-connectorRest-buildTokenRequest`;
1528
1547
  log.trace(origin);
1529
1548
 
1530
- try {
1531
- // Get the entity schema from the file system
1532
- return propUtilInst.getEntitySchema('.system', 'getToken', choosepath, this.dbUtil, (tokenSchema, healthError) => {
1533
- if (healthError || !tokenSchema || Object.keys(tokenSchema).length === 0) {
1534
- log.debug(`${origin}: Using adapter properties for token information`);
1535
- tokenSchema = null;
1536
- } else {
1537
- log.debug(`${origin}: Using action and schema for token information`);
1538
- }
1539
-
1540
- // prepare the additional headers we received
1541
- let thisAHdata = null;
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
+ }
1542
1563
 
1543
- if (tokenSchema) {
1544
- thisAHdata = transUtilInst.mergeObjects(thisAHdata, tokenSchema.headers);
1545
- }
1546
- if (globalRequest) {
1547
- thisAHdata = transUtilInst.mergeObjects(thisAHdata, globalRequest.addlHeaders);
1548
- }
1564
+ // prepare the additional headers we received
1565
+ let thisAHdata = null;
1549
1566
 
1550
- // set up the right credentials - passed in overrides default
1551
- let useUser = username;
1552
- let usePass = password;
1567
+ if (tokenSchema) {
1568
+ thisAHdata = transUtilInst.mergeObjects(thisAHdata, tokenSchema.headers);
1569
+ }
1570
+ if (globalRequest) {
1571
+ thisAHdata = transUtilInst.mergeObjects(thisAHdata, globalRequest.addlHeaders);
1572
+ }
1553
1573
 
1554
- if (callProperties && callProperties.authentication && callProperties.authentication.username) {
1555
- useUser = callProperties.authentication.username;
1556
- }
1557
- if (callProperties && callProperties.authentication && callProperties.authentication.password) {
1558
- usePass = callProperties.authentication.password;
1559
- }
1574
+ // set up the right credentials - passed in overrides default
1575
+ let useUser = username;
1576
+ let usePass = password;
1560
1577
 
1561
- // if no header data passed in create empty - will add data below
1562
- if (!thisAHdata) {
1563
- thisAHdata = {};
1564
- } else {
1565
- const hKeys = Object.keys(thisAHdata);
1566
-
1567
- for (let h = 0; h < hKeys.length; h += 1) {
1568
- 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
+ }
1569
1584
 
1570
- // replace username variable
1571
- if (tempStr.indexOf('{username}') >= 0) {
1572
- tempStr = tempStr.replace('{username}', useUser);
1573
- }
1574
- // replace password variable
1575
- if (tempStr.indexOf('{password}') >= 0) {
1576
- tempStr = tempStr.replace('{password}', usePass);
1577
- }
1578
- 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);
1579
1590
 
1580
- // handle any base64 encoding required on the authStr
1581
- if (thisAHdata[hKeys[h]].indexOf('{b64}') >= 0) {
1582
- // get the range to be encoded
1583
- const sIndex = thisAHdata[hKeys[h]].indexOf('{b64}');
1584
- const eIndex = thisAHdata[hKeys[h]].indexOf('{/b64}');
1591
+ for (let h = 0; h < hKeys.length; h += 1) {
1592
+ let tempStr = thisAHdata[hKeys[h]];
1585
1593
 
1586
- // if start but no end - return an error
1587
- if (sIndex >= 0 && eIndex < sIndex + 5) {
1588
- const errorObj = transUtilInst.formatErrorObject(origin, 'Unable To Encode', [thisAHdata[hKeys[h]]], null, null, null);
1589
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1590
- return callback(null, errorObj);
1594
+ // replace username variable
1595
+ if (tempStr.indexOf('{username}') >= 0) {
1596
+ tempStr = tempStr.replace('{username}', useUser);
1597
+ }
1598
+ // replace password variable
1599
+ if (tempStr.indexOf('{password}') >= 0) {
1600
+ tempStr = tempStr.replace('{password}', usePass);
1591
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
+ }
1592
1616
 
1593
- // get the string to be encoded
1594
- 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);
1595
1619
 
1596
- // encode the string
1597
- const encString = Buffer.from(bufString).toString('base64');
1598
- let tempAuthStr = '';
1620
+ // encode the string
1621
+ const encString = Buffer.from(bufString).toString('base64');
1622
+ let tempAuthStr = '';
1599
1623
 
1600
- // build the new auth field with the encoded string
1601
- if (sIndex > 0) {
1602
- // add the start of the string that did not need encoding
1603
- tempAuthStr = thisAHdata[hKeys[h]].substring(0, sIndex);
1604
- }
1605
- // add the encoded string
1606
- tempAuthStr += encString;
1607
- if (eIndex + 5 < thisAHdata[hKeys[h]].length) {
1608
- // add the end of the string that did not need encoding
1609
- tempAuthStr += thisAHdata[hKeys[h]].substring(eIndex + 6);
1610
- }
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
+ }
1611
1635
 
1612
- // put the temp string into the auth string we will add to the request
1613
- 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
+ }
1614
1639
  }
1615
1640
  }
1616
- }
1617
1641
 
1618
- // set the Content Type headers based on the type of request data for the call
1619
- if (thisAHdata['Content-Type'] === undefined || thisAHdata['Content-Type'] === null) {
1620
- if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'PLAIN') {
1621
- // add the Plain headers if they were not set already
1622
- thisAHdata['Content-Type'] = 'text/plain';
1623
- } else if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'XML') {
1624
- // add the XML headers if they were not set already
1625
- thisAHdata['Content-Type'] = 'application/xml';
1626
- } else if (tokenSchema && tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLENCODE') {
1627
- // add the URLENCODE headers if they were not set already
1628
- thisAHdata['Content-Type'] = 'application/x-www-form-urlencoded';
1629
- } else {
1630
- // add the JSON headers if they were not set already
1631
- 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
+ }
1632
1657
  }
1633
- }
1634
- // set the Accept headers based on the type of response data for the call
1635
- if (thisAHdata.Accept === undefined || thisAHdata.Accept === null) {
1636
- if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'PLAIN') {
1637
- // add the Plain headers if they were not set already
1638
- thisAHdata.Accept = 'text/plain';
1639
- } else if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'XML') {
1640
- // add the XML headers if they were not set already
1641
- thisAHdata.Accept = 'application/xml';
1642
- } else if (tokenSchema && tokenSchema.responseDatatype && tokenSchema.responseDatatype.toUpperCase() === 'URLENCODE') {
1643
- // add the URLENCODE headers if they were not set already
1644
- thisAHdata.Accept = 'application/x-www-form-urlencoded';
1645
- } else {
1646
- // add the JSON headers if they were not set already
1647
- 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
+ }
1648
1673
  }
1649
- }
1650
-
1651
- if (thisAHdata.Accept === '') {
1652
- delete thisAHdata.Accept;
1653
- }
1654
- if (thisAHdata['Content-Type'] === '') {
1655
- delete thisAHdata['Content-Type'];
1656
- }
1657
-
1658
- // set up the options for the call to get incidents - default is all
1659
- const options = {
1660
- hostname: host,
1661
- port,
1662
- path: tokenPath,
1663
- method: 'POST',
1664
- headers: thisAHdata
1665
- };
1666
-
1667
- // passed in properties override defaults
1668
- if (callProperties && callProperties.host) {
1669
- options.hostname = callProperties.host;
1670
- }
1671
- if (callProperties && callProperties.port) {
1672
- options.port = callProperties.port;
1673
- }
1674
1674
 
1675
- // specific token properties override everything (Single Sign On System)
1676
- if (sso && sso.host) {
1677
- options.hostname = sso.host;
1678
- }
1679
- if (sso && sso.port) {
1680
- options.port = sso.port;
1681
- }
1682
- if (sso && sso.protocol) {
1683
- // need to put protocol in token schema
1684
- if (!tokenSchema) {
1685
- tokenSchema = {
1686
- sso: {
1687
- protocol: sso.protocol
1688
- }
1689
- };
1690
- } else if (tokenSchema && !tokenSchema.sso) {
1691
- tokenSchema.sso = {
1692
- protocol: sso.protocol
1693
- };
1694
- } else if (tokenSchema && tokenSchema.sso && !tokenSchema.sso.protocol) {
1695
- tokenSchema.sso.protocol = sso.protocol;
1675
+ if (thisAHdata.Accept === '') {
1676
+ delete thisAHdata.Accept;
1677
+ }
1678
+ if (thisAHdata['Content-Type'] === '') {
1679
+ delete thisAHdata['Content-Type'];
1696
1680
  }
1697
- }
1698
- if (tokenSchema && tokenSchema.sso && tokenSchema.sso.host) {
1699
- options.hostname = tokenSchema.sso.host;
1700
- }
1701
- if (tokenSchema && tokenSchema.sso && tokenSchema.sso.port) {
1702
- options.port = tokenSchema.sso.port;
1703
- }
1704
1681
 
1705
- // If there is a token schema, need to take the data from there
1706
- if (tokenSchema) {
1707
- options.path = tokenSchema.entitypath;
1708
- options.method = tokenSchema.method;
1709
- }
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
+ };
1710
1690
 
1711
- // if the path has a base path parameter in it, need to replace it
1712
- let bpathStr = '{base_path}';
1713
- if (options.path.indexOf(bpathStr) >= 0) {
1714
- // be able to support this if the base path has a slash before it or not
1715
- if (options.path.indexOf('/{base_path}') >= 0) {
1716
- 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;
1717
1697
  }
1718
1698
 
1719
- // replace with base path if we have one, otherwise remove base path
1720
- if (callProperties && callProperties.base_path) {
1721
- // if no leading /, insert one
1722
- if (callProperties.base_path.indexOf('/') !== 0) {
1723
- options.path = options.path.replace(bpathStr, `/${callProperties.base_path}`);
1724
- } else {
1725
- options.path = options.path.replace(bpathStr, callProperties.base_path);
1726
- }
1727
- } else if (basepath) {
1728
- // if no leading /, insert one
1729
- if (basepath.indexOf('/') !== 0) {
1730
- options.path = options.path.replace(bpathStr, `/${basepath}`);
1731
- } else {
1732
- 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;
1733
1720
  }
1734
- } else {
1735
- options.path = options.path.replace(bpathStr, '');
1736
1721
  }
1737
- }
1738
-
1739
- // if the path has a version parameter in it, need to replace it
1740
- let versStr = '{version}';
1741
- if (options.path.indexOf(versStr) >= 0) {
1742
- // be able to support this if the version has a slash before it or not
1743
- if (options.path.indexOf('/{version}') >= 0) {
1744
- 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;
1745
1727
  }
1746
1728
 
1747
- // replace with version if we have one, otherwise remove version
1748
- if (callProperties && callProperties.version) {
1749
- options.path = options.path.replace(versStr, `/${encodeURIComponent(callProperties.version)}`);
1750
- } else if (version) {
1751
- options.path = options.path.replace(versStr, `/${encodeURIComponent(version)}`);
1752
- } else {
1753
- 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;
1754
1733
  }
1755
- }
1756
1734
 
1757
- // if there are URI path variables that have been provided, need to add
1758
- // them to the path
1759
- if (reqBody && reqBody.uriPathVars && reqBody.uriPathVars.length > 0) {
1760
- for (let p = 0; p < reqBody.uriPathVars.length; p += 1) {
1761
- const vnum = p + 1;
1762
- const holder = `pathv${vnum.toString()}`;
1763
- const hindex = options.path.indexOf(holder);
1764
-
1765
- // if path variable is in the url, replace it!!!
1766
- if (hindex >= 0 && reqBody.uriPathVars[p] !== null && reqBody.uriPathVars[p] !== '') {
1767
- // with the provided id
1768
- let idString = '';
1769
-
1770
- // check if the current URI path ends with a slash (may require
1771
- // slash at end)
1772
- if (options.path[hindex - 2] === '/' || options.path[hindex - 2] === ':') {
1773
- // ends with a slash need to add slash to end
1774
- 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}`);
1748
+ } else {
1749
+ options.path = options.path.replace(bpathStr, callProperties.base_path);
1750
+ }
1751
+ } else if (basepath) {
1752
+ // if no leading /, insert one
1753
+ if (basepath.indexOf('/') !== 0) {
1754
+ options.path = options.path.replace(bpathStr, `/${basepath}`);
1775
1755
  } else {
1776
- // otherwise add / to start
1777
- idString = '/';
1778
- idString += encodeURIComponent(reqBody.uriPathVars[p]);
1756
+ options.path = options.path.replace(bpathStr, basepath);
1779
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
+ }
1780
1770
 
1781
- // replace the id in url with the id string
1782
- 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, '');
1783
1778
  }
1784
1779
  }
1785
- }
1786
1780
 
1787
- // need to remove all of the remaining path holders from the URI
1788
- while (options.path.indexOf('{pathv') >= 0) {
1789
- let sIndex = options.path.indexOf('{pathv');
1790
- 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
+ }
1791
1804
 
1792
- // if there is a / before the {pathv} need to remove it
1793
- if (options.path[sIndex - 1] === '/' || options.path[sIndex - 1] === ':') {
1794
- sIndex -= 1;
1805
+ // replace the id in url with the id string
1806
+ options.path = options.path.replace(`{${holder}}`, idString);
1807
+ }
1808
+ }
1795
1809
  }
1796
1810
 
1797
- if (sIndex > 0) {
1798
- // add the start of the path
1799
- 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);
1800
1815
 
1801
- if (eIndex < options.path.length) {
1802
- // add the end of the path
1803
- 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;
1804
1819
  }
1805
1820
 
1806
- options.path = tempStr;
1807
- } else if (eIndex > 0 && eIndex < options.path.length) {
1808
- // add the end of the path
1809
- options.path = options.path.substring(eIndex + 1);
1810
- } else {
1811
- // should not get here - there is some issue in the uripath - missing
1812
- // an end or the path is just {pathv#}
1813
- // add the specific pieces of the error object
1814
- const errorObj = this.transUtil.formatErrorObject(origin, 'Invalid Action File', ['missing entity path', '.system/getToken'], null, null, null);
1815
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1816
- 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
+ }
1817
1842
  }
1818
- }
1819
1843
 
1820
- // only add global options if there are global options to add
1821
- if (globalRequest && globalRequest.uriOptions
1822
- && Object.keys(globalRequest.uriOptions).length > 0) {
1823
- 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);
1824
1848
 
1825
- // if no query paramters yet - start with ?
1826
- if (options.path.indexOf('?') < 0) {
1827
- options.path += `?${optionString}`;
1828
- } else {
1829
- // if already have query parameters, add on to end
1830
- 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
+ }
1831
1856
  }
1832
- }
1833
1857
 
1834
- // remove the path vars from the reqBody
1835
- const actReqBody = Object.assign({}, reqBody);
1836
- if (actReqBody && actReqBody.uriPathVars) {
1837
- delete actReqBody.uriPathVars;
1838
- }
1858
+ // remove the path vars from the reqBody
1859
+ const actReqBody = Object.assign({}, reqBody);
1860
+ if (actReqBody && actReqBody.uriPathVars) {
1861
+ delete actReqBody.uriPathVars;
1862
+ }
1839
1863
 
1840
- // if ssl enabled add the options for ssl
1841
- if (callProperties && callProperties.ssl && Object.hasOwnProperty.call(callProperties.ssl, 'enabled')) {
1842
- if (callProperties.ssl.enabled) {
1843
- 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) {
1844
1893
  // if we are accepting invalid certificates (ok for lab not so much production)
1845
1894
  options.rejectUnauthorized = false;
1846
1895
  } else {
1847
1896
  // if we are not accepting invalid certs, need the ca file in the options
1848
1897
  try {
1849
1898
  options.rejectUnauthorized = true;
1850
- options.ca = [fs.readFileSync(callProperties.ssl.ca_file)];
1899
+ options.ca = [fs.readFileSync(sslCAFile)];
1851
1900
  } catch (e) {
1852
- 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);
1853
1902
  log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1854
- 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
+ }
1855
1924
  }
1856
1925
  }
1857
1926
 
1858
- if (callProperties.ssl.ciphers) {
1859
- options.ciphers = callProperties.ssl.ciphers;
1860
- }
1861
- if (callProperties.ssl.secure_protocol) {
1862
- options.secureProtocol = callProperties.ssl.secure_protocol;
1863
- }
1864
-
1865
- log.info(`${origin}: Connector SSL connections enabled`);
1866
- }
1867
- } else if (sslEnabled) {
1868
- if (sslAcceptInvalid) {
1869
- // if we are accepting invalid certificates (ok for lab not so much production)
1870
- options.rejectUnauthorized = false;
1871
- } else {
1872
- // if we are not accepting invalid certs, need the ca file in the options
1873
- try {
1874
- options.rejectUnauthorized = true;
1875
- options.ca = [fs.readFileSync(sslCAFile)];
1876
- } catch (e) {
1877
- const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslCAFile], null, null, null);
1878
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1879
- return callback(null, errorObj);
1927
+ if (sslCiphers) {
1928
+ options.ciphers = sslCiphers;
1880
1929
  }
1881
- // if there is a cert file, try to read in a cert file in the options
1882
- if (sslCertFile) {
1883
- try {
1884
- options.cert = [fs.readFileSync(sslCertFile)];
1885
- } catch (e) {
1886
- const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslCertFile], null, null, null);
1887
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1888
- return callback(null, errorObj);
1889
- }
1930
+ if (sslPassphrase) {
1931
+ options.passphrase = sslPassphrase;
1890
1932
  }
1891
- // if there is a key file, try to read in a key file in the options
1892
- if (sslKeyFile) {
1893
- try {
1894
- options.key = [fs.readFileSync(sslKeyFile)];
1895
- } catch (e) {
1896
- const errorObj = this.transUtil.formatErrorObject(origin, 'Missing File', [sslKeyFile], null, null, null);
1897
- log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1898
- return callback(null, errorObj);
1899
- }
1933
+ if (secureProtocol) {
1934
+ options.secureProtocol = secureProtocol;
1900
1935
  }
1901
- }
1902
1936
 
1903
- if (sslCiphers) {
1904
- options.ciphers = sslCiphers;
1905
- }
1906
- if (sslPassphrase) {
1907
- options.passphrase = sslPassphrase;
1908
- }
1909
- if (secureProtocol) {
1910
- options.secureProtocol = secureProtocol;
1937
+ log.info(`${origin}: Connector SSL connections enabled`);
1911
1938
  }
1912
1939
 
1913
- log.info(`${origin}: Connector SSL connections enabled`);
1914
- }
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
+ }
1915
1957
 
1916
- const reqData = {};
1917
- let bodyString = null;
1918
-
1919
- // if we have been passed a schema and the Authorization is in a header
1920
- // COMMENTED OUT AND HANDLED IN IF BELOW - take stuff out of body on line 1930
1921
- // if (tokenSchema && tokenSchema.headers && tokenSchema.headers.Authorization) {
1922
- // // request the token
1923
- // options.headers['Content-length'] = 0;
1924
- // return getToken(reqPath, options, tokenSchema, '', callProperties, callback);
1925
- // }
1926
- if (tokenSchema) {
1927
- // if this is a get, need to put the username on the url
1928
- if (options.path.indexOf('/{username}') >= 0) {
1929
- options.path = options.path.replace('/{username}', useUser);
1930
- } else {
1931
- options.path = options.path.replace('{username}', useUser);
1932
- }
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
+ }
1933
1964
 
1934
- // if this is a get, need to put the password on the url
1935
- if (options.path.indexOf('/{password}') >= 0) {
1936
- options.path = options.path.replace('/{password}', usePass);
1937
- } else {
1938
- options.path = options.path.replace('{password}', usePass);
1939
- }
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
+ }
1940
1995
 
1941
- // if this is not a get, need to add the info to the request
1942
- if (options.method !== 'GET') {
1943
- let creds = {
1944
- username: useUser,
1945
- password: usePass
1946
- };
1947
- if (clientId) {
1948
- creds.client_id = clientId;
1949
- }
1950
- if (clientSecret) {
1951
- creds.client_secret = clientSecret;
1952
- }
1953
- if (grantType) {
1954
- creds.grant_type = grantType;
1955
- }
1956
- if (callProperties && callProperties.authentication && callProperties.authentication.client_id) {
1957
- creds.client_id = callProperties.authentication.client_id;
1958
- }
1959
- if (callProperties && callProperties.authentication && callProperties.authentication.client_secret) {
1960
- creds.client_secret = callProperties.authentication.client_secret;
1961
- }
1962
- if (callProperties && callProperties.authentication && callProperties.authentication.grant_type) {
1963
- creds.grant_type = callProperties.authentication.grant_type;
1964
- }
1996
+ // if there is body data to add to the token request body
1997
+ creds = transUtilInst.mergeObjects(actReqBody, creds);
1965
1998
 
1966
- // if there is body data to add to the token request body
1967
- creds = transUtilInst.mergeObjects(actReqBody, creds);
1999
+ if (globalRequest) {
2000
+ creds = transUtilInst.mergeObjects(creds, globalRequest.authData);
2001
+ }
1968
2002
 
1969
- if (globalRequest) {
1970
- creds = transUtilInst.mergeObjects(creds, globalRequest.authData);
1971
- }
2003
+ // if there is body data to add to the token request body
2004
+ if (actReqBody) {
2005
+ const bodyKey = Object.keys(actReqBody);
1972
2006
 
1973
- // if there is body data to add to the token request body
1974
- if (actReqBody) {
1975
- const bodyKey = Object.keys(actReqBody);
2007
+ for (let k = 0; k < bodyKey.length; k += 1) {
2008
+ creds[bodyKey[k]] = actReqBody[bodyKey[k]];
2009
+ }
2010
+ }
1976
2011
 
1977
- for (let k = 0; k < bodyKey.length; k += 1) {
1978
- 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
+ }
1979
2017
  }
1980
- }
1981
2018
 
1982
- if (tokenSchema.headers && tokenSchema.headers.Authorization) {
1983
- // remove the username and password from the creds
1984
- delete creds.username;
1985
- delete creds.password;
1986
- }
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;
1987
2022
 
1988
- // map the data we received to an Entity - will get back the defaults
1989
- const tokenEntity = transUtilInst.mapToOutboundEntity(creds, tokenSchema.requestSchema);
1990
- bodyString = tokenEntity;
1991
-
1992
- // if it is JSON or URLENCODE need to put body into right format
1993
- if (!tokenSchema.requestDatatype || tokenSchema.requestDatatype.toUpperCase() === 'JSON' || tokenSchema.requestDatatype.toUpperCase() === 'FORM') {
1994
- bodyString = JSON.stringify(tokenEntity);
1995
- } else if (tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLENCODE') {
1996
- bodyString = querystring.stringify(tokenEntity);
1997
- } else if (tokenSchema.requestDatatype && tokenSchema.requestDatatype.toUpperCase() === 'URLQUERY') {
1998
- // if the datatype is URLQUERY need to put into the query on the request
1999
- if (authQueryEncode != null) {
2000
- 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) {
2001
2048
  bodyString = querystring.stringify(tokenEntity);
2002
2049
  } else {
2003
2050
  bodyString = '';
@@ -2013,60 +2060,58 @@ function buildTokenRequest(reqPath, reqBody, callProperties, callback) {
2013
2060
  bodyString += `${qkeys[k]}=${tokenEntity[qkeys[k]]}`;
2014
2061
  }
2015
2062
  }
2016
- } else if (encodeUri === true) {
2017
- bodyString = querystring.stringify(tokenEntity);
2018
- } else {
2019
- bodyString = '';
2020
- // if not encoding we need to build
2021
- const qkeys = Object.keys(tokenEntity);
2022
- // add each query parameter and its value
2023
- for (let k = 0; k < qkeys.length; k += 1) {
2024
- // need to add separator for everything after the first one
2025
- if (k > 0) {
2026
- bodyString += '&';
2027
- }
2028
- // adds key=value
2029
- 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}`;
2030
2069
  }
2070
+ bodyString = '';
2031
2071
  }
2032
-
2033
- // append to the path
2034
- if (options.path.indexOf('?') < 0) {
2035
- options.path = `${options.path}?${bodyString}`;
2036
- } else {
2037
- 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);
2038
2076
  }
2039
- bodyString = '';
2040
- }
2041
2077
 
2042
- // if there is a body, set the content length of the body and add it to
2043
- // the header
2044
- if (Object.keys(tokenEntity).length > 0 || tokenSchema.sendEmpty) {
2045
- 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;
2046
2085
  }
2047
-
2048
- // request the token
2049
- 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);
2050
2095
  }
2051
- } else {
2052
- // set the user and password for the token request
2053
- reqData[tokenUserField] = useUser;
2054
- reqData[tokenPwdField] = usePass;
2055
- bodyString = reqData;
2056
2096
 
2057
- // since not a get call, convert reqData to a string and add length
2058
- bodyString = JSON.stringify(reqData);
2059
- options.headers['Content-length'] = Buffer.byteLength(bodyString);
2060
- }
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
+ });
2061
2110
 
2062
- // request the token
2063
- return getToken(reqPath, options, tokenSchema, bodyString, callProperties, callback);
2064
- });
2065
- } catch (e) {
2066
- // handle any exception
2067
- const errorObj = transUtilInst.checkAndReturn(e, origin, 'Issue requesting token');
2068
- return callback(null, errorObj);
2111
+ if (typeof callback === 'function') {
2112
+ return promise.then((result) => callback(result)).catch((error) => callback(null, error));
2069
2113
  }
2114
+ return promise;
2070
2115
  }
2071
2116
 
2072
2117
  /*
@@ -2413,6 +2458,264 @@ function addAuthToRequest(request, authStrs, callProperties, callback) {
2413
2458
  }
2414
2459
  }
2415
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
+ }
2416
2719
  /*
2417
2720
  * INTERNAL FUNCTION: requestAuthenticate determines the authentication for System,
2418
2721
  * and takes appropriate action to authenticate and then makes the request
@@ -2433,6 +2736,34 @@ function requestAuthenticate(request, entitySchema, invalidToken, callProperties
2433
2736
  usePass = callProperties.authentication.password;
2434
2737
  }
2435
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
+
2436
2767
  if (authMethod === 'request_token') {
2437
2768
  // are we working with reusing tokens until they expire?
2438
2769
  if (tokenTimeout >= 0) {
@@ -3407,6 +3738,10 @@ class ConnectorRest {
3407
3738
  authMethod = props.authentication.auth_method;
3408
3739
  }
3409
3740
 
3741
+ if (Array.isArray(props.authentication.multiStepAuthCalls)) {
3742
+ multiStepAuthCalls = props.authentication.multiStepAuthCalls;
3743
+ }
3744
+
3410
3745
  // set the username (required - default is null)
3411
3746
  if (typeof props.authentication.username === 'string') {
3412
3747
  username = props.authentication.username;