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/08 09:50:46 UTC
[cloudstack] 01/03: Added UI changes and permissions
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 4bc15cd69833d6ba6fb3fae48621c89dc1817cd9
Author: Harikrishna Patnala <ha...@gmail.com>
AuthorDate: Mon Nov 7 15:12:43 2022 +0530
Added UI changes and permissions
---
.../cloudstack/api/response/UserResponse.java | 12 ++++
.../resources/META-INF/db/schema-41710to41800.sql | 48 +++++++++++++-
...ListUserTwoFactorAuthenticatorProvidersCmd.java | 2 +
.../auth/SetupUserTwoFactorAuthenticationCmd.java | 17 ++++-
...ValidateUserTwoFactorAuthenticationCodeCmd.java | 2 +
.../api/query/dao/UserAccountJoinDaoImpl.java | 1 +
.../com/cloud/api/query/vo/UserAccountJoinVO.java | 7 ++
.../java/com/cloud/user/AccountManagerImpl.java | 48 +++++++++++---
ui/public/locales/en.json | 5 +-
ui/src/config/section/user.js | 26 +++++++-
ui/src/permission.js | 8 +++
ui/src/store/modules/user.js | 4 +-
ui/src/views/auth/Login.vue | 4 +-
ui/src/views/dashboard/TwoFa.vue | 6 +-
ui/src/views/iam/RegisterTwoFactorAuth.vue | 76 ++++++++++++----------
15 files changed, 206 insertions(+), 60 deletions(-)
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UserResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UserResponse.java
index 1c81027f0a8..d521ce3a07d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/UserResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/UserResponse.java
@@ -120,6 +120,10 @@ public class UserResponse extends BaseResponse implements SetResourceIconRespons
@Param(description = "Base64 string representation of the resource icon", since = "4.16.0.0")
ResourceIconResponse icon;
+ @SerializedName(ApiConstants.IS_2FA_ENABLED)
+ @Param(description = "true if user has two factor authentication enabled", since = "4.18.0.0")
+ private Boolean is2FAenabled;
+
@Override
public String getObjectId() {
return this.getId();
@@ -285,4 +289,12 @@ public class UserResponse extends BaseResponse implements SetResourceIconRespons
public void setResourceIconResponse(ResourceIconResponse icon) {
this.icon = icon;
}
+
+ public Boolean Is2FAenabled() {
+ return is2FAenabled;
+ }
+
+ public void set2FAenabled(Boolean is2FAenabled) {
+ this.is2FAenabled = is2FAenabled;
+ }
}
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql b/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
index 4618e2ca03e..67c9729e591 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41710to41800.sql
@@ -52,4 +52,50 @@ ALTER TABLE `cloud`.`vpc`
ALTER TABLE `cloud`.`user` ADD COLUMN `two_factor_authentication_enabled` tinyint NOT NULL DEFAULT 0;
ALTER TABLE `cloud`.`user` ADD COLUMN `key_for_2fa` varchar(255) default NULL;
-ALTER TABLE `cloud`.`user` ADD COLUMN `user_2fa_provider` varchar(255) default NULL;
\ No newline at end of file
+ALTER TABLE `cloud`.`user` ADD COLUMN `user_2fa_provider` varchar(255) default NULL;
+
+DROP VIEW IF EXISTS `cloud`.`user_view`;
+CREATE VIEW `cloud`.`user_view` AS
+ select
+ user.id,
+ user.uuid,
+ user.username,
+ user.password,
+ user.firstname,
+ user.lastname,
+ user.email,
+ user.state,
+ user.api_key,
+ user.secret_key,
+ user.created,
+ user.removed,
+ user.timezone,
+ user.registration_token,
+ user.is_registered,
+ user.incorrect_login_attempts,
+ user.source,
+ user.default,
+ account.id account_id,
+ account.uuid account_uuid,
+ account.account_name account_name,
+ account.type account_type,
+ account.role_id account_role_id,
+ domain.id domain_id,
+ domain.uuid domain_uuid,
+ domain.name domain_name,
+ domain.path domain_path,
+ async_job.id job_id,
+ async_job.uuid job_uuid,
+ async_job.job_status job_status,
+ async_job.account_id job_account_id,
+ user.two_factor_authentication_enabled two_factor_authentication_enabled
+ from
+ `cloud`.`user`
+ inner join
+ `cloud`.`account` ON user.account_id = account.id
+ inner join
+ `cloud`.`domain` ON account.domain_id = domain.id
+ left join
+ `cloud`.`async_job` ON async_job.instance_id = user.id
+ and async_job.instance_type = 'User'
+ and async_job.job_status = 0;
\ No newline at end of file
diff --git a/server/src/main/java/com/cloud/api/auth/ListUserTwoFactorAuthenticatorProvidersCmd.java b/server/src/main/java/com/cloud/api/auth/ListUserTwoFactorAuthenticatorProvidersCmd.java
index aa82061ac16..f16ddf1ce5a 100644
--- a/server/src/main/java/com/cloud/api/auth/ListUserTwoFactorAuthenticatorProvidersCmd.java
+++ b/server/src/main/java/com/cloud/api/auth/ListUserTwoFactorAuthenticatorProvidersCmd.java
@@ -18,6 +18,7 @@ package com.cloud.api.auth;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
+import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
@@ -32,6 +33,7 @@ import java.util.List;
@APICommand(name = ListUserTwoFactorAuthenticatorProvidersCmd.APINAME,
description = "Lists user two factor authenticator providers",
+ authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User},
responseObject = UserTwoFactorAuthenticatorProviderResponse.class, since = "4.18.0")
public class ListUserTwoFactorAuthenticatorProvidersCmd extends BaseCmd {
diff --git a/server/src/main/java/com/cloud/api/auth/SetupUserTwoFactorAuthenticationCmd.java b/server/src/main/java/com/cloud/api/auth/SetupUserTwoFactorAuthenticationCmd.java
index 5ef0341662c..055d84c816b 100644
--- a/server/src/main/java/com/cloud/api/auth/SetupUserTwoFactorAuthenticationCmd.java
+++ b/server/src/main/java/com/cloud/api/auth/SetupUserTwoFactorAuthenticationCmd.java
@@ -17,18 +17,21 @@
package com.cloud.api.auth;
import com.cloud.user.AccountManager;
+import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserTwoFactorAuthenticationSetupResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import javax.inject.Inject;
-@APICommand(name = SetupUserTwoFactorAuthenticationCmd.APINAME, description = "Setup the 2fa for the user.", requestHasSensitiveInfo = false,
+@APICommand(name = SetupUserTwoFactorAuthenticationCmd.APINAME, description = "Setup the 2fa for the user.", authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User}, requestHasSensitiveInfo = false,
responseObject = UserTwoFactorAuthenticationSetupResponse.class, entityType = {}, since = "4.18.0")
public class SetupUserTwoFactorAuthenticationCmd extends BaseCmd {
@@ -48,6 +51,9 @@ public class SetupUserTwoFactorAuthenticationCmd extends BaseCmd {
@Parameter(name = ApiConstants.ENABLE, type = CommandType.BOOLEAN, description = "Enabled by default, provide false to disable 2FA")
private Boolean enable;
+ @Parameter(name = ApiConstants.USER_ID, type = CommandType.STRING, entityType = UserResponse.class, description = "optional: the id of the user for which 2FA has to be disabled")
+ private Long userId;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -60,6 +66,10 @@ public class SetupUserTwoFactorAuthenticationCmd extends BaseCmd {
return enable == null ? true : enable;
}
+ public Long getUserId() {
+ return userId;
+ }
+
@Override
public void execute() throws ServerApiException {
UserTwoFactorAuthenticationSetupResponse response = accountManager.setupUserTwoFactorAuthentication(this);
@@ -78,4 +88,9 @@ public class SetupUserTwoFactorAuthenticationCmd extends BaseCmd {
return CallContext.current().getCallingAccount().getId();
}
+ @Override
+ public ApiCommandResourceType getApiResourceType() {
+ return ApiCommandResourceType.User;
+ }
+
}
diff --git a/server/src/main/java/com/cloud/api/auth/ValidateUserTwoFactorAuthenticationCodeCmd.java b/server/src/main/java/com/cloud/api/auth/ValidateUserTwoFactorAuthenticationCodeCmd.java
index a3405761eac..67d13370819 100644
--- a/server/src/main/java/com/cloud/api/auth/ValidateUserTwoFactorAuthenticationCodeCmd.java
+++ b/server/src/main/java/com/cloud/api/auth/ValidateUserTwoFactorAuthenticationCodeCmd.java
@@ -21,6 +21,7 @@ import com.cloud.api.response.ApiResponseSerializer;
import com.cloud.exception.CloudAuthenticationException;
import com.cloud.user.AccountManager;
import com.cloud.user.UserAccount;
+import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
@@ -44,6 +45,7 @@ import java.util.List;
import java.util.Map;
@APICommand(name = ValidateUserTwoFactorAuthenticationCodeCmd.APINAME, description = "Checks the 2fa code for the user.", requestHasSensitiveInfo = false,
+ authorized = {RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User},
responseObject = SuccessResponse.class, entityType = {}, since = "4.18.0")
public class ValidateUserTwoFactorAuthenticationCodeCmd extends BaseCmd implements APIAuthenticator {
diff --git a/server/src/main/java/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java
index 8d06bcd0a26..ee6e08d69db 100644
--- a/server/src/main/java/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/UserAccountJoinDaoImpl.java
@@ -72,6 +72,7 @@ public class UserAccountJoinDaoImpl extends GenericDaoBase<UserAccountJoinVO, Lo
userResponse.setApiKey(usr.getApiKey());
userResponse.setSecretKey(usr.getSecretKey());
userResponse.setIsDefault(usr.isDefault());
+ userResponse.set2FAenabled(usr.isTwoFactorAuthenticationEnabled());
// set async job
if (usr.getJobId() != null) {
diff --git a/server/src/main/java/com/cloud/api/query/vo/UserAccountJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/UserAccountJoinVO.java
index 2c6a5060076..4b73fa58ed6 100644
--- a/server/src/main/java/com/cloud/api/query/vo/UserAccountJoinVO.java
+++ b/server/src/main/java/com/cloud/api/query/vo/UserAccountJoinVO.java
@@ -130,6 +130,9 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I
@Enumerated(value = EnumType.STRING)
private User.Source source;
+ @Column(name = "two_factor_authentication_enabled")
+ boolean twoFactorAuthenticationEnabled;
+
public UserAccountJoinVO() {
}
@@ -274,4 +277,8 @@ public class UserAccountJoinVO extends BaseViewVO implements InternalIdentity, I
public User.Source getSource() {
return source;
}
+
+ public boolean isTwoFactorAuthenticationEnabled() {
+ return twoFactorAuthenticationEnabled;
+ }
}
diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
index 3c2fbe50a2a..40cd5a8d7fb 100644
--- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
@@ -3197,42 +3197,72 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
Account caller = CallContext.current().getCallingAccount();
Account owner = _accountService.getActiveAccountById(caller.getId());
- checkAccess(caller, null, true, owner);
-
UserTwoFactorAuthenticationSetupResponse response = new UserTwoFactorAuthenticationSetupResponse();
if (cmd.getEnable()) {
+ checkAccess(caller, null, true, owner);
+ Long userId = CallContext.current().getCallingUserId();
+
if (StringUtils.isEmpty(providerName)) {
throw new InvalidParameterValueException("Provider name is mandatory to setup 2FA");
}
UserTwoFactorAuthenticator provider = getUserTwoFactorAuthenticationProvider(providerName);
- UserAccountVO userAccount = _userAccountDao.findById(owner.getId());
+ UserAccountVO userAccount = _userAccountDao.findById(userId);
+ UserVO userVO = _userDao.findById(userId);
String code = provider.setup2FAKey(userAccount);
UserVO user = _userDao.createForUpdate();
user.setKeyFor2fa(code);
user.setUser2faProvider(provider.getName());
user.setTwoFactorAuthenticationEnabled(true);
- _userDao.update(owner.getId(), user);
+ _userDao.update(userId, user);
- response.setId(owner.getUuid());
- response.setUsername(owner.getName());
+ response.setId(userVO.getUuid());
+ response.setUsername(userAccount.getUsername());
response.setSecretCode(code);
return response;
}
+ // Admin can disable 2FA of the users
+ UserVO userVO = null;
+ Long userId = cmd.getUserId();
+ if (userId != null) {
+ userVO = validateUser(userId, caller.getDomainId());
+ if (userVO == null) {
+ throw new InvalidParameterValueException("Unable to find user= " + userVO.getUsername() + " in domain id = " + caller.getDomainId());
+ }
+ owner = _accountService.getActiveAccountById(userId);
+ } else {
+ userVO = _userDao.findById(caller.getId());
+ }
+ checkAccess(caller, null, true, owner);
+
UserVO user = _userDao.createForUpdate();
user.setKeyFor2fa(null);
user.setUser2faProvider(null);
user.setTwoFactorAuthenticationEnabled(false);
- _userDao.update(owner.getId(), user);
+ _userDao.update(userVO.getId(), user);
- response.setId(owner.getUuid());
- response.setUsername(owner.getName());
+ response.setId(userVO.getUuid());
+ response.setUsername(userVO.getUsername());
return response;
}
+ private UserVO validateUser(Long userId, Long domainId) {
+ UserVO user = null;
+ if (userId != null) {
+ user = _userDao.findById(userId);
+ if (user == null) {
+ throw new InvalidParameterValueException("Invalid user ID provided");
+ }
+ if (_accountDao.findById(user.getAccountId()).getDomainId() != domainId) {
+ throw new InvalidParameterValueException("User doesn't belong to the specified account or domain");
+ }
+ }
+ return user;
+ }
+
public UserTwoFactorAuthenticator getUserTwoFactorAuthenticator(final String name) {
if (StringUtils.isEmpty(name)) {
throw new CloudRuntimeException("Invalid UserTwoFactorAuthenticator name provided");
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 508c6f93098..aa2ac1c9336 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -136,7 +136,8 @@
"label.action.reboot.systemvm": "Reboot system VM",
"label.action.recover.volume": "Recover volume",
"label.action.recurring.snapshot": "Recurring snapshots",
-"label.action.register.2FA.user.auth": "Register user for Two Factor Authentication",
+"label.action.register.2FA.user.auth": "Register user Two Factor Authentication",
+"label.action.disable.2FA.user.auth": "Disable user Two Factor Authentication",
"label.action.register.iso": "Register ISO",
"label.action.register.template": "Register template from URL",
"label.action.release.ip": "Release IP",
@@ -895,6 +896,7 @@
"label.iqn": "Target IQN",
"label.is.in.progress": "is in progress",
"label.is.shared": "Is shared",
+"label.is2faenabled": "Is 2FA enabled",
"label.isadvanced": "Show advanced settings",
"label.iscsi": "iSCSI",
"label.iscustomized": "Custom disk size",
@@ -1944,6 +1946,7 @@
"message.action.destroy.instance.with.backups": "Please confirm that you want to destroy the instance. There may be backups associated with the instance which will not be deleted.",
"message.action.destroy.systemvm": "Please confirm that you want to destroy the System VM.",
"message.action.destroy.volume": "Please confirm that you want to destroy the volume.",
+"message.action.disable.2FA.user.auth": "Please confirm that you want to disable user Two factor authentication.",
"message.action.disable.cluster": "Please confirm that you want to disable this cluster.",
"message.action.disable.physical.network": "Please confirm that you want to disable this physical network.",
"message.action.disable.pod": "Please confirm that you want to disable this pod.",
diff --git a/ui/src/config/section/user.js b/ui/src/config/section/user.js
index 5a298134839..cb86d395396 100644
--- a/ui/src/config/section/user.js
+++ b/ui/src/config/section/user.js
@@ -26,7 +26,7 @@ export default {
hidden: true,
permission: ['listUsers'],
columns: ['username', 'state', 'firstname', 'lastname', 'email', 'account'],
- details: ['username', 'id', 'firstname', 'lastname', 'email', 'usersource', 'timezone', 'rolename', 'roletype', 'account', 'domain', 'created'],
+ details: ['username', 'id', 'firstname', 'lastname', 'email', 'usersource', 'timezone', 'rolename', 'roletype', 'is2faenabled', 'account', 'domain', 'created'],
tabs: [
{
name: 'details',
@@ -107,14 +107,34 @@ export default {
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/ConfigureSamlSsoAuth.vue')))
},
{
- // update API name
- api: 'updateUser',
+ api: 'setupUserTwoFactorAuthentication',
icon: 'scan-outlined',
label: 'label.action.register.2FA.user.auth',
dataView: true,
popup: true,
+ show: (record, store) => {
+ return (record.is2faenabled === false && record.id === store.userInfo.id)
+ },
component: shallowRef(defineAsyncComponent(() => import('@/views/iam/RegisterTwoFactorAuth.vue')))
},
+ {
+ api: 'setupUserTwoFactorAuthentication',
+ icon: 'scan-outlined',
+ label: 'label.action.disable.2FA.user.auth',
+ message: 'message.action.disable.2FA.user.auth',
+ dataView: true,
+ groupAction: true,
+ popup: true,
+ args: ['enable'],
+ mapping: {
+ enable: {
+ value: (record) => { return false }
+ }
+ },
+ show: (record, store) => {
+ return (record.is2faenabled === true) && (record.id === store.userInfo.id || ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype))
+ }
+ },
{
api: 'deleteUser',
icon: 'delete-outlined',
diff --git a/ui/src/permission.js b/ui/src/permission.js
index b14b826487c..834d0e098be 100644
--- a/ui/src/permission.js
+++ b/ui/src/permission.js
@@ -60,6 +60,14 @@ router.beforeEach((to, from, next) => {
console.log('hari3')
next({ path: '/dashboard' })
NProgress.done()
+ } else if (to.path === '/2FA') {
+ if (store.getters.twoFaEnabled && !store.getters.loginFlag) {
+ console.log('Do Two-factor authentication')
+ next()
+ } else {
+ next({ path: '/dashboard' })
+ NProgress.done()
+ }
} else {
console.log('hari4')
if (Object.keys(store.getters.apis).length === 0) {
diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js
index 5a83e9bb1da..42c7db72ca3 100644
--- a/ui/src/store/modules/user.js
+++ b/ui/src/store/modules/user.js
@@ -180,9 +180,7 @@ const user = {
commit('SET_CLOUDIAN', {})
commit('SET_DOMAIN_STORE', {})
commit('SET_LOGOUT_FLAG', false)
- // TODO: get value from session and set - currently hard-coding it
- // commit('SET_2FA_ENABLED', (result.is2faenabled === 'true'))
- commit('SET_2FA_ENABLED', true)
+ commit('SET_2FA_ENABLED', (result.is2faenabled === 'true'))
commit('SET_LOGIN_FLAG', false)
notification.destroy()
diff --git a/ui/src/views/auth/Login.vue b/ui/src/views/auth/Login.vue
index 3fd287b7383..4b1f773ddb0 100644
--- a/ui/src/views/auth/Login.vue
+++ b/ui/src/views/auth/Login.vue
@@ -298,12 +298,10 @@ export default {
loginSuccess (res) {
this.$notification.destroy()
this.$store.commit('SET_COUNT_NOTIFY', 0)
- this.$store.commit('SET_LOGIN_FLAG', true)
- console.log(store.getters.twoFaEnabled)
if (store.getters.twoFaEnabled === true) {
this.$router.push({ path: '/2FA' }).catch(() => {})
} else {
- console.log('hari2')
+ this.$store.commit('SET_LOGIN_FLAG', true)
this.$router.push({ path: '/dashboard' }).catch(() => {})
}
},
diff --git a/ui/src/views/dashboard/TwoFa.vue b/ui/src/views/dashboard/TwoFa.vue
index 0f9e6017642..8d9eb5cb6e1 100644
--- a/ui/src/views/dashboard/TwoFa.vue
+++ b/ui/src/views/dashboard/TwoFa.vue
@@ -86,6 +86,9 @@ export default {
api('validateUserTwoFactorAuthenticationCode', { '2facode': values.secretkey }).then(response => {
this.twoFAresponse = true
if (this.twoFAresponse) {
+ this.$notification.destroy()
+ this.$store.commit('SET_COUNT_NOTIFY', 0)
+ this.$store.commit('SET_LOGIN_FLAG', true)
this.$router.push({ path: '/dashboard' }).catch(() => {})
}
console.log(response)
@@ -96,9 +99,6 @@ export default {
})
})
})
-
- // Add logic to set loginFlag to true
- this.$store.dispatch('SetLoginFlag', true)
}
}
}
diff --git a/ui/src/views/iam/RegisterTwoFactorAuth.vue b/ui/src/views/iam/RegisterTwoFactorAuth.vue
index 1c1db3e28cf..67eab5bbefa 100644
--- a/ui/src/views/iam/RegisterTwoFactorAuth.vue
+++ b/ui/src/views/iam/RegisterTwoFactorAuth.vue
@@ -38,43 +38,45 @@
</a-select-option>
</a-select>
</div>
- <div v-if="selectedProvider === 'google'">
- <br />
- <div> {{ $t('message.two.fa.auth.register.account') }} </div>
- <vue-qrious
- class="center-align"
- :value="googleUrl"
- @change="onDataUrlChange"
- />
- </div>
- <div v-else-if="selectedProvider === 'staticpin'">
- <div> <a @click="setup2FAProvider"> {{ $t('message.two.fa.static.pin.part2') }}</a></div>
- </div>
- <div v-else-if="selectedProvider !== null && selectedProvider !== 'staticpin'">
- <div> {{ $t('message.two.fa.static.pin.part1') }} <a @click="setup2FAProvider"> {{ $t('message.two.fa.static.pin.part2') }}</a></div>
- </div>
- <div v-if="selectedProvider">
- <br />
- <h3> {{ $t('label.enter.code') }} </h3>
- <a-form @finish="submitPin" v-ctrl-enter="submitPin" class="container">
- <a-input v-model:value="code" />
- <div :span="24">
- <a-button ref="submit" type="primary" @click="submitPin">{{ $t('label.ok') }}</a-button>
- </div>
- </a-form>
- </div>
+ <div v-if="show2FAdetails">
+ <div v-if="selectedProvider === 'google'">
+ <br />
+ <div> {{ $t('message.two.fa.auth.register.account') }} </div>
+ <vue-qrious
+ class="center-align"
+ :value="googleUrl"
+ @change="onDataUrlChange"
+ />
+ </div>
+ <div v-else-if="selectedProvider === 'staticpin'">
+ <div> <a @click="setup2FAProvider"> {{ $t('message.two.fa.static.pin.part2') }}</a></div>
+ </div>
+ <div v-else-if="selectedProvider !== null && selectedProvider !== 'staticpin'">
+ <div> {{ $t('message.two.fa.static.pin.part1') }} <a @click="setup2FAProvider"> {{ $t('message.two.fa.static.pin.part2') }}</a></div>
+ </div>
+ <div v-if="selectedProvider">
+ <br />
+ <h3> {{ $t('label.enter.code') }} </h3>
+ <a-form @finish="submitPin" v-ctrl-enter="submitPin" class="container">
+ <a-input v-model:value="code" />
+ <div :span="24">
+ <a-button ref="submit" type="primary" @click="submitPin">{{ $t('label.ok') }}</a-button>
+ </div>
+ </a-form>
+ </div>
- <a-modal
- v-if="showPin"
- :visible="showPin"
- :title="$t('label.two.factor.secret')"
- :closable="true"
- :footer="null"
- @cancel="onCloseModal"
- centered
- width="450px">
- <div> {{ pin }} </div>
- </a-modal>
+ <a-modal
+ v-if="showPin"
+ :visible="showPin"
+ :title="$t('label.two.factor.secret')"
+ :closable="true"
+ :footer="null"
+ @cancel="onCloseModal"
+ centered
+ width="450px">
+ <div> {{ pin }} </div>
+ </a-modal>
+ </div>
</a-form>
</div>
</template>
@@ -100,6 +102,7 @@ export default {
pin: '',
code: '',
showPin: false,
+ show2FAdetails: false,
providers: [],
selectedProvider: null
}
@@ -124,6 +127,7 @@ export default {
this.googleUrl = 'otpauth://totp/CloudStack:' + this.username + '?secret=' + this.pin + '&issuer=CloudStack'
}
this.showPin = true
+ this.show2FAdetails = true
}).catch(error => {
this.$notification.error({
message: this.$t('message.request.failed'),