mobile: implement login with OTP based TFA enabled

roughly copied over from the full-fledged manager UI, but enough
differences between manager <-> mobile and ExtJS <-> Sencha Touch to
just adapt it here instead of having a force-shared implementation
with lots of corner case checks and even more callback methods..

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht 2019-10-01 13:30:06 +02:00
parent ab17ebcdc4
commit 627548d6fb

View File

@ -1,6 +1,67 @@
Ext.define('PVE.Login', {
extend: 'Ext.form.Panel',
alias: "widget.pveLogin",
handleTFA: function(username, ticketResponse) {
let me = this;
let errlabel = me.down('#signInFailedLabel');
// set auth cookie with half-loggedin ticket for TFA
ticketResponse.LoggedOut = true;
Proxmox.Utils.setAuthData(ticketResponse);
if (Ext.isDefined(ticketResponse.U2FChallenge)) {
Ext.Msg.show({
title: 'Error - U2F not implemented',
message: 'The U2F two factor authentication is not yet implemented on mobile.',
buttons: Ext.MessageBox.CANCEL,
});
errlabel.show();
} else {
Ext.Msg.show({
title: 'Two-Factor Authentication',
message: 'Please enter your OTP verification code:',
buttons: Ext.MessageBox.OKCANCEL,
prompt: {
xtype: 'tfacode',
},
fn: function(buttonId, code) {
if (buttonId === "cancel") {
Proxmox.LoggedOut = false;
Proxmox.Utils.authClear();
} else {
me.mask({
xtype: 'loadmask',
message: 'Loading...'
});
Proxmox.Utils.API2Request({
url: '/api2/extjs/access/tfa',
params: { response: code },
method: 'POST',
timeout: 5000, // it'll delay both success & failure
success: function(resp, opts) {
me.unmask();
// Fill in what we copy over from the 1st factor:
let authdata = resp.result.data;
authdata.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
authdata.username = username;
// Finish login, sets real cookie and loads page
PVE.Workspace.updateLoginData(authdata);
},
failure: function(resp, opts) {
me.unmask();
Proxmox.Utils.authClear();
errlabel.show();
}
});
}
},
});
}
},
config: {
title: 'Login',
padding: 10,
@ -30,33 +91,10 @@ Ext.define('PVE.Login', {
name: 'password',
required: true
},
{
xtype: 'textfield',
itemId: 'otpField',
placeHolder: gettext('OTP'),
name: 'otp',
allowBlank: false,
hidden: true
},
{
xtype: 'pveRealmSelector',
itemId: 'realmSelectorField',
name: 'realm',
listeners: {
change: function(f, value) {
var form = this.up('formpanel');
var otp_field = form.down('#otpField');
if (f.needOTP(value)) {
otp_field.setHidden(false);
otp_field.enable();
} else {
otp_field.setHidden(true);
otp_field.disable();
}
}
}
}
]
},
@ -75,33 +113,36 @@ Ext.define('PVE.Login', {
ui: 'action',
text: 'Log In',
handler: function() {
var form = this.up('formpanel');
var form = this.up('formpanel');
var usernameField = form.down('#userNameTextField'),
passwordField = form.down('#passwordTextField'),
realmField = form.down('#realmSelectorField'),
otpField = form.down('#otpField'),
label = form.down('#signInFailedLabel');
passwordField = form.down('#passwordTextField'),
realmField = form.down('#realmSelectorField'),
errlabel = form.down('#signInFailedLabel');
label.hide();
errlabel.hide();
var username = usernameField.getValue();
var password = passwordField.getValue();
var realm = realmField.getValue();
var otp = otpField.getValue();
Proxmox.Utils.API2Request({
url: '/access/ticket',
method: 'POST',
waitMsgTarget: form,
params: { username: username, password: password, realm: realm, otp: otp},
params: { username: username, password: password, realm: realm },
failure: function(response, options) {
label.show();
errlabel.show();
},
success: function(response, options) {
usernameField.setValue('');
passwordField.setValue('');
PVE.Workspace.updateLoginData(response.result.data);
let data = response.result.data;
if (Ext.isDefined(data.NeedTFA)) {
form.handleTFA(username, data);
} else {
PVE.Workspace.updateLoginData(data);
}
}
});
}
@ -109,3 +150,16 @@ Ext.define('PVE.Login', {
]
}
});
Ext.define('PVE.field.TFACode', {
extend: 'Ext.field.Text',
xtype: 'tfacode',
config: {
component: {
type: 'number'
},
maxLength: 6,
required: true,
},
});