You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ha...@apache.org on 2022/11/27 17:18:40 UTC

[cloudstack] 01/03: Added setup 2FA at login page

This is an automated email from the ASF dual-hosted git repository.

harikrishna pushed a commit to branch 2FA
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit a378431d44487e07eda6dd5ab66c3d0192cc7b94
Author: Harikrishna Patnala <ha...@gmail.com>
AuthorDate: Fri Nov 25 14:32:13 2022 +0530

    Added setup 2FA at login page
---
 server/src/main/java/com/cloud/api/ApiServlet.java |  6 +-
 ui/src/config/router.js                            |  9 +++
 ui/src/permission.js                               |  2 +-
 ui/src/views/auth/Login.vue                        |  2 +
 ui/src/views/dashboard/Dashboard.vue               |  4 +-
 ui/src/views/dashboard/VerifyTwoFa.vue             | 83 ++++++++++++----------
 ui/src/views/iam/RegisterTwoFactorAuth.vue         |  1 +
 7 files changed, 66 insertions(+), 41 deletions(-)

diff --git a/server/src/main/java/com/cloud/api/ApiServlet.java b/server/src/main/java/com/cloud/api/ApiServlet.java
index ef7407062a4..f7b8a4f66ba 100644
--- a/server/src/main/java/com/cloud/api/ApiServlet.java
+++ b/server/src/main/java/com/cloud/api/ApiServlet.java
@@ -35,6 +35,8 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import com.cloud.api.auth.ListUserTwoFactorAuthenticatorProvidersCmd;
+import com.cloud.api.auth.SetupUserTwoFactorAuthenticationCmd;
 import com.cloud.api.auth.ValidateUserTwoFactorAuthenticationCodeCmd;
 import com.cloud.user.UserAccount;
 import org.apache.cloudstack.api.ApiConstants;
@@ -300,7 +302,9 @@ public class ApiServlet extends HttpServlet {
                 s_logger.trace(String.format("new session: %s", session));
             }
 
-            if (!isNew && !command.equalsIgnoreCase(ApiConstants.LIST_IDPS)) {
+            if (!isNew && !command.equalsIgnoreCase(ApiConstants.LIST_IDPS)
+                    && !command.equalsIgnoreCase(ListUserTwoFactorAuthenticatorProvidersCmd.APINAME)
+                    && !command.equalsIgnoreCase(SetupUserTwoFactorAuthenticationCmd.APINAME)) {
                 s_logger.debug("Checking if two factor authentication is enabled, if enabled it will be verified");
                 userId = (Long)session.getAttribute("userid");
                 UserAccount userAccount = accountMgr.getUserAccountById(userId);
diff --git a/ui/src/config/router.js b/ui/src/config/router.js
index a1d5be7522d..e1c83255530 100644
--- a/ui/src/config/router.js
+++ b/ui/src/config/router.js
@@ -316,6 +316,15 @@ export const constantRouterMap = [
     },
     component: () => import('@/views/dashboard/VerifyTwoFa')
   },
+  {
+    path: '/setup2FA',
+    name: 'SetupTwoFaAtLogin',
+    meta: {
+      title: 'label.two.factor.authentication',
+      hidden: true
+    },
+    component: () => import('@/views/dashboard/SetupTwoFaAtLogin')
+  },
   {
     path: '/403',
     component: () => import(/* webpackChunkName: "forbidden" */ '@/views/exception/403')
diff --git a/ui/src/permission.js b/ui/src/permission.js
index 8dbed2e950e..b26242a9159 100644
--- a/ui/src/permission.js
+++ b/ui/src/permission.js
@@ -59,7 +59,7 @@ router.beforeEach((to, from, next) => {
     if (to.path === '/user/login') {
       next({ path: '/dashboard' })
       NProgress.done()
-    } else if (to.path === '/verify2FA') {
+    } else if (to.path === '/verify2FA' || to.path === '/setup2FA') {
       if (store.getters.twoFaEnabled && !store.getters.loginFlag) {
         console.log('Do Two-factor authentication')
         next()
diff --git a/ui/src/views/auth/Login.vue b/ui/src/views/auth/Login.vue
index 0a64fbe3925..e4c52eaded9 100644
--- a/ui/src/views/auth/Login.vue
+++ b/ui/src/views/auth/Login.vue
@@ -300,6 +300,8 @@ export default {
       this.$store.commit('SET_COUNT_NOTIFY', 0)
       if (store.getters.twoFaEnabled === true && store.getters.twoFaProvider !== '') {
         this.$router.push({ path: '/verify2FA' }).catch(() => {})
+      } else if (store.getters.twoFaEnabled === true && store.getters.twoFaProvider === '') {
+        this.$router.push({ path: '/setup2FA' }).catch(() => {})
       } else {
         this.$store.commit('SET_LOGIN_FLAG', true)
         this.$router.push({ path: '/dashboard' }).catch(() => {})
diff --git a/ui/src/views/dashboard/Dashboard.vue b/ui/src/views/dashboard/Dashboard.vue
index e5bab748fb6..ea8e385decb 100644
--- a/ui/src/views/dashboard/Dashboard.vue
+++ b/ui/src/views/dashboard/Dashboard.vue
@@ -36,6 +36,7 @@ import CapacityDashboard from './CapacityDashboard'
 import UsageDashboard from './UsageDashboard'
 import OnboardingDashboard from './OnboardingDashboard'
 import VerifyTwoFa from './VerifyTwoFa'
+import SetupTwoFaAtLogin from './SetupTwoFaAtLogin'
 
 export default {
   name: 'Dashboard',
@@ -43,7 +44,8 @@ export default {
     CapacityDashboard,
     UsageDashboard,
     OnboardingDashboard,
-    VerifyTwoFa
+    VerifyTwoFa,
+    SetupTwoFaAtLogin
   },
   provide: function () {
     return {
diff --git a/ui/src/views/dashboard/VerifyTwoFa.vue b/ui/src/views/dashboard/VerifyTwoFa.vue
index acbd87170a5..9dca8c715da 100644
--- a/ui/src/views/dashboard/VerifyTwoFa.vue
+++ b/ui/src/views/dashboard/VerifyTwoFa.vue
@@ -16,44 +16,42 @@
 // under the License.
 
 <template>
-  <a-form>
-    <img
-      v-if="$config.banner"
-      :style="{
-        width: $config.theme['@banner-width'],
-        height: $config.theme['@banner-height']
-      }"
-      :src="$config.banner"
-      class="user-layout-logo"
-      alt="logo">
-    <h1 style="text-align: center; font-size: 24px; color: gray"> {{ $t('label.two.factor.authentication') }} </h1>
-    <br />
-    <br />
-    <a-form
-      :ref="formRef"
-      :model="form"
-      :rules="rules"
-      @finish="handleSubmit"
-      layout="vertical">
-      <a-form-item name="code" ref="code">
-        <a-input
-          class="center-align"
-          style="width: 400px"
-          v-model:value="form.code"
-          placeholder="xxxxxxx" />
-      </a-form-item>
-      <div :span="24" class="center-align top-padding">
-          <a-button
-            :loading="loading"
-            ref="submit"
-            type="primary"
+  <div class="center">
+    <a-form>
+      <img
+        v-if="$config.banner"
+        :src="$config.banner"
+        class="user-layout-logo"
+        alt="logo">
+      <h1 style="text-align: center; font-size: 24px; color: gray"> {{ $t('label.two.factor.authentication') }} </h1>
+      <br />
+      <br />
+      <a-form
+        :ref="formRef"
+        :model="form"
+        :rules="rules"
+        @finish="handleSubmit"
+        layout="vertical">
+        <a-form-item name="code" ref="code">
+          <a-input
             class="center-align"
-            @click="handleSubmit">{{ $t('label.verify') }}
-          </a-button>
-        </div>
-      <p style="text-align: center" v-html="$t('message.two.fa.auth')"></p>
+            style="width: 400px"
+            v-model:value="form.code"
+            placeholder="xxxxxxx" />
+        </a-form-item>
+        <div :span="24" class="center-align top-padding">
+            <a-button
+              :loading="loading"
+              ref="submit"
+              type="primary"
+              class="center-align"
+              @click="handleSubmit">{{ $t('label.verify') }}
+            </a-button>
+          </div>
+        <p style="text-align: center" v-html="$t('message.two.fa.auth')"></p>
+      </a-form>
     </a-form>
-  </a-form>
+  </div>
 </template>
 <script>
 
@@ -61,7 +59,7 @@ import { api } from '@/api'
 import { ref, reactive, toRaw } from 'vue'
 
 export default {
-  name: 'TwoFa',
+  name: 'VerifyTwoFa',
   data () {
     return {
       twoFAresponse: false
@@ -95,7 +93,6 @@ export default {
             })
             this.$emit('refresh-data')
           }
-          console.log(response)
         }).catch(error => {
           this.$notification.error({
             message: this.$t('message.request.failed'),
@@ -108,6 +105,16 @@ export default {
 }
 </script>
 <style lang="less" scoped>
+  .center {
+    position: fixed;
+    top: 42.5%;
+    left: 50%;
+    -webkit-transform: translate(-50%, -50%);
+
+    background-color: #D3D3D3;
+    padding: 70px 50px 70px 50px;
+    z-index: 100;
+  }
   .center-align {
     display: block;
     margin-left: auto;
diff --git a/ui/src/views/iam/RegisterTwoFactorAuth.vue b/ui/src/views/iam/RegisterTwoFactorAuth.vue
index 122c484eec7..7404a58613a 100644
--- a/ui/src/views/iam/RegisterTwoFactorAuth.vue
+++ b/ui/src/views/iam/RegisterTwoFactorAuth.vue
@@ -23,6 +23,7 @@
       layout="vertical">
       <div class="form-layout form-align" v-ctrl-enter="submitPin">
          <a-select
+          :disabled="twoFAenabled === true"
           v-model:value="selectedProvider"
           optionFilterProp="label"
           :filterOption="(input, option) => {