Skip to content

Commit 7774bfe

Browse files
authored
[5.4] MSTR-350: Close OTP dialog after submit on login retry (#1357)
1 parent 8e7247f commit 7774bfe

File tree

4 files changed

+76
-43
lines changed

4 files changed

+76
-43
lines changed

src/apps/auth/app.js

Lines changed: 61 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ define(function(require) {
12831283
},
12841284
error: function(errorPayload, data, globalHandler) {
12851285
if (data.status === 401 && errorPayload.data.hasOwnProperty('multi_factor_request')) {
1286-
self.handleMultiFactor(errorPayload.data, dataRecovery, function(augmentedDataRecovery) {
1286+
self.handleMultiFactor(errorPayload.data, dataRecovery, null, function(augmentedDataRecovery) {
12871287
self.recoveryWithResetId(augmentedDataRecovery, success, error);
12881288
}, function() {
12891289
monster.util.logoutAndReload();
@@ -1389,18 +1389,21 @@ define(function(require) {
13891389
// If it's a 401 that is about requesting additional login information via MFA, we need to know if it comes from a reconnect attempt
13901390
// If it comes from a reconnect attempt, then we show a popup to ask them if they want to reconnect.
13911391
// If we don't do that and the system automatically reconnected, then the User would see a popup asking him to re-authenticate Duo without any context.
1392-
var handleMultifactor = function() {
1393-
self.handleMultiFactor(errorPayload.data, loginData, function(augmentedLoginData) {
1394-
self.putAuth(augmentedLoginData, callback, wrongCredsCallback, pUpdateLayout, additionalArgs);
1395-
}, wrongCredsCallback);
1396-
};
1397-
1398-
if (additionalArgs && additionalArgs.hasOwnProperty('isRetryLoginRequest') && additionalArgs.isRetryLoginRequest === true) {
1399-
monster.ui.confirm(self.i18n.active().retryLoginConfirmText, function() {
1400-
handleMultifactor();
1401-
}, function() {
1402-
monster.util.logoutAndReload();
1403-
});
1392+
var handleMultifactor = function(cancelCallback) {
1393+
self.handleMultiFactor(errorPayload.data, loginData, additionalArgs, function(augmentedLoginData) {
1394+
self.putAuth(augmentedLoginData, callback, wrongCredsCallback, pUpdateLayout, additionalArgs);
1395+
}, wrongCredsCallback, cancelCallback);
1396+
},
1397+
showReconnectDialog = function() {
1398+
monster.ui.confirm(self.i18n.active().retryLoginConfirmText, function() {
1399+
handleMultifactor(showReconnectDialog);
1400+
}, function() {
1401+
monster.util.logoutAndReload();
1402+
});
1403+
};
1404+
1405+
if (_.get(additionalArgs, 'isRetryLoginRequest', false) === true) {
1406+
showReconnectDialog();
14041407
} else {
14051408
handleMultifactor();
14061409
}
@@ -1414,9 +1417,10 @@ define(function(require) {
14141417
});
14151418
},
14161419

1417-
handleMultiFactor: function(data, loginData, success, error) {
1420+
handleMultiFactor: function(data, loginData, additionalArgs, success, error, cancel) {
14181421
var self = this,
1419-
mfaProvider = data.multi_factor_request.provider_name;
1422+
mfaProvider = data.multi_factor_request.provider_name,
1423+
isRetryLoginRequest = _.get(additionalArgs, 'isRetryLoginRequest', false);
14201424

14211425
switch (mfaProvider) {
14221426
case 'duo_universal':
@@ -1427,8 +1431,10 @@ define(function(require) {
14271431
break;
14281432
case 'otp':
14291433
self.showOtpVerificationDialog({
1434+
isRetryLoginRequest: isRetryLoginRequest,
14301435
loginData: loginData,
1431-
success: success
1436+
success: success,
1437+
cancel: cancel
14321438
});
14331439
break;
14341440
default:
@@ -1460,24 +1466,34 @@ define(function(require) {
14601466
/**
14611467
* Shows the OTP verification dialog.
14621468
* @param {Object} args
1469+
* @param {Boolean} [args.isRetryLoginRequest] Whether or not is a login retry request
14631470
* @param {Object} args.loginData Login data
14641471
* @param {String} args.loginData.credentials Hashed credentials
14651472
* @param {String} args.loginData.accout_name Account name
14661473
* @param {Function} args.success Login success callback
1474+
* @param {Function} args.cancel Cancel callback
14671475
*/
14681476
showOtpVerificationDialog: function(args) {
14691477
var self = this,
14701478
$template = $(self.getTemplate({
1471-
name: 'mfa-otpVerificationDialog'
1479+
name: 'mfa-otpVerificationDialog',
1480+
data: {
1481+
isRetryLoginRequest: !!args.isRetryLoginRequest
1482+
}
14721483
})),
14731484
$dialog = monster.ui.dialog($template, {
14741485
title: self.i18n.active().multiFactor.verification.title
14751486
}),
1476-
bindArgs = _.assign({
1477-
$dialog: $dialog
1478-
}, args);
1487+
bindArgs = _.chain(args)
1488+
.pick(['loginData', 'success', 'cancel'])
1489+
.assign({
1490+
$dialog: $dialog
1491+
})
1492+
.value();
14791493

14801494
self.bindOtpVerificationDialogEvents(bindArgs);
1495+
1496+
$template.find('#mfa_code').focus();
14811497
},
14821498

14831499
/**
@@ -1488,13 +1504,15 @@ define(function(require) {
14881504
* @param {String} args.loginData.credentials Hashed credentials
14891505
* @param {String} args.loginData.accout_name Account name
14901506
* @param {Function} args.success Login success callback
1507+
* @param {Function} args.cancel Cancel callback
14911508
*/
14921509
bindOtpVerificationDialogEvents: function(args) {
14931510
var self = this,
14941511
$dialog = args.$dialog,
14951512
loginData = args.loginData,
14961513
validator = args.validator,
14971514
successCallback = args.success,
1515+
cancelCallback = args.cancel,
14981516
$form = $dialog.find('form'),
14991517
validator = monster.ui.validate($form, {
15001518
rules: {
@@ -1505,7 +1523,8 @@ define(function(require) {
15051523
}),
15061524
$mfaCode = $form.find('#mfa_code'),
15071525
$btnVerify = $dialog.find('#btn_mfa_verify'),
1508-
isCodeLengthInvalid = true;
1526+
isCodeLengthInvalid = true,
1527+
isSubmitted = false;
15091528

15101529
monster.ui.mask($mfaCode, '000000', {
15111530
placeholder: '______'
@@ -1528,7 +1547,8 @@ define(function(require) {
15281547
$dialog.dialog('close');
15291548
self.showOtpSetupDialog({
15301549
loginData: loginData,
1531-
success: successCallback
1550+
success: successCallback,
1551+
cancel: cancelCallback
15321552
});
15331553
});
15341554

@@ -1576,11 +1596,23 @@ define(function(require) {
15761596
return;
15771597
}
15781598

1599+
isSubmitted = true;
1600+
1601+
$dialog.dialog('close');
1602+
15791603
successCallback(_.assign({
15801604
multi_factor_response: code
15811605
}, loginData));
15821606
});
15831607
});
1608+
1609+
$dialog.on('dialogclose', function() {
1610+
if (isSubmitted) {
1611+
return;
1612+
}
1613+
1614+
cancelCallback && cancelCallback();
1615+
});
15841616
},
15851617

15861618
/**
@@ -1594,7 +1626,6 @@ define(function(require) {
15941626
showOtpSetupDialog: function(args) {
15951627
var self = this,
15961628
loginData = args.loginData,
1597-
successCallback = args.success,
15981629
$template = $(self.getTemplate({
15991630
name: 'mfa-otpSetupDialog'
16001631
})),
@@ -1611,11 +1642,11 @@ define(function(require) {
16111642

16121643
monster.parallel({
16131644
bindEvents: function bindEvents(next) {
1614-
self.bindOtpSetupDialogEvents({
1615-
$dialog: $dialog,
1616-
loginData: loginData,
1617-
success: successCallback
1618-
});
1645+
var bindArgs = _.assign({
1646+
$dialog: $dialog
1647+
}, args);
1648+
1649+
self.bindOtpSetupDialogEvents(bindArgs);
16191650

16201651
next();
16211652
},
@@ -1748,16 +1779,12 @@ define(function(require) {
17481779
bindOtpSetupDialogEvents: function(args) {
17491780
var self = this,
17501781
$dialog = args.$dialog,
1751-
loginData = args.loginData,
1752-
successCallback = args.success;
1782+
showOtpVerificationDialogArgs = _.pick(args, ['loginData', 'success', 'cancel']);
17531783

17541784
$dialog.find('#btn_mfa_enter_code').on('click', function(e) {
17551785
e.preventDefault();
17561786
$dialog.dialog('close');
1757-
self.showOtpVerificationDialog({
1758-
loginData: loginData,
1759-
success: successCallback
1760-
});
1787+
self.showOtpVerificationDialog(showOtpVerificationDialogArgs);
17611788
});
17621789
},
17631790

src/apps/auth/views/mfa-otpVerificationDialog.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
<button class="btn-submit monster-button monster-button-primary" id="btn_mfa_verify" type="submit" disabled="true">
1616
{{ i18n.multiFactor.verification.verifyButton }}
1717
</button>
18+
{{#unless isRetryLoginRequest}}
1819
<hr />
1920
<p class="form-footer">
2021
{{ i18n.multiFactor.verification.setupDesciption }}
2122
<a href="javascript:void(0);" id="btn_mfa_setup" class="form-toggle medium-link">
2223
{{ i18n.multiFactor.verification.setupButton }}
2324
</a>
2425
</p>
26+
{{/unless}}
2527
</div>
2628
</form>
2729
</div>

src/js/lib/monster.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,14 @@ define(function(require) {
889889
var error = args.error;
890890
var errorMessage = _.get(args, 'errorMessage', monster.apps.core.i18n.active().invalidCredentialsMessage);
891891
var options = args.options;
892+
var retryRequest = function() {
893+
requestHandler(_.assign({}, options, {
894+
// Used to feed the updated token to the SDK (when requestHandler() references monster.kazooSdk.request())
895+
authToken: monster.util.getAuthToken(),
896+
// We setup the flag to false this time, so that if it errors out again, we properly log out of the UI
897+
preventCallbackError: false
898+
}));
899+
};
892900

893901
// If we have a 401 after being logged in, it means our session expired, or that it's a MFA denial of the relogin attempt
894902
// We don't want to show the normal error box for 401s, but still want to check the payload if they happen, via the error tool.
@@ -903,9 +911,7 @@ define(function(require) {
903911
// If it's a retryLoginRequest, we don't want to prevent the callback as it could be a MFA denial
904912
} else if (!_.get(options, 'isRetryLoginRequest', false)) {
905913
if (_privateFlags.lockRetryAttempt) {
906-
_privateFlags.addRetryFunction(function() {
907-
requestHandler(options);
908-
});
914+
_privateFlags.addRetryFunction(retryRequest);
909915
} else {
910916
// We added a new locking mechanism. Basically if your module use a parallel request, you could have 5 requests ending in a 401. We don't want to automatically re-login 5 times, so we lock the system
911917
// Once the re-login is effective, we'll unlock it.
@@ -920,12 +926,7 @@ define(function(require) {
920926
isRetryLoginRequest: true
921927
},
922928
success: function() {
923-
requestHandler($.extend(true, {}, options, {
924-
// Used to feed the updated token to the SDK (when requestHandler() references monster.kazooSdk.request())
925-
authToken: monster.util.getAuthToken(),
926-
// We setup the flag to false this time, so that if it errors out again, we properly log out of the UI
927-
preventCallbackError: false
928-
}));
929+
retryRequest();
929930
_privateFlags.unlockRetryFunctions();
930931
},
931932
error: function() {

src/js/lib/monster.socket.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,9 @@ define(function(require) {
389389
wsc.logger.log('attempting to reauthenticate...');
390390

391391
monster.pub('auth.retryLogin', {
392+
additionalArgs: {
393+
isRetryLoginRequest: true
394+
},
392395
success: function() {
393396
wsc.logger.log('reauthentication successful');
394397
wsc.bind(params);

0 commit comments

Comments
 (0)