[pve-devel] [PATCH pve-manager] ui: implement OpenId login

Dietmar Maurer dietmar at proxmox.com
Thu Jun 24 10:17:59 CEST 2021


---
 PVE/HTTPServer.pm                  |   4 +-
 www/manager6/Utils.js              |   8 +++
 www/manager6/window/LoginWindow.js | 105 ++++++++++++++++++++++++++++-
 3 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/PVE/HTTPServer.pm b/PVE/HTTPServer.pm
index 636b562b..dabdf7f3 100755
--- a/PVE/HTTPServer.pm
+++ b/PVE/HTTPServer.pm
@@ -68,7 +68,9 @@ sub auth_handler {
 
     # explicitly allow some calls without auth
     if (($rel_uri eq '/access/domains' && $method eq 'GET') ||
-	($rel_uri eq '/access/ticket' && ($method eq 'GET' || $method eq 'POST'))) {
+	($rel_uri eq '/access/ticket' && ($method eq 'GET' || $method eq 'POST')) ||
+	($rel_uri eq '/access/openid/login' &&  $method eq 'POST') ||
+	($rel_uri eq '/access/openid/auth-url' &&  $method eq 'POST')) {
 	$require_auth = 0;
     }
 
diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index 3415c9eb..c2d139f9 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -1742,6 +1742,14 @@ Ext.define('PVE.Utils', {
 
 	return true;
     },
+
+    openid_login_param: function() {
+	let param = Ext.Object.fromQueryString(window.location.search);
+	if (param.state !== undefined && param.code !== undefined) {
+	    return param;
+	}
+	return undefined;
+    },
 },
 
     singleton: true,
diff --git a/www/manager6/window/LoginWindow.js b/www/manager6/window/LoginWindow.js
index 72078080..5d3d06b8 100644
--- a/www/manager6/window/LoginWindow.js
+++ b/www/manager6/window/LoginWindow.js
@@ -2,6 +2,21 @@
 Ext.define('PVE.window.LoginWindow', {
     extend: 'Ext.window.Window',
 
+    viewModel: {
+	data: {
+	    openid: false,
+	},
+	formulas: {
+	    button_text: function(get) {
+		if (get("openid") === true) {
+		    return gettext("Login (OpenID redirect)");
+		} else {
+		    return gettext("Login");
+		}
+	    },
+	},
+    },
+
     controller: {
 
 	xclass: 'Ext.app.ViewController',
@@ -18,6 +33,33 @@ Ext.define('PVE.window.LoginWindow', {
 		return;
 	    }
 
+	    let redirect_url = location.origin;
+	    let params = form.getValues();
+
+	    if (this.getViewModel().data.openid === true) {
+		let realm = params.realm;
+		Proxmox.Utils.API2Request({
+		    url: '/api2/extjs/access/openid/auth-url',
+		    params: {
+			realm: realm,
+			"redirect-url": redirect_url,
+		    },
+		    method: 'POST',
+		    success: function(resp, opts) {
+			window.location = resp.result.data;
+		    },
+		    failure: function(resp, opts) {
+			Proxmox.Utils.authClear();
+			form.unmask();
+			Ext.MessageBox.alert(
+			    gettext('Error'),
+			    gettext('OpenId redirect failed. Please try again<br>Error: ' + resp.htmlStatus),
+			);
+		    },
+		});
+		return;
+	    }
+
 	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
 
 	    // set or clear username
@@ -162,11 +204,21 @@ Ext.define('PVE.window.LoginWindow', {
 		    window.location.reload();
 		},
 	    },
-            'button[reference=loginButton]': {
+	    'field[name=realm]': {
+		change: function(f, value) {
+		    let record = f.store.getById(value);
+		    if (record === undefined) return;
+		    let data = record.data;
+		    this.getViewModel().set("openid", data.type === "openid");
+		},
+	    },
+           'button[reference=loginButton]': {
 		click: 'onLogon',
             },
 	    '#': {
 		show: function() {
+		    var me = this;
+
 		    var sp = Ext.state.Manager.getProvider();
 		    var checkboxField = this.lookupReference('saveunField');
 		    var unField = this.lookupReference('usernameField');
@@ -180,6 +232,42 @@ Ext.define('PVE.window.LoginWindow', {
 			var pwField = this.lookupReference('passwordField');
 			pwField.focus();
 		    }
+
+		    let param = PVE.Utils.openid_login_param();
+		    if (param !== undefined) {
+			Proxmox.Utils.authClear();
+
+			let loginForm = this.lookupReference('loginForm');
+			loginForm.mask(gettext('OpenID login - please wait...'), 'x-mask-loading');
+
+			let redirect_url = location.origin;
+
+			Proxmox.Utils.API2Request({
+			    url: '/api2/extjs/access/openid/login',
+			    params: {
+				state: param.state,
+				code: param.code,
+				"redirect-url": redirect_url,
+			    },
+			    method: 'POST',
+			    failure: function(response) {
+				loginForm.unmask();
+				Ext.MessageBox.alert(
+				    gettext('Error'),
+				    gettext('Login failed. Please try again<br>Error: ' + response.htmlStatus),
+				    function() {
+					window.location = redirect_url;
+				    },
+				);
+			    },
+			    success: function(response, options) {
+				loginForm.unmask();
+				let data = response.result.data;
+				history.replaceState(null, '', redirect_url);
+				me.success(data);
+			    },
+			});
+		    }
 		},
 	    },
 	},
@@ -217,6 +305,10 @@ Ext.define('PVE.window.LoginWindow', {
 		itemId: 'usernameField',
 		reference: 'usernameField',
 		stateId: 'login-username',
+		bind: {
+		    visible: "{!openid}",
+		    disabled: "{openid}",
+		},
 	    },
 	    {
 		xtype: 'textfield',
@@ -224,6 +316,10 @@ Ext.define('PVE.window.LoginWindow', {
 		fieldLabel: gettext('Password'),
 		name: 'password',
 		reference: 'passwordField',
+		bind: {
+		    visible: "{!openid}",
+		    disabled: "{openid}",
+		},
 	    },
 	    {
 		xtype: 'pmxRealmComboBox',
@@ -248,9 +344,14 @@ Ext.define('PVE.window.LoginWindow', {
 		labelWidth: 250,
 		labelAlign: 'right',
 		submitValue: false,
+		bind: {
+		    visible: "{!openid}",
+		},
 	    },
 	    {
-		text: gettext('Login'),
+		bind: {
+		    text: "{button_text}",
+		},
 		reference: 'loginButton',
 	    },
 	],
-- 
2.30.2





More information about the pve-devel mailing list