[pve-devel] [PATCH v2 manager] ui: auth: add api token authentication to login window

Tim Marx t.marx at proxmox.com
Thu May 7 14:28:25 CEST 2020


Signed-off-by: Tim Marx <t.marx at proxmox.com>
---

Notes:
    changed since v1:
    * store token including the product prefix
    * add token id to username to make it more obvious that it's note the actual user

 www/manager6/Workspace.js          |   5 ++
 www/manager6/window/LoginWindow.js | 129 ++++++++++++++++++++++-------
 2 files changed, 105 insertions(+), 29 deletions(-)

diff --git a/www/manager6/Workspace.js b/www/manager6/Workspace.js
index 57cb1bb9..b03443cb 100644
--- a/www/manager6/Workspace.js
+++ b/www/manager6/Workspace.js
@@ -73,6 +73,11 @@ Ext.define('PVE.Workspace', {
 
 	me.callParent();
 
+	var storedUser = Proxmox.Utils.getStoredUser();
+	if (storedUser.username) {
+	    Proxmox.UserName = storedUser.username;
+	}
+
         if (!Proxmox.Utils.authOK()) {
 	    me.showLogin();
 	} else {
diff --git a/www/manager6/window/LoginWindow.js b/www/manager6/window/LoginWindow.js
index e29b7352..223ad581 100644
--- a/www/manager6/window/LoginWindow.js
+++ b/www/manager6/window/LoginWindow.js
@@ -12,6 +12,8 @@ Ext.define('PVE.window.LoginWindow', {
 	    var form = this.lookupReference('loginForm');
 	    var unField = this.lookupReference('usernameField');
 	    var saveunField = this.lookupReference('saveunField');
+	    var tField = this.lookupReference('apitokenField');
+
 	    var view = this.getView();
 
 	    if (!form.isValid()) {
@@ -20,38 +22,60 @@ Ext.define('PVE.window.LoginWindow', {
 
 	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
 
-	    // set or clear username
-	    var sp = Ext.state.Manager.getProvider();
-	    if (saveunField.getValue() === true) {
-		sp.set(unField.getStateId(), unField.getValue());
+	    if (tField.value !== '') {
+		var splitToken = tField.value.match(/^(.*)=(.*)$/);
+		Proxmox.Utils.API2Request({
+		    url: '/api2/extjs/access/uicapabilities',
+		    headers:{
+			Authorization: 'PVEAPIToken=' + tField.value
+		    },
+		    success: function(response, opts) {
+			var data = {
+			    username: splitToken[1],
+			    token: 'PVEAPIToken=' + tField.value,
+			    cap: response.result.data.cap
+			};
+			me.success(data);
+		    },
+
+		    failure: function(response, opts) {
+			me.failure(response);
+		    }
+		});
 	    } else {
-		sp.clear(unField.getStateId());
-	    }
-	    sp.set(saveunField.getStateId(), saveunField.getValue());
+		// set or clear username
+		var sp = Ext.state.Manager.getProvider();
+		if (saveunField.getValue() === true) {
+		    sp.set(unField.getStateId(), unField.getValue());
+		} else {
+		    sp.clear(unField.getStateId());
+		}
+		sp.set(saveunField.getStateId(), saveunField.getValue());
 
-	    form.submit({
-		failure: function(f, resp){
-		    me.failure(resp);
-		},
-		success: function(f, resp){
-		    view.el.unmask();
+		form.submit({
+		    failure: function(f, resp){
+			me.failure(resp);
+		    },
+		    success: function(f, resp){
+			view.el.unmask();
 
-		    var data = resp.result.data;
-		    if (Ext.isDefined(data.NeedTFA)) {
-			// Store first factor login information first:
-			data.LoggedOut = true;
-			Proxmox.Utils.setAuthData(data);
+			var data = resp.result.data;
+			if (Ext.isDefined(data.NeedTFA)) {
+			    // Store first factor login information first:
+			    data.LoggedOut = true;
+			    Proxmox.Utils.setAuthData(data);
 
-			if (Ext.isDefined(data.U2FChallenge)) {
-			    me.perform_u2f(data);
+			    if (Ext.isDefined(data.U2FChallenge)) {
+				me.perform_u2f(data);
+			    } else {
+				me.perform_otp();
+			    }
 			} else {
-			    me.perform_otp();
+			    me.success(data);
 			}
-		    } else {
-			me.success(data);
 		    }
-		}
-	    });
+		});
+	    }
 
 	},
 	failure: function(resp) {
@@ -143,6 +167,31 @@ Ext.define('PVE.window.LoginWindow', {
 		}
 	    });
 	},
+	onUsetokenChange: function(value) {
+	    var uField = this.lookupReference('usernameField');
+	    var svunField = this.lookupReference('saveunField');
+	    var pField = this.lookupReference('passwordField');
+	    var rField = this.lookupReference('realmField');
+	    var tField = this.lookupReference('apitokenField');
+
+	    uField.setVisible(!value.checked);
+	    uField.setDisabled(value.checked);
+
+	    svunField.setVisible(!value.checked);
+	    svunField.setDisabled(value.checked);
+
+	    pField.setVisible(!value.checked);
+	    pField.setDisabled(value.checked);
+
+	    rField.setVisible(!value.checked);
+	    rField.setDisabled(value.checked);
+
+
+
+	    tField.setVisible(value.checked);
+	    tField.setDisabled(!value.checked);
+
+	},
 
 	control: {
 	    'field[name=username]': {
@@ -198,7 +247,20 @@ Ext.define('PVE.window.LoginWindow', {
 
     defaultFocus: 'usernameField',
     defaultButton: 'loginButton',
-
+    tools: [
+	{
+	    xtype: 'checkbox',
+	    fieldLabel: gettext('Use API Token'),
+	    name: 'usetoken',
+	    reference: 'usetoken',
+	    stateId: 'login-usetoken',
+	    labelAlign: 'right',
+	    submitValue: false,
+	    listeners: {
+		change: 'onUsetokenChange'
+	    }
+	}
+    ],
     items: [{
 	xtype: 'form',
 	layout: 'form',
@@ -209,7 +271,6 @@ Ext.define('PVE.window.LoginWindow', {
 	    labelAlign: 'right',
 	    allowBlank: false
 	},
-
 	items: [
 	    {
 		xtype: 'textfield',
@@ -228,7 +289,17 @@ Ext.define('PVE.window.LoginWindow', {
 	    },
 	    {
 		xtype: 'pveRealmComboBox',
-		name: 'realm'
+		name: 'realm',
+		reference: 'realmField'
+	    },
+	    {
+		xtype: 'textfield',
+		fieldLabel: gettext('API Token'),
+		name: 'apitoken',
+		reference: 'apitokenField',
+		emptyText: 'USER at REALM!TOKENID=UUID',
+		hidden: true,
+		disabled: true
 	    },
 	    {
 		xtype: 'proxmoxLanguageSelector',
@@ -246,8 +317,8 @@ Ext.define('PVE.window.LoginWindow', {
 		name: 'saveusername',
 		reference: 'saveunField',
 		stateId: 'login-saveusername',
-		labelWidth: 250,
 		labelAlign: 'right',
+		labelWidth: 250,
 		submitValue: false
 	    },
 	    {
-- 
2.20.1




More information about the pve-devel mailing list