This is an automated email from the ASF dual-hosted git repository. DaanHoogland pushed a commit to branch ghi12583-samlLogin2fa in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 40d68a65c891ae6157efc48d52a0b2da090f3704 Author: Daan Hoogland <[email protected]> AuthorDate: Wed Nov 4 12:12:30 2026 +0100 saml: permit login when 2fa is enabled --- ui/src/permission.js | 2 +- ui/src/store/modules/user.js | 32 +++++++++++++++++----------- ui/src/views/dashboard/SetupTwoFaAtLogin.vue | 1 + ui/src/views/dashboard/VerifyTwoFa.vue | 1 + 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/ui/src/permission.js b/ui/src/permission.js index 266dc992c8d..0036c994f83 100644 --- a/ui/src/permission.js +++ b/ui/src/permission.js @@ -83,7 +83,7 @@ router.beforeEach((to, from, next) => { const isSAML = JSON.parse(Cookies.get('isSAML') || Cookies.get('isSAML', { path: '/client' }) || false) const twoFaEnabled = JSON.parse(Cookies.get('twoFaEnabled') || Cookies.get('twoFaEnabled', { path: '/client' }) || false) const twoFaProvider = Cookies.get('twoFaProvider') || Cookies.get('twoFaProvider', { path: '/client' }) - if (isSAML === true && !store.getters.loginFlag && to.path !== '/dashboard') { + if (isSAML === true && !store.getters.loginFlag) { if (twoFaEnabled === true && twoFaProvider !== '' && twoFaProvider !== undefined) { next({ path: '/verify2FA' }) return diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js index eb3fdccb5e2..72d890a14c9 100644 --- a/ui/src/store/modules/user.js +++ b/ui/src/store/modules/user.js @@ -57,6 +57,20 @@ function setLoginCookies (result) { Cookies.set('username', result.username) } +// Cookies may be set by the UI (host only, path '/') or by the server on SAML login (domain and '/client' path) +function removeCookie (cookieName) { + const paths = ['/', '/client'] + const hostname = window.location.hostname + const domains = [undefined, hostname, `.${hostname}`] + paths.forEach(path => { + domains.forEach(domain => { + const options = { path } + if (domain) options.domain = domain + Cookies.remove(cookieName, options) + }) + }) +} + function processLoginResponse (commit, response) { const result = response.loginresponse || {} setLoginCookies(result) @@ -446,18 +460,7 @@ const user = { }).catch(() => { resolve() }).finally(() => { - const paths = ['/', '/client'] - const hostname = window.location.hostname - const domains = [undefined, hostname, `.${hostname}`] - Object.keys(Cookies.get()).forEach(cookieName => { - paths.forEach(path => { - domains.forEach(domain => { - const options = { path } - if (domain) options.domain = domain - Cookies.remove(cookieName, options) - }) - }) - }) + Object.keys(Cookies.get()).forEach(cookieName => removeCookie(cookieName)) }) }) }, @@ -571,6 +574,11 @@ const user = { SetLoginFlag ({ commit }, loggedIn) { commit('SET_LOGIN_FLAG', loggedIn) }, + Clear2FACookies () { + // SAML login reports the 2FA state in cookies; once verified, a page reload must not ask for 2FA again + removeCookie('twoFaEnabled') + removeCookie('twoFaProvider') + }, SetCustomHypervisorName ({ commit }, name) { commit('SET_CUSTOM_HYPERVISOR_NAME', name) } diff --git a/ui/src/views/dashboard/SetupTwoFaAtLogin.vue b/ui/src/views/dashboard/SetupTwoFaAtLogin.vue index da0d0243034..f9144de410b 100644 --- a/ui/src/views/dashboard/SetupTwoFaAtLogin.vue +++ b/ui/src/views/dashboard/SetupTwoFaAtLogin.vue @@ -287,6 +287,7 @@ export default { this.$notification.destroy() this.$store.commit('SET_COUNT_NOTIFY', 0) this.$store.commit('SET_LOGIN_FLAG', true) + this.$store.dispatch('Clear2FACookies') this.$router.push({ path: '/dashboard' }).catch(() => {}) this.twoFAverified = true diff --git a/ui/src/views/dashboard/VerifyTwoFa.vue b/ui/src/views/dashboard/VerifyTwoFa.vue index 7ec6d08a95b..2ec871d22e4 100644 --- a/ui/src/views/dashboard/VerifyTwoFa.vue +++ b/ui/src/views/dashboard/VerifyTwoFa.vue @@ -102,6 +102,7 @@ export default { this.$notification.destroy() this.$store.commit('SET_COUNT_NOTIFY', 0) this.$store.commit('SET_LOGIN_FLAG', true) + this.$store.dispatch('Clear2FACookies') this.$router.push({ path: '/dashboard' }).catch(() => {}) this.$message.success({
