]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/window/LoginWindow.js
ui: resource tree settings: use the safer hash as bogus submit URL
[pve-manager.git] / www / manager6 / window / LoginWindow.js
index 0f7ae345e6a362d65c33c2aa39cbbab3aa9de2b9..4a07f75bf75dcbe50d6950600dbc281ac1422bd6 100644 (file)
@@ -2,11 +2,26 @@
 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',
 
-       onLogon: function() {
+       onLogon: async function() {
            var me = this;
 
            var form = this.lookupReference('loginForm');
@@ -18,6 +33,32 @@ Ext.define('PVE.window.LoginWindow', {
                return;
            }
 
+           let creds = form.getValues();
+
+           if (this.getViewModel().data.openid === true) {
+               const redirectURL = location.origin;
+               Proxmox.Utils.API2Request({
+                   url: '/api2/extjs/access/openid/auth-url',
+                   params: {
+                       realm: creds.realm,
+                       "redirect-url": redirectURL,
+                   },
+                   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.') + `<br>${resp.htmlStatus}`,
+                       );
+                   },
+               });
+               return;
+           }
+
            view.el.mask(gettext('Please wait...'), 'x-mask-loading');
 
            // set or clear username
@@ -29,31 +70,70 @@ Ext.define('PVE.window.LoginWindow', {
            }
            sp.set(saveunField.getStateId(), saveunField.getValue());
 
-           form.submit({
-               failure: function(f, resp){
-                   me.failure(resp);
-               },
-               success: function(f, resp){
-                   view.el.unmask();
+           try {
+               // Request updated authentication mechanism:
+               creds['new-format'] = 1;
 
-                   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);
-                       } else {
-                           me.perform_otp();
-                       }
+               let resp = await Proxmox.Async.api2({
+                   url: '/api2/extjs/access/ticket',
+                   params: creds,
+                   method: 'POST',
+               });
+
+               let data = resp.result.data;
+               if (data.ticket.startsWith("PVE:!tfa!")) {
+                   // Store first factor login information first:
+                   data.LoggedOut = true;
+                   Proxmox.Utils.setAuthData(data);
+
+                   data = await me.performTFAChallenge(data);
+
+                   // Fill in what we copy over from the 1st factor:
+                   data.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
+                   data.username = Proxmox.UserName;
+                   me.success(data);
+               } else 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);
                    } else {
-                       me.success(data);
+                       me.perform_otp();
                    }
+               } else {
+                   me.success(data);
                }
+           } catch (error) {
+               me.failure(error);
+           }
+       },
+
+       /* START NEW TFA CODE (pbs copy) */
+       performTFAChallenge: async function(data) {
+           let me = this;
+
+           let userid = data.username;
+           let ticket = data.ticket;
+           let challenge = JSON.parse(decodeURIComponent(
+               ticket.split(':')[1].slice("!tfa!".length),
+           ));
+
+           let resp = await new Promise((resolve, reject) => {
+               Ext.create('Proxmox.window.TfaLoginWindow', {
+                   userid,
+                   ticket,
+                   challenge,
+                   onResolve: value => resolve(value),
+                   onReject: reject,
+               }).show();
            });
 
+           return resp.result.data;
        },
+       /* END NEW TFA CODE (pbs copy) */
+
        failure: function(resp) {
            var me = this;
            var view = me.getView();
@@ -63,9 +143,13 @@ Ext.define('PVE.window.LoginWindow', {
                uf.focus(true, true);
            };
 
-           Ext.MessageBox.alert(gettext('Error'),
-                                gettext("Login failed. Please try again"),
-                                handler);
+           let emsg = gettext("Login failed. Please try again");
+
+           if (resp.failureType === "connect") {
+               emsg = gettext("Connection failure. Network error or Proxmox VE services not running?");
+           }
+
+           Ext.MessageBox.alert(gettext('Error'), emsg, handler);
        },
        success: function(data) {
            var me = this;
@@ -85,7 +169,7 @@ Ext.define('PVE.window.LoginWindow', {
                    Proxmox.LoggedOut = false;
                    Proxmox.Utils.authClear();
                    me.getView().show();
-               }
+               },
            });
            win.show();
        },
@@ -96,12 +180,12 @@ Ext.define('PVE.window.LoginWindow', {
            var msg = Ext.Msg.show({
                title: 'U2F: '+gettext('Verification'),
                message: gettext('Please press the button on your U2F Device'),
-               buttons: []
+               buttons: [],
            });
            var chlg = data.U2FChallenge;
            var key = {
                version: chlg.version,
-               keyHandle: chlg.keyHandle
+               keyHandle: chlg.keyHandle,
            };
            u2f.sign(chlg.appId, chlg.challenge, [key], function(res) {
                msg.close();
@@ -118,10 +202,11 @@ Ext.define('PVE.window.LoginWindow', {
            var me = this;
            var view = me.getView();
            view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-           var params = { response: res };
            Proxmox.Utils.API2Request({
                url: '/api2/extjs/access/tfa',
-               params: params,
+               params: {
+                   response: res,
+               },
                method: 'POST',
                timeout: 5000, // it'll delay both success & failure
                success: function(resp, opts) {
@@ -136,7 +221,7 @@ Ext.define('PVE.window.LoginWindow', {
                failure: function(resp, opts) {
                    Proxmox.Utils.authClear();
                    me.failure(resp);
-               }
+               },
            });
        },
 
@@ -149,7 +234,7 @@ Ext.define('PVE.window.LoginWindow', {
                            pf.focus(false);
                        }
                    }
-               }
+               },
            },
            'field[name=lang]': {
                change: function(f, value) {
@@ -157,13 +242,23 @@ Ext.define('PVE.window.LoginWindow', {
                    Ext.util.Cookies.set('PVELangCookie', value, dt);
                    this.getView().mask(gettext('Please wait...'), 'x-mask-loading');
                    window.location.reload();
-               }
+               },
+           },
+           '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',
            },
-            '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');
@@ -171,35 +266,63 @@ Ext.define('PVE.window.LoginWindow', {
                    var checked = sp.get(checkboxField.getStateId());
                    checkboxField.setValue(checked);
 
-                   if(checked === true) {
+                   if (checked === true) {
                        var username = sp.get(unField.getStateId());
                        unField.setValue(username);
                        var pwField = this.lookupReference('passwordField');
                        pwField.focus();
                    }
-               }
-           }
-       }
+
+                   let auth = Proxmox.Utils.getOpenIDRedirectionAuthorization();
+                   if (auth !== undefined) {
+                       Proxmox.Utils.authClear();
+
+                       let loginForm = this.lookupReference('loginForm');
+                       loginForm.mask(gettext('OpenID login - please wait...'), 'x-mask-loading');
+
+                       const redirectURL = location.origin;
+
+                       Proxmox.Utils.API2Request({
+                           url: '/api2/extjs/access/openid/login',
+                           params: {
+                               state: auth.state,
+                               code: auth.code,
+                               "redirect-url": redirectURL,
+                           },
+                           method: 'POST',
+                           failure: function(response) {
+                               loginForm.unmask();
+                               let error = response.htmlStatus;
+                               Ext.MessageBox.alert(
+                                   gettext('Error'),
+                                   gettext('OpenID login failed, please try again') + `<br>${error}`,
+                                   () => { window.location = redirectURL; },
+                               );
+                           },
+                           success: function(response, options) {
+                               loginForm.unmask();
+                               let data = response.result.data;
+                               history.replaceState(null, '', redirectURL);
+                               me.success(data);
+                           },
+                       });
+                   }
+               },
+           },
+       },
     },
 
     width: 400,
-
     modal: true,
-
     border: false,
-
     draggable: true,
-
     closable: false,
-
     resizable: false,
-
     layout: 'auto',
 
     title: gettext('Proxmox VE Login'),
 
     defaultFocus: 'usernameField',
-
     defaultButton: 'loginButton',
 
     items: [{
@@ -210,7 +333,7 @@ Ext.define('PVE.window.LoginWindow', {
 
        fieldDefaults: {
            labelAlign: 'right',
-           allowBlank: false
+           allowBlank: false,
        },
 
        items: [
@@ -220,18 +343,26 @@ Ext.define('PVE.window.LoginWindow', {
                name: 'username',
                itemId: 'usernameField',
                reference: 'usernameField',
-               stateId: 'login-username'
+               stateId: 'login-username',
+               bind: {
+                   visible: "{!openid}",
+                   disabled: "{openid}",
+               },
            },
            {
                xtype: 'textfield',
                inputType: 'password',
                fieldLabel: gettext('Password'),
                name: 'password',
-               reference: 'passwordField'
+               reference: 'passwordField',
+               bind: {
+                   visible: "{!openid}",
+                   disabled: "{openid}",
+               },
            },
            {
-               xtype: 'pveRealmComboBox',
-               name: 'realm'
+               xtype: 'pmxRealmComboBox',
+               name: 'realm',
            },
            {
                xtype: 'proxmoxLanguageSelector',
@@ -239,8 +370,8 @@ Ext.define('PVE.window.LoginWindow', {
                value: Ext.util.Cookies.get('PVELangCookie') || Proxmox.defaultLang || 'en',
                name: 'lang',
                reference: 'langField',
-               submitValue: false
-           }
+               submitValue: false,
+           },
        ],
        buttons: [
            {
@@ -249,63 +380,19 @@ Ext.define('PVE.window.LoginWindow', {
                name: 'saveusername',
                reference: 'saveunField',
                stateId: 'login-saveusername',
-               labelWidth: 'auto',
+               labelWidth: 250,
                labelAlign: 'right',
-               submitValue: false
+               submitValue: false,
+               bind: {
+                   visible: "{!openid}",
+               },
            },
            {
-               text: gettext('Login'),
-               reference: 'loginButton'
-           }
-       ]
-    }]
+               bind: {
+                   text: "{button_text}",
+               },
+               reference: 'loginButton',
+           },
+       ],
+    }],
  });
-Ext.define('PVE.window.TFALoginWindow', {
-    extend: 'Ext.window.Window',
-
-    modal: true,
-    resizable: false,
-    title: 'Two-Factor Authentication',
-    layout: 'form',
-    defaultButton: 'loginButton',
-    defaultFocus: 'otpField',
-
-    controller: {
-       xclass: 'Ext.app.ViewController',
-       login: function() {
-           var me = this;
-           var view = me.getView();
-           view.onLogin(me.lookup('otpField').getValue());
-           view.close();
-       },
-       cancel: function() {
-           var me = this;
-           var view = me.getView();
-           view.onCancel();
-           view.close();
-       }
-    },
-
-    items: [
-       {
-           xtype: 'textfield',
-           fieldLabel: gettext('Please enter your OTP verification code:'),
-           name: 'otp',
-           itemId: 'otpField',
-           reference: 'otpField',
-           allowBlank: false
-       }
-    ],
-
-    buttons: [
-       {
-           text: gettext('Login'),
-           reference: 'loginButton',
-           handler: 'login'
-       },
-       {
-           text: gettext('Cancel'),
-           handler: 'cancel'
-       }
-    ]
-});