You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2020/06/26 18:27:27 UTC
[cloudstack-primate] branch master updated: iam: account form with
saml option (#170)
This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-primate.git
The following commit(s) were added to refs/heads/master by this push:
new be0db5e iam: account form with saml option (#170)
be0db5e is described below
commit be0db5e8eda8d5e9be17680c0105dcfdaf5998b2
Author: Pearl Dsilva <pe...@gmail.com>
AuthorDate: Fri Jun 26 23:57:20 2020 +0530
iam: account form with saml option (#170)
- New accounts form with option to enable SAML when applicable
- LDAP import form with saml support
- SAML authorisation action form for users
Co-authored-by: Pearl Dsilva <pe...@shapeblue.com>
Co-authored-by: Abhishek Kumar <ab...@gmail.com>
Co-authored-by: Rohit Yadav <ro...@shapeblue.com>
Co-authored-by: davidjumani <dj...@gmail.com>
---
src/config/section/account.js | 3 +-
src/config/section/user.js | 8 +
src/locales/en.json | 2 +
src/views/iam/AddAccount.vue | 419 +++++++++++++++++++++++++++++++++
src/views/iam/AddLdapAccount.vue | 62 ++++-
src/views/iam/ConfigureSamlSsoAuth.vue | 138 +++++++++++
6 files changed, 619 insertions(+), 13 deletions(-)
diff --git a/src/config/section/account.js b/src/config/section/account.js
index f465523..6c973d9 100644
--- a/src/config/section/account.js
+++ b/src/config/section/account.js
@@ -54,7 +54,8 @@ export default {
icon: 'plus',
label: 'label.add.account',
listView: true,
- args: ['username', 'password', 'confirmpassword', 'email', 'firstname', 'lastname', 'domainid', 'account', 'roleid', 'timezone', 'networkdomain']
+ popup: true,
+ component: () => import('@/views/iam/AddAccount.vue')
},
{
api: 'ldapCreateAccount',
diff --git a/src/config/section/user.js b/src/config/section/user.js
index 689b229..176e36f 100644
--- a/src/config/section/user.js
+++ b/src/config/section/user.js
@@ -71,6 +71,14 @@ export default {
show: (record) => { return record.state === 'enabled' }
},
{
+ api: 'authorizeSamlSso',
+ icon: 'form',
+ label: 'Configure SAML SSO Authorization',
+ dataView: true,
+ popup: true,
+ component: () => import('@/views/iam/ConfigureSamlSsoAuth.vue')
+ },
+ {
api: 'deleteUser',
icon: 'delete',
label: 'label.action.delete.user',
diff --git a/src/locales/en.json b/src/locales/en.json
index 7008ce0..9626d59 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -1659,6 +1659,8 @@
"label.rule.number": "Rule Number",
"label.rules": "Rules",
"label.running": "Running VMs",
+"label.saml.disable": "SAML Disable",
+"label.saml.enable": "SAML Enable",
"label.s3.access.key": "Access Key",
"label.s3.bucket": "Bucket",
"label.s3.connection.timeout": "Connection Timeout",
diff --git a/src/views/iam/AddAccount.vue b/src/views/iam/AddAccount.vue
new file mode 100644
index 0000000..2c9130d
--- /dev/null
+++ b/src/views/iam/AddAccount.vue
@@ -0,0 +1,419 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+<template>
+ <div class="form-layout">
+ <a-spin :spinning="loading">
+ <a-form :form="form" :loading="loading" @submit="handleSubmit" layout="vertical">
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.role') }}
+ <a-tooltip :title="apiParams.roleid.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-select
+ v-decorator="['roleid', {
+ initialValue: selectedRole,
+ rules: [{ required: true, message: $t('message.error.select') }] }]"
+ :loading="roleLoading"
+ :placeholder="apiParams.roleid.description">
+ <a-select-option v-for="role in roles" :key="role.id">
+ {{ role.name + ' (' + role.type + ')' }}
+ </a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.username') }}
+ <a-tooltip :title="apiParams.username.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input
+ v-decorator="['username', {
+ rules: [{ required: true, message: $t('message.error.required.input') }]
+ }]"
+ :placeholder="apiParams.username.description" />
+ </a-form-item>
+ <a-row :gutter="12">
+ <a-col :md="24" :lg="12">
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.password') }}
+ <a-tooltip :title="apiParams.password.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input-password
+ v-decorator="['password', {
+ rules: [{ required: true, message: $t('message.error.required.input') }]
+ }]"
+ :placeholder="apiParams.password.description"/>
+ </a-form-item>
+ </a-col>
+ <a-col :md="24" :lg="12">
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.confirmpassword') }}
+ <a-tooltip :title="apiParams.password.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input-password
+ v-decorator="['confirmpassword', {
+ rules: [
+ { required: true, message: $t('message.error.required.input') },
+ { validator: validateConfirmPassword }
+ ]
+ }]"
+ :placeholder="apiParams.password.description"/>
+ </a-form-item>
+ </a-col>
+ </a-row>
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.email') }}
+ <a-tooltip :title="apiParams.email.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input
+ v-decorator="['email', {
+ rules: [{ required: true, message: $t('message.error.required.input') }]
+ }]"
+ :placeholder="apiParams.email.description" />
+ </a-form-item>
+ <a-row :gutter="12">
+ <a-col :md="24" :lg="12">
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.firstname') }}
+ <a-tooltip :title="apiParams.firstname.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input
+ v-decorator="['firstname', {
+ rules: [{ required: true, message: $t('message.error.required.input') }]
+ }]"
+ :placeholder="apiParams.firstname.description" />
+ </a-form-item>
+ </a-col>
+ <a-col :md="24" :lg="12">
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.lastname') }}
+ <a-tooltip :title="apiParams.lastname.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input
+ v-decorator="['lastname', {
+ rules: [{ required: true, message: $t('message.error.required.input') }]
+ }]"
+ :placeholder="apiParams.lastname.description" />
+ </a-form-item>
+ </a-col>
+ </a-row>
+ <a-form-item v-if="this.isAdminOrDomainAdmin()">
+ <span slot="label">
+ {{ $t('label.domain') }}
+ <a-tooltip :title="apiParams.domainid.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-select
+ :loading="domainLoading"
+ v-decorator="['domainid', {
+ initialValue: selectedDomain,
+ rules: [{ required: true, message: $t('message.error.select') }] }]"
+ :placeholder="apiParams.domainid.description">
+ <a-select-option v-for="domain in domainsList" :key="domain.id">
+ {{ domain.name }}
+ </a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.account') }}
+ <a-tooltip :title="apiParams.account.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input v-decorator="['account']" :placeholder="apiParams.account.description" />
+ </a-form-item>
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.timezone') }}
+ <a-tooltip :title="apiParams.timezone.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-select
+ showSearch
+ v-decorator="['timezone']"
+ :loading="timeZoneLoading">
+ <a-select-option v-for="opt in timeZoneMap" :key="opt.id">
+ {{ opt.name || opt.description }}
+ </a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item>
+ <span slot="label">
+ {{ $t('label.networkdomain') }}
+ <a-tooltip :title="apiParams.networkdomain.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-input
+ v-decorator="['networkdomain']"
+ :placeholder="apiParams.networkdomain.description" />
+ </a-form-item>
+ <div v-if="'authorizeSamlSso' in $store.getters.apis">
+ <a-form-item :label="$t('label.samlenable')">
+ <a-switch v-decorator="['samlenable']" @change="checked => { this.samlEnable = checked }" />
+ </a-form-item>
+ <a-form-item v-if="samlEnable">
+ <span slot="label">
+ {{ $t('label.samlentity') }}
+ <a-tooltip :title="apiParams.entityid.description">
+ <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+ </a-tooltip>
+ </span>
+ <a-select
+ v-decorator="['samlentity', {
+ initialValue: selectedIdp,
+ }]"
+ :loading="idpLoading">
+ <a-select-option v-for="(idp, idx) in idps" :key="idx">
+ {{ idp.orgName }}
+ </a-select-option>
+ </a-select>
+ </a-form-item>
+ </div>
+ <div :span="24" class="action-button">
+ <a-button @click="closeAction">{{ this.$t('Cancel') }}</a-button>
+ <a-button :loading="loading" type="primary" @click="handleSubmit">{{ this.$t('OK') }}</a-button>
+ </div>
+ </a-form>
+ </a-spin>
+ </div>
+</template>
+<script>
+import { api } from '@/api'
+import { timeZone } from '@/utils/timezone'
+import debounce from 'lodash/debounce'
+
+export default {
+ name: 'AddAccountForm',
+ data () {
+ this.fetchTimeZone = debounce(this.fetchTimeZone, 800)
+ return {
+ loading: false,
+ domainLoading: false,
+ domainsList: [],
+ selectedDomain: '',
+ roleLoading: false,
+ roles: [],
+ selectedRole: '',
+ timeZoneLoading: false,
+ timeZoneMap: [],
+ samlEnable: false,
+ idpLoading: false,
+ idps: [],
+ selectedIdp: ''
+ }
+ },
+ beforeCreate () {
+ this.form = this.$form.createForm(this)
+ this.apiConfig = this.$store.getters.apis.createAccount || {}
+ this.apiParams = {}
+ this.apiConfig.params.forEach(param => {
+ this.apiParams[param.name] = param
+ })
+ this.apiConfig = this.$store.getters.apis.authorizeSamlSso || {}
+ this.apiConfig.params.forEach(param => {
+ this.apiParams[param.name] = param
+ })
+ },
+ mounted () {
+ this.fetchData()
+ },
+ methods: {
+ fetchData () {
+ this.fetchDomains()
+ this.fetchRoles()
+ this.fetchTimeZone()
+ if ('listIdps' in this.$store.getters.apis) {
+ this.fetchIdps()
+ }
+ },
+ isAdminOrDomainAdmin () {
+ return ['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype)
+ },
+ isValidValueForKey (obj, key) {
+ return key in obj && obj[key] != null
+ },
+ validateConfirmPassword (rule, value, callback) {
+ if (!value || value.length === 0) {
+ callback()
+ } else if (rule.field === 'confirmpassword') {
+ const form = this.form
+ const messageConfirm = this.$t('error.password.not.match')
+ const passwordVal = form.getFieldValue('password')
+ if (passwordVal && passwordVal !== value) {
+ callback(messageConfirm)
+ } else {
+ callback()
+ }
+ } else {
+ callback()
+ }
+ },
+ fetchDomains () {
+ this.domainLoading = true
+ api('listDomains', {
+ listAll: true,
+ details: 'min'
+ }).then(response => {
+ this.domainsList = response.listdomainsresponse.domain || []
+ this.selectedDomain = this.domainsList[0].id || ''
+ }).catch(error => {
+ this.$notification.error({
+ message: `Error ${error.response.status}`,
+ description: error.response.data.errorresponse.errortext
+ })
+ }).finally(() => {
+ this.domainLoading = false
+ })
+ },
+ fetchRoles () {
+ this.roleLoading = true
+ api('listRoles').then(response => {
+ this.roles = response.listrolesresponse.role || []
+ this.selectedRole = this.roles[0].id
+ }).finally(() => {
+ this.roleLoading = false
+ })
+ },
+ fetchTimeZone (value) {
+ this.timeZoneMap = []
+ this.timeZoneLoading = true
+
+ timeZone(value).then(json => {
+ this.timeZoneMap = json
+ this.timeZoneLoading = false
+ })
+ },
+ fetchIdps () {
+ this.idpLoading = true
+ api('listIdps').then(response => {
+ this.idps = response.listidpsresponse.idp || []
+ this.selectedIdp = this.idps[0].id || ''
+ }).finally(() => {
+ this.idpLoading = false
+ })
+ },
+ handleSubmit (e) {
+ e.preventDefault()
+ this.form.validateFields((err, values) => {
+ if (err) {
+ return
+ }
+ this.loading = true
+ const params = {
+ roleid: values.roleid,
+ username: values.username,
+ password: values.password,
+ email: values.email,
+ firstname: values.firstname,
+ lastname: values.lastname,
+ domainid: values.domainid
+ }
+ if (this.isValidValueForKey(values, 'account') && values.account.length > 0) {
+ params.account = values.account
+ }
+ if (this.isValidValueForKey(values, 'timezone') && values.timezone.length > 0) {
+ params.timezone = values.timezone
+ }
+ if (this.isValidValueForKey(values, 'networkdomain') && values.networkdomain.length > 0) {
+ params.networkdomain = values.networkdomain
+ }
+
+ api('createAccount', params).then(response => {
+ this.$emit('refresh-data')
+ this.$notification.success({
+ message: 'Create Account',
+ description: 'Successfully created account ' + params.username
+ })
+ const users = response.createaccountresponse.account.user
+ if (values.samlenable && users) {
+ for (var i = 0; i < users.length; i++) {
+ api('authorizeSamlSso', {
+ enable: values.samlenable,
+ entityid: values.samlentity,
+ userid: users[i].id
+ }).then(response => {
+ this.$notification.success({
+ message: this.$t('samlenable'),
+ description: 'Successfully enabled SAML Authorization'
+ })
+ }).catch(error => {
+ this.$notification.error({
+ message: 'Request Failed',
+ description: (error.response && error.response.headers && error.response.headers['x-description']) || error.message,
+ duration: 0
+ })
+ }).finally(() => {
+ this.loading = false
+ this.closeAction()
+ })
+ }
+ }
+ }).catch(error => {
+ this.$notification.error({
+ message: 'Request Failed',
+ description: (error.response && error.response.headers && error.response.headers['x-description']) || error.message,
+ duration: 0
+ })
+ }).finally(() => {
+ this.loading = false
+ this.closeAction()
+ })
+ })
+ },
+ closeAction () {
+ this.$emit('close-action')
+ }
+ }
+}
+</script>
+<style scoped lang="less">
+ .form-layout {
+ width: 80vw;
+ @media (min-width: 600px) {
+ width: 450px;
+ }
+ }
+ .action-button {
+ text-align: right;
+ button {
+ margin-right: 5px;
+ }
+ }
+</style>
diff --git a/src/views/iam/AddLdapAccount.vue b/src/views/iam/AddLdapAccount.vue
index ce91f0c..e41c11a 100644
--- a/src/views/iam/AddLdapAccount.vue
+++ b/src/views/iam/AddLdapAccount.vue
@@ -112,6 +112,25 @@
:placeholder="apiParams.group.description"
/>
</a-form-item>
+ <div v-if="'authorizeSamlSso' in $store.getters.apis">
+ <a-form-item :label="$t('label.samlenable')">
+ <a-switch v-decorator="['samlEnable']" @change="checked => { this.samlEnable = checked }" />
+ </a-form-item>
+ <a-form-item v-if="samlEnable" :label="$t('label.samlentity')">
+ <a-select
+ v-decorator="['samlEntity', {
+ initialValue: selectedIdp,
+ rules: [{ required: samlEnable, message: `${this.$t('message.error.select')}` }]
+ }]"
+ placeholder="Choose SAML identity provider"
+ :loading="loading">
+ <a-select-option v-for="(idp, idx) in listIdps" :key="idx">
+ {{ idp.orgName }}
+ </a-select-option>
+ </a-select>
+ </a-form-item>
+ </div>
+
<div class="card-footer">
<a-button @click="handleClose">{{ $t('label.close') }}</a-button>
<a-button :loading="loading" type="primary" @click="handleSubmit">{{ $t('label.add') }}</a-button>
@@ -139,6 +158,8 @@ export default {
listDomains: [],
listRoles: [],
timeZoneMap: [],
+ listIdps: [],
+ selectedIdp: '',
filters: [],
selectedFilter: '',
listLoading: false,
@@ -146,7 +167,8 @@ export default {
domainLoading: false,
roleLoading: false,
loading: false,
- searchQuery: undefined
+ searchQuery: undefined,
+ samlEnable: false
}
},
beforeCreate () {
@@ -168,6 +190,7 @@ export default {
this.dataSource = []
this.listDomains = []
this.listRoles = []
+ this.listIdps = []
this.columns = [
{
title: this.$t('label.name'),
@@ -224,11 +247,13 @@ export default {
const [
listTimeZone,
listDomains,
- listRoles
+ listRoles,
+ listIdps
] = await Promise.all([
this.fetchTimeZone(),
this.fetchListDomains(),
- this.fetchListRoles()
+ this.fetchListRoles(),
+ ('listIdps' in this.$store.getters.apis) ? this.fetchIdps() : []
]).catch(error => {
this.$notifyError(error)
}).finally(() => {
@@ -239,6 +264,7 @@ export default {
this.timeZoneMap = listTimeZone && listTimeZone.length > 0 ? listTimeZone : []
this.listDomains = listDomains && listDomains.length > 0 ? listDomains : []
this.listRoles = listRoles && listRoles.length > 0 ? listRoles : []
+ this.listIdps = listIdps && listIdps.length > 0 ? listIdps : []
},
fetchTimeZone (value) {
return new Promise((resolve, reject) => {
@@ -299,6 +325,19 @@ export default {
})
})
},
+ fetchIdps () {
+ return new Promise((resolve, reject) => {
+ api('listIdps').then(json => {
+ const listIdps = json.listidpsresponse.idp || []
+ if (listIdps.length !== 0) {
+ this.selectedIdp = listIdps[0].id
+ }
+ resolve(listIdps)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
handleSubmit (e) {
e.preventDefault()
this.form.validateFields((err, values) => {
@@ -338,13 +377,13 @@ export default {
})
}
this.loading = true
- Promise.all(promises).then(response => {
- for (let i = 0; i < response.length; i++) {
+ Promise.all(promises).then(responses => {
+ for (const response of responses) {
if (apiName === 'ldapCreateAccount' && values.samlEnable) {
const users = response.createaccountresponse.account.user
- const entity = values.samlEntity
- if (users && entity) {
- this.authorizeUsersForSamlSSO(users, entity)
+ const entityId = values.samlEntity
+ if (users && entityId) {
+ this.authorizeUsersForSamlSSO(users, entityId)
}
} else if (apiName === 'importLdapUsers' && response.ldapuserresponse && values.samlEnable) {
this.$notification.error({
@@ -355,12 +394,11 @@ export default {
if (apiName === 'ldapCreateAccount') {
this.$notification.success({
message: this.$t('label.add.ldap.account'),
- description: response[i].createaccountresponse.account.name
+ description: response.createaccountresponse.account.name
})
}
}
}
-
this.$emit('refresh-data')
this.handleClose()
}).catch(error => {
@@ -393,13 +431,13 @@ export default {
handleClose () {
this.$emit('close-action')
},
- authorizeUsersForSamlSSO (users, entity) {
+ authorizeUsersForSamlSSO (users, entityId) {
const promises = []
for (var i = 0; i < users.length; i++) {
const params = {}
params.enable = true
params.userid = users[i].id
- params.entityid = entity
+ params.entityid = entityId
promises.push(new Promise((resolve, reject) => {
api('authorizeSamlSso', params).catch(error => {
reject(error)
diff --git a/src/views/iam/ConfigureSamlSsoAuth.vue b/src/views/iam/ConfigureSamlSsoAuth.vue
new file mode 100644
index 0000000..d8e213a
--- /dev/null
+++ b/src/views/iam/ConfigureSamlSsoAuth.vue
@@ -0,0 +1,138 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+<template>
+ <div class="form-layout">
+ <a-form :form="form" @submit="handleSubmit" layout="vertical" :loading="loading">
+ <a-form-item :label="$t('label.samlenable')">
+ <a-switch
+ v-decorator="['samlEnable', {
+ initialValue: isSamlEnabled
+ }]"
+ :checked="isSamlEnabled"
+ @change="val => { isSamlEnabled = val }"
+ />
+ </a-form-item>
+ <a-form-item :label="$t('label.samlentity')">
+ <a-select
+ v-decorator="['samlEntity', {
+ initialValue: selectedIdp,
+ }]">
+ <a-select-option v-for="(idp, idx) in idps" :key="idx">
+ {{ idp.orgName }}
+ </a-select-option>
+ </a-select>
+ </a-form-item>
+ <div class="card-footer">
+ <a-button @click="handleClose">{{ $t('Close') }}</a-button>
+ <a-button :loading="loading" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
+ </div>
+ </a-form>
+ </div>
+</template>
+<script>
+import { api } from '@/api'
+export default {
+ name: 'ConfigureSamlSsoAuth',
+ props: {
+ resource: {
+ type: Object,
+ required: true
+ }
+ },
+ data () {
+ return {
+ selectedIdp: '',
+ idps: [],
+ isSamlEnabled: false,
+ loading: false
+ }
+ },
+ beforeCreate () {
+ this.form = this.$form.createForm(this)
+ },
+ mounted () {
+ this.fetchData()
+ },
+ methods: {
+ fetchData () {
+ this.IsUserSamlAuthorized()
+ this.loading = true
+ api('listIdps').then(response => {
+ this.idps = response.listidpsresponse.idp || []
+ }).finally(() => {
+ this.loading = false
+ })
+ },
+ IsUserSamlAuthorized () {
+ api('listSamlAuthorization', {
+ userid: this.resource.id
+ }).then(response => {
+ this.isSamlEnabled = response.listsamlauthorizationsresponse.samlauthorization[0].status || false
+ this.selectedIdp = response.listsamlauthorizationsresponse.samlauthorization[0].idpid || ''
+ })
+ },
+ handleClose () {
+ this.$emit('close-action')
+ },
+ handleSubmit (e) {
+ e.preventDefault()
+ this.form.validateFields((err, values) => {
+ if (err) {
+ return
+ }
+ api('authorizeSamlSso', {
+ enable: values.samlEnable,
+ userid: this.resource.id,
+ entityid: values.samlEntity
+ }).then(response => {
+ this.$notification.success({
+ message: values.samlEnable ? this.$t('label.saml.enable') : this.$t('label.saml.disable'),
+ description: values.samlEnable ? `Successfully enabled SAML Authorization for ${this.resource.username}`
+ : `Successfully disabled SAML Authorization for ${this.resource.username}`
+ })
+ }).catch(error => {
+ this.$notification.error({
+ message: 'Request Failed',
+ description: (error.response && error.response.headers && error.response.headers['x-description']) || error.message,
+ duration: 0
+ })
+ }).finally(() => {
+ this.loading = false
+ this.handleClose()
+ })
+ })
+ }
+ }
+}
+</script>
+<style scoped lang="less">
+.form-layout {
+ width: 75vw;
+
+ @media (min-width: 700px) {
+ width: 40vw;
+ }
+}
+.card-footer {
+ text-align: right;
+
+ button + button {
+ margin-left: 8px;
+ }
+}
+</style>