Merge pull request #68 from isururanawaka/admin-portal-integrated
Tenant portal integrated to admin portal
diff --git a/custos-demo-gateway/.env b/custos-demo-gateway/.env
index 1680335..5819f5c 100644
--- a/custos-demo-gateway/.env
+++ b/custos-demo-gateway/.env
@@ -1,3 +1,3 @@
-VUE_APP_CLIENT_ID="custos-id"
-VUE_APP_CLIENT_SEC="custos-sec"
+VUE_APP_CLIENT_ID="custos-su8y67qnckn5eejwusnz-10000641"
+VUE_APP_CLIENT_SEC="wGo5SGduOofjqFpl3UrR8ngrTafGHMOQDInz3bF0"
VUE_APP_REDIRECT_URI="http://localhost:8080/callback"
diff --git a/custos-demo-gateway/.idea/workspace.xml b/custos-demo-gateway/.idea/workspace.xml
index 90a905e..8d40917 100644
--- a/custos-demo-gateway/.idea/workspace.xml
+++ b/custos-demo-gateway/.idea/workspace.xml
@@ -93,7 +93,8 @@
<workItem from="1599486134588" duration="217546000" />
<workItem from="1601038400517" duration="67420000" />
<workItem from="1602211298031" duration="8699000" />
- <workItem from="1602377149425" duration="3193000" />
+ <workItem from="1602377149425" duration="8790000" />
+ <workItem from="1602505747007" duration="10776000" />
</task>
<servers />
</component>
@@ -113,10 +114,14 @@
<screen x="1680" y="0" width="1920" height="1080" />
</state>
<state x="2378" y="294" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog/1680.0.1920.1080/0.0.1680.1050@1680.0.1920.1080" timestamp="1601162305471" />
- <state x="2305" y="183" width="667" height="729" key="find.popup" timestamp="1601404607112">
+ <state x="2305" y="183" width="667" height="729" key="find.popup" timestamp="1602455803792">
<screen x="1680" y="0" width="1920" height="1080" />
</state>
- <state x="2305" y="183" width="667" height="729" key="find.popup/1680.0.1920.1080/0.0.1680.1050@1680.0.1920.1080" timestamp="1601404607112" />
+ <state x="2305" y="183" width="667" height="729" key="find.popup/1680.0.1920.1080/0.0.1680.1050@1680.0.1920.1080" timestamp="1602455803792" />
+ <state x="2302" y="338" key="git4idea.merge.GitMergeDialog" timestamp="1602545752519">
+ <screen x="1680" y="0" width="1920" height="1080" />
+ </state>
+ <state x="2302" y="338" key="git4idea.merge.GitMergeDialog/1680.0.1920.1080/0.0.1680.1050@1680.0.1920.1080" timestamp="1602545752519" />
<state x="2305" y="241" width="670" height="676" key="search.everywhere.popup" timestamp="1600705258945">
<screen x="1680" y="0" width="1920" height="1080" />
</state>
@@ -127,7 +132,7 @@
<breakpoints>
<line-breakpoint enabled="true" type="javascript">
<url>file://$PROJECT_DIR$/src/components/workspace/Users.vue</url>
- <line>324</line>
+ <line>325</line>
<option name="timeStamp" value="1" />
</line-breakpoint>
</breakpoints>
diff --git a/custos-demo-gateway/1 b/custos-demo-gateway/1
new file mode 100644
index 0000000..400ec05
--- /dev/null
+++ b/custos-demo-gateway/1
@@ -0,0 +1,11 @@
+version: "3.3"
+services:
+ web:
+ image : "apachecustos/custos-demo-gateway-local:latest"
+ ports:
+ - "8080:8080"
+ environment:
+ VUE_APP_CLIENT_ID: 'tenant-id'
+ VUE_APP_CLIENT_SEC: 'tenant-sec'
+ VUE_APP_REDIRECT_URI: 'http://localhost:8080/callback'
+ VUE_APP_CUSTOS_TOKEN_ENDPOINT: 'https://custos.scigap.org/apiserver/identity-management/v1.0.0/token'
diff --git a/custos-demo-gateway/Dockerfile b/custos-demo-gateway/Dockerfile
index 079efea..dd23c75 100644
--- a/custos-demo-gateway/Dockerfile
+++ b/custos-demo-gateway/Dockerfile
@@ -10,8 +10,6 @@
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
-COPY privkey.pem /etc/nginx/privkey.pem
-COPY fullchain.pem /etc/nginx/fullchain.pem
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
EXPOSE 8080 443
diff --git a/custos-demo-gateway/fullchain.pem b/custos-demo-gateway/fullchain.pem
deleted file mode 100644
index e6199f0..0000000
--- a/custos-demo-gateway/fullchain.pem
+++ /dev/null
@@ -1,59 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFdTCCBF2gAwIBAgISA4dFxqSZr9p+QksSmAdoLUZfMA0GCSqGSIb3DQEBCwUA
-MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
-ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA5MjgyMzIzMTNaFw0y
-MDEyMjcyMzIzMTNaMCkxJzAlBgNVBAMTHmRlbW8uZ2F0ZXdheS5jdXN0b3Muc2Np
-Z2FwLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhSqh9FXvM0
-xo8t0oQJ9OGCE9loLbMm2/knZ1ITsRbKTHMczvKkiRBxwgU7kitLDrwolNf5vqQy
-lZrCOjEqda5pi1KwFLNLlYJmV1g+oF5+o0yTTMKUPOnN2+hI9Sjuwwi+/fRMqKsw
-l8SfAum2nDBP9BUuB9MZFThcCm+Cxl55Qz0VXVgzYE+jnNY+BvX4EDaov9mmHkwn
-uXFO6W61k4F/IiD2qhxWmTX8ElwyG8Y6wgNCA/qn5kEPDFCuEXypaVIimDoJyKwD
-VJ84nXlQLrJVLu8Ai6MFKQE6uGOW4tM4zwD9r3zUb8noPJqfwKeE5MEDhQtCA/lh
-PG4UBniquBUCAwEAAaOCAnQwggJwMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
-BggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUUrmz
-/B8YDBArAIE6loWileymPe0wHwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl7/Oo
-7KEwbwYIKwYBBQUHAQEEYzBhMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5pbnQt
-eDMubGV0c2VuY3J5cHQub3JnMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQt
-eDMubGV0c2VuY3J5cHQub3JnLzApBgNVHREEIjAggh5kZW1vLmdhdGV3YXkuY3Vz
-dG9zLnNjaWdhcC5vcmcwTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMB
-AQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEF
-BgorBgEEAdZ5AgQCBIH2BIHzAPEAdwBep3P531bA57U2SH3QSeAyepGaDIShEhKE
-GHWWgXFFWAAAAXTXPeyUAAAEAwBIMEYCIQCOpzkBmQCq4YljG/+IYPhuiTyBTBB6
-lyx25017CC3ZmAIhAKaYWDLX/QCeWOVbWzxqXdcAwwPqSA5SL2mDL3SDePzMAHYA
-B7dcG+V9aP/xsMYdIxXHuuZXfFeUt2ruvGE6GmnTohwAAAF01z3s9gAABAMARzBF
-AiAKxZt6ENgjLqtnzkR0mbEUivqEjqtPcNlC4GN+H1EQlAIhAO1oygawEpMs2TAa
-eMhw3J+bJ4P63IRQEdGerqChRs/HMA0GCSqGSIb3DQEBCwUAA4IBAQA3vvDU3ULX
-VbHWFHug54FkWfhVK49V6eGVRImQOiyTdOoQS6MHKvsedg3aBhj3FwRXQzx7VZ61
-xPthZeNooKNUB184eg+R9L2v1HDT1PyGQgXq9MIVJJzXGw9A9W22o68vbMOp5Pw/
-WC5b+ozYbNz38527XE9KBVoETwrsjIg3q/U/beV9MaLt8EfVobOJXb7JvpTvc3me
-ZI6+y2t9Buj4ebIjHA/Ve1SrWEfGVQNjgz86J8JIg7jPV3lv5Gn49JwILSC53bCK
-GSgYLjGPp8Lwtew8NJDTVzRjwquvxky9smVci2GwGUYAv55l07vvv5dHRYKKFF/z
-gUoZxG3CR60/
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
------END CERTIFICATE-----
diff --git a/custos-demo-gateway/nginx.conf b/custos-demo-gateway/nginx.conf
index c329dbe..ec6850d 100644
--- a/custos-demo-gateway/nginx.conf
+++ b/custos-demo-gateway/nginx.conf
@@ -3,9 +3,10 @@
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
server {
+
listen 80;
- server_name demo.gateway.custos.scigap.org www.demo.gateway.custos.scigap.org;
- return 301 https://demo.gateway.custos.scigap.org$request_uri;
+ server_name testdrive.usecustos.org www.testdrive.usecustos.org;
+ return 301 https://testdrive.usecustos.org$request_uri;
}
server {
@@ -54,4 +55,4 @@
location / {
try_files $uri $uri/ /index.html;
}
-}
\ No newline at end of file
+}
diff --git a/custos-demo-gateway/src/components/404.vue b/custos-demo-gateway/src/components/404.vue
new file mode 100644
index 0000000..037d1cb
--- /dev/null
+++ b/custos-demo-gateway/src/components/404.vue
@@ -0,0 +1,15 @@
+<template>
+ <div class="hello">
+ <h1>(404) Page NotFound</h1>
+ </div>
+</template>
+
+<script>
+ export default {
+ name: "404"
+ }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/custos-demo-gateway/src/components/Callback.vue b/custos-demo-gateway/src/components/Callback.vue
index f4f3800..2c9e02b 100644
--- a/custos-demo-gateway/src/components/Callback.vue
+++ b/custos-demo-gateway/src/components/Callback.vue
@@ -48,7 +48,29 @@
this.tokenEndpoint = "https://custos.scigap.org/apiserver/identity-management/v1.0.0/token"
await this.authenticate()
- await this.$router.push('workspace')
+
+ await this.$router.push('tenants')
+ let username = await this.$store.dispatch('identity/getCurrentUserName')
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ offset: 0, limit: 1, client_id: this.custosId, client_sec: this.custosSec,
+ username: username
+ }
+ let resp = await this.$store.dispatch('user/users', data)
+ if (Array.isArray(resp) && resp.length > 0) {
+ resp.forEach(user => {
+ let dat = {
+ usertoken:accessToken,
+ body: {
+ username: user.username,
+ first_name: user.first_name,
+ last_name: user.last_name,
+ email: user.email,
+ }
+ }
+ this.$store.dispatch('user/updateUserProfile', dat)
+ })
+ }
}
}
</script>
diff --git a/custos-demo-gateway/src/components/Header.vue b/custos-demo-gateway/src/components/Header.vue
index 28106da..c48e97d 100644
--- a/custos-demo-gateway/src/components/Header.vue
+++ b/custos-demo-gateway/src/components/Header.vue
@@ -18,50 +18,52 @@
</template>
<template v-slot:default v-if="user">
- <b-dropdown-item href="#" v-on:click="$router.push('/workspace/profile')">Profile</b-dropdown-item>
+ <b-dropdown-item href="#" v-on:click="loadProfilePage">Profile</b-dropdown-item>
<b-dropdown-item v-on:click="logout">Logout</b-dropdown-item>
</template>
</b-dropdown>
</div>
- <div class="navigation text-left">
- <router-link to="/workspace">
- <b-icon icon="house-door-fill"></b-icon>
- </router-link>
- <router-link to="/workspace/users" v-if="this.isAdmin">Users</router-link>
- <router-link to="/workspace/groups">Groups</router-link>
- <router-link to="/workspace/agents" v-if="this.isAdmin">Service Accounts</router-link>
- <router-link to="/workspace/secrets">Secrets</router-link>
- <router-link to="/workspace/sharings">Sharing</router-link>
- <router-link to="/workspace/logs" v-if="this.isAdmin">logs</router-link>
+ <div class="navigation text-left" v-if="tenantModeactivated">
+ <div class="row">
+ <div class="column">
+ <router-link v-bind:to="{name: 'workspace', params:{tenantId:this.activatedClientId}}">
+ <b-icon icon="house-door-fill"></b-icon>
- <!-- <b-button href="#" variant="link" v-on:click="$router.push('/workspace')">-->
- <!-- <b-icon icon="house-door-fill"></b-icon>-->
- <!-- </b-button>-->
- <!-- <b-button v-if="this.isAdmin" href="#" variant="link" v-on:click="$router.push('/workspace/users')">-->
- <!-- Users-->
- <!-- </b-button>-->
- <!-- <b-button href="#" variant="link" v-on:click="$router.push('/workspace/groups')">-->
- <!-- Groups-->
- <!-- </b-button>-->
- <!-- <b-button v-if="this.isAdmin" href="#" variant="link" v-on:click="$router.push('/workspace/agents')">-->
- <!-- Service Accounts-->
- <!-- </b-button>-->
- <!-- <b-button href="#" variant="link" v-on:click="$router.push('/workspace/secrets')">-->
- <!-- Secrets-->
- <!-- </b-button>-->
- <!-- <b-button href="#" variant="link" v-on:click="$router.push('/workspace/sharings')">-->
- <!-- Sharing-->
- <!-- </b-button>-->
- <!-- <b-button v-if="this.isAdmin" href="#" variant="link" v-on:click="$router.push('/workspace/logs')">-->
- <!-- Logs-->
- <!-- </b-button>-->
+ </router-link>
+ <router-link v-bind:to="{name: 'users', params:{tenantId:this.activatedClientId}}"
+ v-if="this.isAdmin">Users
+ </router-link>
+ <router-link v-bind:to="{name: 'groups', params:{tenantId:this.activatedClientId}}">Groups
+ </router-link>
+ <router-link v-bind:to="{name: 'agents', params:{tenantId:this.activatedClientId}}"
+ v-if="this.isAdmin">Service Accounts
+ </router-link>
+ <router-link v-bind:to="{name: 'secrets', params:{tenantId:this.activatedClientId}}">Secrets
+ </router-link>
+ <router-link v-bind:to="{name: 'sharings', params:{tenantId:this.activatedClientId}}">Sharing
+ </router-link>
+ <router-link v-bind:to="{name: 'logs', params:{tenantId:this.activatedClientId}}"
+ v-if="this.isAdmin">Logs
+ </router-link>
+ </div>
+ <div class="column">
+ <b-button pill variant="success" size="sm" v-on:click="exitTenantExplorer" class="tenant-manager">
+ Tenant
+ Manager
+ </b-button>
+ </div>
+ </div>
+
</div>
+
+
</div>
</template>
<script>
import config from "@/config";
+ import auth from "@/service/auth";
export default {
name: "Header",
@@ -69,7 +71,10 @@
return {
isAdmin: false,
user: null,
- authenticated: false
+ authenticated: false,
+ tenantModeactivated: false,
+ activatedClientId: ''
+
}
},
methods: {
@@ -77,10 +82,15 @@
return this.authenticated
},
async logout() {
- await this.$store.dispatch('identity/logout', {
- client_id: config.value('clientId'),
- client_sec: config.value('clientSec'),
- })
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (!this.tenantModeactivated) {
+ await this.$store.dispatch('identity/logout', {
+ client_id: config.value('clientId'),
+ client_sec: config.value('clientSec'),
+ })
+ } else {
+ await this.$store.dispatch('identity/logoutTenantAdmin', {})
+ }
await this.$router.push("/")
await this.$store.dispatch('agent/reset')
@@ -90,23 +100,32 @@
await this.$store.dispatch('user/reset')
},
async validateAuthentication() {
- this.authenticated = await this.$store.dispatch('identity/isAuthenticated', {
- client_id: config.value('clientId'),
- client_sec: config.value('clientSec')
- }) === true
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (!this.tenantModeactivated) {
+ this.authenticated = await this.$store.dispatch('identity/isAuthenticated', {
+ client_id: config.value('clientId'),
+ client_sec: config.value('clientSec')
+ }) === true
+ } else {
+ this.authenticated = await this.$store.dispatch('identity/isAuthenticated', {
+ client_id: auth.getClientId(),
+ client_sec: auth.getClientSec()
+ }) === true
+ }
return this.authenticated
},
async fetchAuthenticatedUser() {
this.isAdmin = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
let currentUserName = await this.$store.dispatch('identity/getCurrentUserName')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
if (await this.validateAuthentication() && (!this.user || this.user.username !== currentUserName)) {
+ let accessToken = await this.$store.getters['identity/getAccessToken']
let resp = await this.$store.dispatch('user/users', {
offset: 0,
limit: 1,
- client_id: config.value('clientId'),
- client_sec: config.value('clientSec'),
+ usertoken:accessToken,
username: currentUserName
})
if (Array.isArray(resp) && resp.length > 0) {
@@ -123,16 +142,39 @@
})
}
}
+ },
+
+ async setOperationalMode() {
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.activatedClientId = await this.$store.dispatch('tenant/getActivatedClientId')
+ }
+ },
+ async exitTenantExplorer() {
+ await this.$store.dispatch('identity/logoutTenantAdmin')
+ await this.$router.push({name: 'tenants'})
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ },
+
+ async loadProfilePage() {
+ if (this.tenantModeactivated) {
+ await this.$router.push({name: 'tenantUserProfile', params: {tenantId: this.activatedClientId}})
+ } else {
+ await this.$router.push({name: 'profile'})
+ }
+
}
},
watch: {
$route() {
this.authenticated = false
this.fetchAuthenticatedUser()
+ this.setOperationalMode()
}
},
async beforeMount() {
this.fetchAuthenticatedUser()
+ this.setOperationalMode()
}
}
</script>
@@ -220,4 +262,49 @@
.navigation a.router-link-exact-active {
background-color: #00000047;
}
+
+ .tenant-manager {
+ position: fixed;
+ margin-left: 30%;
+ background-color: #f83600;
+ border-color: #ebebeb;
+ font-size: medium;
+ margin-bottom: 0.25%;
+ margin-top: 0.08%;
+ }
+
+ .column {
+ float: left;
+ width: 50%;
+ }
+
+
+ .left-column {
+ float: left;
+ width: 3%;
+ padding: 0px;
+ height: 100vh;
+ background: #fe8c00;
+ background: -webkit-linear-gradient(to bottom, #afafae, #afafae);
+ background: linear-gradient(to bottom, #afafae, #afafae);
+ }
+
+ /*.right-column {*/
+ /* float: left;*/
+ /* width: 97%;*/
+ /* padding: 0px;*/
+ /* height: 100vh;*/
+ /*}*/
+
+ .upper-row {
+ float: left;
+ width: 100%;
+ padding: 0px;
+ background: #fe8c00;
+ background: -webkit-linear-gradient(to right, #f83600, #fe8c00);
+ background: linear-gradient(to right, #f83600, #fe8c00);
+ height: 3.5%;
+ }
+
+
</style>
\ No newline at end of file
diff --git a/custos-demo-gateway/src/components/admin-portal/ListTenants.vue b/custos-demo-gateway/src/components/admin-portal/ListTenants.vue
new file mode 100644
index 0000000..02e8e30
--- /dev/null
+++ b/custos-demo-gateway/src/components/admin-portal/ListTenants.vue
@@ -0,0 +1,508 @@
+<template>
+ <div v-if="!this.view_tenant">
+ <div class="row">
+ <div class="col">
+ <h1 class="h4 mb-4 heading">Manage Tenants</h1>
+ </div>
+ </div>
+ <div class="card">
+ <div class="searchBoxDiv">
+ <b-row>
+ <b-col cols="1">
+ <b-form-input v-model="searchID" class="searchBox" placeholder="Enter TenantId"></b-form-input>
+ </b-col>
+ <b-button variant="primary" @click="searchHandler" class="btnCustom"><span>
+ <i class="fas fa-search"></i>
+ </span> Search
+ </b-button>
+ </b-row>
+ </div>
+ <div v-if="this.searchInd === true" class="table" align="center">
+
+ <b-table v-if="this.searchList[0].tenant_status ==='ACTIVE'" style="width: 70%" striped hover responsive
+ :items="searchList" :fields="fields" selectable
+ small
+ ref="selectableTable"
+ select-mode="single"
+ @row-selected="onRowSelected">
+ <template #cell(actions)="row">
+ <b-button pill size="sm" @click="loginToTenant(row.item, row.index, $event.target)"
+ class="tenantLogin">
+ Tenant Explorer
+ </b-button>
+
+ <b-dropdown :disabled="row.item.parent_tenant_id>0" right class="ml-2" text="..." no-caret toggle-class="list-button">
+ <template v-slot:button-content>
+ <b-icon icon="three-dots-vertical"></b-icon>
+ </template>
+ <template v-slot:default>
+ <b-dropdown-item href="#"
+ v-on:click="createChildTenant(row.item, row.index, $event.target)">
+ Create Child Tenant
+ </b-dropdown-item>
+ </template>
+ </b-dropdown>
+ </template>
+ </b-table>
+ <b-table v-else style="width: 70%" striped hover responsive :items="searchList"
+ :fields="nonActionFields" selectable
+ small
+ ref="selectableTable"
+ select-mode="single"
+ @row-selected="onRowSelected">
+ </b-table>
+ </div>
+ <div class="h-tabs" v-if="this.searchInd === false">
+ <div class="h-tab">
+ <div align="center" v-on:click="onClickHandler(1)"
+ v-bind:class="[value===1 ? 'tab-content-active' : 'tab-content' ]">Active
+ </div>
+ <div align="center" v-on:click="onClickHandler(2)"
+ v-bind:class="[value===2 ? 'tab-content-active' : 'tab-content' ]">Requested
+ </div>
+ <div align="center" v-on:click="onClickHandler(3)"
+ v-bind:class="[value===3 ? 'tab-content-active' : 'tab-content' ]">Deactivated
+ </div>
+ </div>
+ <div v-if="value === 1" class="content card-body">
+ <b-table striped hover responsive :items="active_display" :fields="fields" selectable small
+ ref="selectableTable"
+ select-mode="single"
+ :per-page="perPage"
+ :current-page="currentActivePage"
+ @row-selected="onRowSelected">
+ <template #cell(actions)="row">
+ <b-button pill size="sm" @click="loginToTenant(row.item, row.index, $event.target)"
+ class="tenantLogin">
+ Tenant Explorer
+ </b-button>
+
+ <b-dropdown :disabled="row.item.parent_tenant_id>0" right class="ml-2" text="..." no-caret toggle-class="list-button">
+ <template v-slot:button-content>
+ <b-icon icon="three-dots-vertical"></b-icon>
+ </template>
+ <template v-slot:default >
+ <b-dropdown-item href="#"
+ v-on:click="createChildTenant(row.item, row.index, $event.target)">
+ Create Child Tenant
+ </b-dropdown-item>
+ </template>
+ </b-dropdown>
+ </template>
+
+ </b-table>
+ <div>
+ <b-pagination
+ size="sm"
+ class="float-right"
+ v-model="currentActivePage"
+ :total-rows="activeRows"
+ :per-page="perPage"
+ aria-controls="my-table"
+ ></b-pagination>
+ </div>
+ </div>
+ <div v-if="value === 2" class="content card-body">
+ <b-table striped hover responsive :items="requested_display" :fields="nonActionFields" selectable
+ small
+ ref="selectableTable"
+ select-mode="single"
+ :per-page="perPage"
+ :current-page="currentRequestedPage"
+ @row-selected="onRowSelected">
+ </b-table>
+ <div>
+ <b-pagination
+ size="sm"
+ class="float-right"
+ v-model="currentRequestedPage"
+ :total-rows="requestedRows"
+ :per-page="perPage"
+ aria-controls="my-table"
+ ></b-pagination>
+ </div>
+ </div>
+ <div v-if="value === 3" class="content card-body">
+ <b-table striped hover responsive :items="deactivated_display" :fields="nonActionFields" selectable
+ small
+ ref="selectableTable"
+ select-mode="single"
+ :per-page="perPage"
+ :current-page="currentDeactivatedPage"
+ @row-selected="onRowSelected">
+ </b-table>
+ <div>
+ <b-pagination
+ size="sm"
+ class="float-right"
+ v-model="currentDeactivatedPage"
+ :total-rows="requestedRows"
+ :per-page="perPage"
+ aria-controls="my-table"
+ ></b-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ <div v-else>
+ <Tenant :tenantRequest="selectedTenant" @reloadParent="reloadMe"></Tenant>
+ </div>
+</template>
+
+<script>
+
+ import Tenant from "@/components/admin-portal/Tenant";
+ import config from "@/config";
+
+ export default {
+ components: {Tenant},
+ props: {
+ tokenData: {
+ type: String
+ }
+ },
+ data() {
+ return {
+ requested: [],
+ active: [],
+ deactivated: [],
+ value: 1,
+ searchID: '',
+ searchList: [],
+ searchInd: false,
+ perPage: 5,
+ currentActivePage: 0,
+ currentRequestedPage: 0,
+ currentDeactivatedPage: 0,
+ active_page: 1,
+ active_pages: [],
+ selectedTenant: '',
+ view_tenant: false,
+ custosId: null,
+ custosSec: null,
+ isAdminUser: false,
+ user: null,
+ fields: [{key: 'client_id', label: 'Tenant Id'}, {key: 'client_name', label: 'Tenant Name'}, {
+ key: 'domain',
+ label: 'Domain'
+ }, {key: 'Actions', label: 'Actions'}],
+ nonActionFields: [{key: 'client_id', label: 'Tenant Id'}, {key: 'client_name', label: 'Tenant Name'}, {
+ key: 'domain',
+ label: 'Domain'
+ }],
+ active_display: [],
+ requested_page: 1,
+ requested_pages: [],
+ requested_display: [],
+ deactivated_page: 1,
+ deactivated_pages: [],
+ deactivated_display: [],
+ req_offset: 0,
+ active_offset: 0,
+ deactivated_offset: 0,
+ req_limit: 0,
+ active_limit: 0,
+ deactive_limit: 0
+ }
+ },
+ computed: {
+ activeRows() {
+ return this.active_display.length;
+ },
+ requestedRows() {
+ return this.requested_display.length;
+ },
+ deactivatedRows() {
+ return this.deactivated_display.length;
+ }
+ },
+ async beforeMount() {
+ this.custosId = config.value('clientId')
+ this.custosSec = config.value('clientSec')
+ this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
+ this.currentUserName = await this.$store.dispatch('identity/getCurrentUserName')
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+
+ let data = {
+ offset: 0, limit: 1, usertoken:accessToken,
+ username: this.currentUserName
+ }
+ let resp = await this.$store.dispatch('user/users', data)
+ if (Array.isArray(resp) && resp.length > 0) {
+ resp.forEach(obj => {
+ this.user = {
+ username: obj.username,
+ first_name: obj.first_name,
+ last_name: obj.last_name,
+ email: obj.email
+ }
+
+ this.user = obj
+ this.first_name = obj.first_name
+ this.last_name = obj.last_name
+ this.email = obj.email
+ })
+ }
+ await this.loadTenants(this.active_display, this.requested_display, this.deactivated_display)
+
+ },
+ methods: {
+ onClickHandler(step) {
+ this.value = step;
+ },
+ async searchHandler() {
+
+ if (!this.searchID) {
+ this.searchInd = false;
+ return
+ }
+ this.searchInd = true;
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ usertoken:accessToken,
+ requesting_client_id: this.searchID
+ }
+
+ let response = await this.$store.dispatch('tenant/getTenantByClientId', data)
+ if (response) {
+ this.searchList.length = 0
+ this.searchList.push(response)
+ }
+ },
+
+ onRowSelected: function (items) {
+ if (items != null && items.length > 0) {
+
+ this.view_tenant = true
+ this.selectedTenant = items[0];
+ }
+
+ },
+
+ async reloadMe() {
+ this.view_tenant = false
+ this.active_display =[]
+ this.requested_display =[]
+ this.deactivated_display =[]
+ await this.loadTenants(this.active_display, this.requested_display, this.deactivated_display)
+
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async loginToTenant(item, index, target) {
+ await this.$emit('loginToTenant', {tenantId: item.client_id, tenantName: item.client_name})
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async createChildTenant(item, index, target) {
+ await this.$emit('createChildTenant', {tenantId: item.client_id})
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async getTenantsRecursively(offset, status, container) {
+ if (container == null || container == undefined) {
+ container = []
+ }
+ let limit = 50
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ usertoken:accessToken,
+ status: status,
+ limit: 50,
+ offset: offset
+ }
+ let response = await this.$store.dispatch('tenant/getTenants', data);
+ let tenants = response.tenant
+ if (tenants.length > 0) {
+ tenants.forEach(tent => {
+ if (tent.client_id != null && tent.client_id != "") {
+ container.push(tent)
+ }
+ })
+ }
+
+ if (tenants.length >= limit) {
+ offset = offset + tenants.length
+ await this.getTenantsRecursively(offset, status, container)
+ }
+
+ return container
+ },
+
+ async getAllTenants(status, requester_email) {
+ let container = [];
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ usertoken:accessToken,
+ status: status,
+ requester_email: requester_email
+ }
+ let response = await this.$store.dispatch('tenant/getTenants', data);
+ let tenants = response.tenant
+ if (tenants.length > 0) {
+ tenants.forEach(tent => {
+ if (tent.client_id != null && tent.client_id != "") {
+ container.push(tent)
+ }
+ })
+ }
+ return container
+ },
+ async loadTenants(active_display,requested_display, deactivated_display) {
+ if (this.isAdminUser) {
+ this.active_display = await this.getTenantsRecursively(0, 'ACTIVE',active_display)
+ this.requested_display = await this.getTenantsRecursively(0, 'REQUESTED',requested_display)
+ this.deactivated_display = await this.getTenantsRecursively(0, 'DEACTIVATED',deactivated_display)
+
+ } else {
+ this.active_display = await this.getAllTenants('ACTIVE', this.user.email)
+ this.requested_display = await this.getAllTenants('REQUESTED', this.user.email)
+ this.deactivated_display = await this.getAllTenants('DEACTIVATED', this.user.email)
+ }
+ },
+
+ },
+
+ async mounted() {
+ this.searchInd = false
+ }
+ };
+</script>
+
+<style scoped>
+ .link {
+ color: #ff6600;
+ }
+
+ .h-tab {
+ display: flex;
+ max-height: 500px;
+ margin-top: 20px;
+ padding: 20px;
+ }
+
+ .h-tabs {
+ flex: 8;
+ }
+
+ .list-button {
+ border-radius: 30px;
+ width: 35px;
+ height: 35px;
+ padding: 0px;
+ line-height: 0px;
+ font-size: 15px;
+ background-color: #ff6600;
+ }
+
+ .tab-content {
+ flex: 1;
+ border-bottom: 3px solid black;
+ padding: 8px;
+ color: black;
+ font-weight: bold;
+ cursor: pointer;
+ font-size: 20px;
+ }
+
+ .tab-content-active {
+ flex: 1;
+ border-bottom: 3px solid #ff6600;;
+ padding: 8px;
+ color: #ff6600;
+ font-weight: bold;
+ cursor: pointer;
+ font-size: 20px;
+ }
+
+ .table-head {
+ background-color: lightgray;
+ }
+
+ .content {
+ margin-top: 20px;
+ width: 1100px;
+ margin-left: 20px;
+ }
+
+ .heading {
+ font-size: 30px;
+ color: black;
+ font-weight: bold;
+ }
+
+ .searchBoxDiv {
+ margin-top: 20px;
+ margin-left: 50px;
+ }
+
+ .searchBox {
+ width: 350px;
+ height: 45px;
+ }
+
+ .table {
+ padding: 20px;
+ }
+
+ .btnCustom {
+ color: white;
+ background-color: #ff6600;
+ padding: 10px 25px;
+ border: 1px solid #ff6600;
+ border-radius: 8px;
+ margin-left: 20%;
+ }
+
+ .btnCustom:hover {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .btnCustom:focus {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .btnPagination {
+ color: #ff6600;
+ background-color: white;
+ padding: 10px 25px;
+ border: 1px solid #ff6600;
+ border-radius: 8px;
+ font-weight: bold;
+ }
+
+ .btnPagination:hover {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .btnPaginationActive {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .tenantLogin {
+ background-color: darkolivegreen;
+ }
+
+ .createChildTenant {
+ background-color: #ff6600;
+ margin-left: 2%;
+ }
+</style>
\ No newline at end of file
diff --git a/custos-demo-gateway/src/components/admin-portal/NewTenant.vue b/custos-demo-gateway/src/components/admin-portal/NewTenant.vue
new file mode 100644
index 0000000..6e548b2
--- /dev/null
+++ b/custos-demo-gateway/src/components/admin-portal/NewTenant.vue
@@ -0,0 +1,804 @@
+<template>
+ <div>
+ <div class="row">
+ <div class="col">
+ <h1 class="h4 mb-4 heading"> Tenant Wizard</h1>
+ </div>
+ </div>
+ <b-form @submit="onSubmit">
+ <div class="h-tabs card" align="left">
+ <div class="h-tab">
+ <!-- <div align="center" v-on:click="onClickHandler(1)" v-bind:class="[tabIndex===1 ? 'tab-content-active' : 'tab-content' ]">Requester Info</div>-->
+ <div align="center" v-on:click="onClickHandler(1)"
+ v-bind:class="[tabIndex===1 ? 'tab-content-active' : 'tab-content' ]">Gateway Admin details
+ </div>
+ <div align="center" v-on:click="onClickHandler(2)"
+ v-bind:class="[tabIndex===2 ? 'tab-content-active' : 'tab-content' ]">Gateway details
+ </div>
+ <div align="center" v-on:click="onClickHandler(3)"
+ v-bind:class="[tabIndex===3 ? 'tab-content-active' : 'tab-content' ]">Tenant Credentials
+ </div>
+ </div>
+
+ <div v-if="tabIndex === 1" class="content">
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-1"
+ label="Admin Username"
+ label-for="admin-username"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab1.admin_username.$invalid"
+ id="admin-username"
+ name="admin-username"
+ trim
+ v-model="form.tab1.admin_username"
+ readonly>
+ </b-form-input>
+ </b-form-group>
+ <b-form-row>
+ <b-col>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-4"
+ label="Admin First Name"
+ label-for="admin-first-name"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab1.admin_first_name.$invalid"
+ id="admin-first-name"
+ name="admin-first-name"
+ trim
+ v-model="form.tab1.admin_first_name">
+ </b-form-input>
+ </b-form-group>
+ </b-col>
+ <b-col>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-5"
+ label="Admin Last Name"
+ label-for="admin-last-name"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab1.admin_last_name.$invalid"
+ id="admin-last-name"
+ name="admin-last-name"
+ trim
+ v-model="form.tab1.admin_last_name">
+ </b-form-input>
+ </b-form-group>
+ </b-col>
+ </b-form-row>
+
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-6"
+ label="Admin Email"
+ label-for="admin-email"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab1.admin_email.$invalid"
+ id="admin-email"
+ name="admin-email"
+ trim
+ type="email"
+ v-model="form.tab1.admin_email"
+ readonly
+ >
+ </b-form-input>
+ </b-form-group>
+
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-7"
+ label="Admin Password"
+ label-for="admin-password"
+ class="inputLabels"
+ >
+ <b-input :state="!$v.form.tab1.admin_password.$invalid"
+ aria-describedby="password-help-block"
+ id="admin-password"
+ name="admin-password"
+ trim
+ type="password"
+ v-model="form.tab1.admin_password"></b-input>
+ <b-form-text id="password-help-block">
+ Your password must be at least 8 characters long, and must contain letters and
+ numbers, and must at least one special character.
+ </b-form-text>
+ </b-form-group>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-8"
+ label="Confirm Admin Password"
+ label-for="confirm-admin-password"
+ class="inputLabels"
+ >
+ <b-input :state="!$v.form.tab1.confirm_admin_password.$invalid"
+ aria-describedby="password-help-block"
+ id="confirm-admin-password"
+ name="confirm-admin-password"
+ trim
+ type="password"
+ v-model="form.tab1.confirm_admin_password"></b-input>
+ </b-form-group>
+ </div>
+ <div v-if="tabIndex === 2" class="content">
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ id="fieldset-9"
+ description="The Client Name is displayed to end-users on the Identity Provider selection page."
+ label="Tenant Name"
+ label-for="client-name"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab2.client_name.$invalid"
+ id="client-name"
+ name="client-name"
+ trim
+ placeholder="Name of your OAuth 2.0 client"
+ v-model="form.tab2.client_name">
+ </b-form-input>
+ </b-form-group>
+ <div v-for="(redirect_uri, index) in form.tab2.redirect_uris" :key=index>
+ <b-form-row class="align-items-center">
+ <b-col>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ id="fieldset-10"
+ description="Enter your callback URL. The redirect_uri parameter must exactly match a URL in this list"
+ label="Redirect URI"
+ label-for="redirect-uri"
+ class="inputLabels"
+ >
+ <b-input-group>
+ <b-form-input
+ :state="!$v.form.tab2.redirect_uris.$each[index].$invalid"
+ id="redirect-uri"
+ name='redirect-uri'
+ trim
+ type="url"
+ v-model="form.tab2.redirect_uris[index]">
+ </b-form-input>
+ <b-input-group-append>
+ <b-button v-if="index > 0" @click="deleteRedirectUri(index)">Delete URI
+ </b-button>
+ <b-button @click="addRedirectUri(index)">Add another URI</b-button>
+
+ </b-input-group-append>
+ </b-input-group>
+ </b-form-group>
+ </b-col>
+ </b-form-row>
+ </div>
+ <b-form-group label="Scope:" class="inputLabels">
+ <b-form-checkbox-group
+ :options="scopeOptions"
+ id="scope"
+ name="scope"
+ v-model="form.tab2.scope"
+ >
+ <b-link href="https://www.cilogon.org/oidc#h.p_PEQXL8QUjsQm">Information on scopes</b-link>
+ </b-form-checkbox-group>
+ </b-form-group>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-11"
+ label="Domain"
+ label-for="domain"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab2.domain.$invalid"
+ id="domain"
+ placeholder="idp.htrc.indiana.edu"
+ trim
+ v-model="form.tab2.domain">
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-1"
+ label="Client URI"
+ label-for="client-uri"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab2.client_uri.$invalid"
+ id="client-uri"
+ trim
+ v-model="form.tab2.client_uri">
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-12"
+ label="Logo URI"
+ label-for="logo-uri"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab2.logo_uri.$invalid"
+ id="logo-uri"
+ trim
+ type="url"
+ v-model="form.tab2.logo_uri">
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-8"
+ label="Parent Tenant ID"
+ label-for="client-id"
+ class="inputLabels"
+ :disabled="!form.tab2.parentID"
+ >
+ <b-form-input
+ :state="!$v.form.tab2.parentID.$invalid"
+ id="parent-id"
+ name="parent-id"
+ trim
+ v-model="form.tab2.parentID"
+ :disabled="!form.tab2.parentID"
+ readonly
+ >
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ description=""
+ id="fieldset-8"
+ label="Parent Tenant Secret"
+ label-for="parent-secret"
+ class="inputLabels"
+ >
+ <b-form-input
+ :state="!$v.form.tab2.parentSecret.$invalid"
+ id="parent-secret"
+ name="parent-secret"
+ trim
+ v-model="form.tab2.parentSecret"
+ :disabled="!form.tab2.parentID"
+ >
+ </b-form-input>
+ </b-form-group>
+
+
+ <b-form-group
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ id="fieldset-13"
+ label="Comment"
+ label-for="comment"
+ class="inputLabels"
+ >
+ <b-form-textarea
+ :state="!$v.form.tab2.comment.$invalid"
+ id="comment"
+ rows="3" textarea trim
+ placeholder="Provide description of the new tenant and any other comments here (at least 15 characters long) "
+ v-model="form.tab2.comment">
+ </b-form-textarea>
+ </b-form-group>
+ <b-form-group label="Application Type">
+ <b-form-radio-group
+ :options="application_typeOptions"
+ id="application-type"
+ name="application-type"
+ v-model="form.tab2.application_type"
+ ></b-form-radio-group>
+ </b-form-group>
+
+ </div>
+ <div v-if="tabIndex === 3" class="content">
+ <div v-if="(this.clientID === ''&& !this.requestingTenant)">
+ <div class="row">
+ <div class="col">
+ <h1 class="h4 mb-4">Please create a new tenant to view ClientID and Client Secret</h1>
+ </div>
+ </div>
+ </div>
+ <div v-if="(this.requestingTenant)">
+
+ <div v-if="this.requestingTenant" class="text-center">
+ <b-spinner variant="primary" style="width: 3rem; height: 3rem;"
+ label="Large Spinner"></b-spinner>
+ </div>
+ </div>
+ <div v-if="(this.clientID !== ''&& !this.requestingTenant)">
+ <div class="row">
+ <div class="col">
+ <div class="card border-default">
+ <div class="card-body">
+ <table class="table">
+ <tbody>
+ <tr>
+ <th scope="row">Tenant ID</th>
+ <td>
+ <div> {{this.clientID}}</div>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">Tenant Secret</th>
+ <td>
+ <div> {{this.clientSecret}}</div>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">Tenant Status</th>
+ <td>
+ <div> {{this.status}}</div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="text-center">
+ <b-button-group class="mt-2">
+ <b-button v-if="tabIndex > 1 && tabIndex <= 2" @click="tabIndex--" class="btnCustom">Previous
+ </b-button>
+ <b-button v-if="tabIndex == 1" @click="tabIndex++" class="btnCustom"
+ :disabled="enableNextButton(this.tabIndex)">Next
+ </b-button>
+ <b-button v-if="tabIndex == 2" class="btnCustom"
+ :disabled="enableNextButton(this.tabIndex)" type="submit">Create Tenant
+ </b-button>
+ </b-button-group>
+ </div>
+ </div>
+ </b-form>
+ </div>
+</template>
+
+<script>
+ import {email, required, minLength} from "vuelidate/lib/validators";
+ import config from "@/config";
+
+ export default {
+ props: {
+ requesterEmail: String,
+ tenantId: String
+ },
+ computed: {
+ state() {
+ return this.name.length >= 4 ? true : false
+ },
+ invalidFeedback() {
+ return ''
+ },
+ validFeedback() {
+ return ''
+ },
+ },
+ data() {
+ return {
+ tabIndex: 1,
+ isSubmitted: false,
+ custosId: "",
+ custosSec: "",
+ currentUserName: "",
+ user: "",
+ requestingTenant: false,
+ form: {
+ tab1: {
+ requester_email: "",
+ admin_username: "",
+ admin_first_name: "",
+ admin_last_name: "",
+ admin_email: "",
+ admin_password: "",
+ confirm_admin_password: "",
+ },
+ tab2: {
+ client_name: "",
+ redirect_uris: [""],
+ scope: "openid email profile org.cilogon.userinfo".split(" "),
+ domain: "",
+ client_uri: "",
+ logo_uri: "",
+ application_type: "web",
+ comment: "",
+ parentID: "",
+ parentSecret: "",
+ },
+ primary_contact: "",
+ secondary_contact: "",
+
+
+ },
+ scopeOptions: [
+ {text: "openId", value: "openid", disabled: "true"},
+ {text: "email", value: "email", disabled: "true"},
+ {text: "profile", value: "profile", disabled: "true"},
+ {text: "org.cilogon.userinfo", value: "org.cilogon.userinfo", disabled: "true"},
+ ],
+ application_typeOptions: [
+ {text: "web", value: "web"},
+ ],
+ clientID: 'testing-client',
+ clientSecret: 'testing-secret',
+ status:'REQUESTED'
+ }
+ },
+ validations: {
+ form: {
+ tab1: {
+ requester_email: {email},
+ admin_username: {required},
+ admin_first_name: {required},
+ admin_last_name: {required},
+ admin_email: {required},
+ admin_password: {
+ required,
+ strongPassword(admin_password) {
+ return (
+ /[a-z]/.test(admin_password) && // checks for a-z
+ /[0-9]/.test(admin_password) && // checks for 0-9
+ /\W|_/.test(admin_password) && // checks for special char
+ admin_password.length >= 8
+ );
+ }
+ },
+ confirm_admin_password: {
+ required,
+ strongPassword(confirm_admin_password) {
+ return (
+ // /[a-z]/.test(admin_password) && // checks for a-z
+ // /[0-9]/.test(admin_password) && // checks for 0-9
+ // /\W|_/.test(admin_password) && // checks for special char
+ // admin_password.length >= 8
+ confirm_admin_password == this.form.tab1.admin_password
+ );
+ }
+ },
+ },
+
+ tab2: {
+ client_name: {required},
+ scope: {required},
+ domain: {
+ required,
+ validDomain(domain) {
+ return (
+ /^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,}\.?((xn--)?([a-z0-9\-.]{1,61}|[a-z0-9-]{1,30})\.?[a-z]{2,})$/.test(domain)
+ )
+ }
+ },
+ client_uri: {
+ required,
+ validURL(client_uri) {
+ return (
+ /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/.test(client_uri)
+ )
+ }
+
+ },
+ logo_uri: {
+ required,
+ validURL(logo_uri) {
+ return (
+ /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/.test(logo_uri)
+ )
+ }
+ },
+ application_type: {required},
+ redirect_uris: {
+ $each: {
+ required,
+ validURL(url) {
+ return (
+ /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/.test(url)
+ )
+ }
+ }
+ },
+ comment: {required, minLength: minLength(15)},
+ parentID: {},
+ parentSecret: {
+ validate(parentSecret) {
+ if (this.form.tab2.parentID) {
+ return (
+ parentSecret
+ )
+ } else {
+ return (
+ true
+ )
+ }
+ }
+ }
+
+ },
+ primary_contact: {required},
+ secondary_contact: {},
+
+
+ }
+ },
+ methods: {
+ isSubmitDisabled() {
+ if (!this.isSubmitted)
+ return this.$v.form.$invalid;
+ return this.isSubmitted;
+ },
+ linkClass(idx) {
+ if (this.tabIndex === idx) {
+ return ['bg-primary', 'text-light']
+ } else {
+ return ['bg-light', 'text-info']
+ }
+ },
+ onClickHandler(step) {
+ this.tabIndex = step;
+ },
+ async onSubmit(event) {
+ event.preventDefault();
+ this.isSubmitted = true;
+ this.requestingTenant = true
+ this.tabIndex++;
+
+ if (!this.$v.form.tab1.$invalid && !this.$v.form.tab2.$invalid) {
+ let requester_email = this.$v.form.tab1.admin_email.$model;
+ let admin_username = this.$v.form.tab1.admin_username.$model;
+ let admin_first_name = this.$v.form.tab1.admin_first_name.$model;
+ let admin_last_name = this.$v.form.tab1.admin_last_name.$model;
+ let admin_email = this.$v.form.tab1.admin_email.$model;
+ let admin_password = this.$v.form.tab1.admin_password.$model;
+ let client_name = this.$v.form.tab2.client_name.$model;
+ let redirect_uris = this.$v.form.tab2.redirect_uris.$model;
+ let scope = this.$v.form.tab2.scope.$model;
+ let domain = this.$v.form.tab2.domain.$model;
+ let client_uri = this.$v.form.tab2.client_uri.$model;
+ let logo_uri = this.$v.form.tab2.logo_uri.$model;
+ let comment = this.$v.form.tab2.comment.$model;
+ let application_type = this.$v.form.tab2.application_type.$model;
+ let scopeString = '';
+ for (var i = 0; i < scope.length; i++) {
+ scopeString += scope[i] + " "
+ }
+ scopeString = scopeString.trim()
+ let contacts = [];
+ contacts.push(requester_email);
+
+ let body = {
+ "client_name": client_name,
+ "requester_email": requester_email,
+ "admin_username": admin_username,
+ "admin_first_name": admin_first_name,
+ "admin_last_name": admin_last_name,
+ "admin_email": admin_email,
+ "contacts": contacts,
+ "redirect_uris": redirect_uris,
+ "scope": scopeString,
+ "domain": domain,
+ "admin_password": admin_password,
+ "client_uri": client_uri,
+ "logo_uri": logo_uri,
+ "application_type": application_type,
+ "comment": comment
+ }
+
+
+ if (this.$v.form.tab2.parentID.$model && this.$v.form.tab2.parentSecret.$model) {
+ let data = {
+ client_id: this.$v.form.tab2.parentID.$model,
+ client_sec: this.$v.form.tab2.parentSecret.$model,
+ body: body
+ }
+
+ let response = await this.$store.dispatch('tenant/createChildTenant', data)
+ this.clientID = response.client_id
+ this.clientSecret = response.client_secret
+ if (response.is_activated) {
+ this.status ="ACTIVE"
+ }
+
+
+ } else {
+ let data = {
+ body: body
+ }
+ let response = await this.$store.dispatch('tenant/createAdminTenant', data)
+ this.clientID = response.client_id
+ this.clientSecret = response.client_secret
+ if (response.is_activated) {
+ this.status ="ACTIVE"
+ }
+
+ }
+
+
+ this.requestingTenant = false
+ }
+ },
+ addRedirectUri: function () {
+ this.form.tab2.redirect_uris.push("");
+ },
+ deleteRedirectUri: function (index) {
+ if (index > 0) {
+ this.form.tab2.redirect_uris.splice(index, 1);
+ }
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ enableNextButton(taboption) {
+ if (taboption == 1) {
+ return !!this.$v.form.tab1.$invalid
+ }
+ if (taboption == 2) {
+ return !!this.$v.form.tab2.$invalid
+ }
+ },
+
+ async sleep(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+
+
+ },
+
+ async mounted() {
+ this.custosId = config.value('clientId')
+ this.custosSec = config.value('clientSec')
+ this.currentUserName = await this.$store.dispatch('identity/getCurrentUserName')
+ let data = {
+ offset: 0, limit: 1, client_id: this.custosId, client_sec: this.custosSec,
+ username: this.currentUserName
+ }
+ let resp = await this.$store.dispatch('user/users', data)
+ if (Array.isArray(resp) && resp.length > 0) {
+ resp.forEach(obj => {
+ this.user = {
+ username: obj.username,
+ first_name: obj.first_name,
+ last_name: obj.last_name,
+ email: obj.email,
+ status: obj.state,
+ attributes: [],
+ roles: []
+ }
+ this.user = obj
+ this.form.tab1.admin_username = obj.username
+ this.form.tab1.admin_first_name = obj.first_name
+ this.form.tab1.admin_last_name = obj.last_name
+ this.form.tab1.admin_email = obj.email
+
+
+ })
+ }
+ this.form.tab2.parentID = this.$props.tenantId
+ }
+ }
+</script>
+
+<style scoped>
+ .btn:hover {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .btn:focus {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .link {
+ color: #ff6600;
+ }
+
+ .h-tab {
+ display: flex;
+ max-height: 500px;
+ margin-top: 20px;
+ padding: 20px;
+ }
+
+ .h-tabs {
+ flex: 8;
+ }
+
+ .tab-content {
+ flex: 1;
+ border-bottom: 3px solid black;
+ padding: 8px;
+ color: black;
+ font-weight: bold;
+ cursor: pointer;
+ font-size: 20px;
+ }
+
+ .tab-content-active {
+ flex: 1;
+ border-bottom: 3px solid #ff6600;;
+ padding: 8px;
+ color: #ff6600;
+ font-weight: bold;
+ cursor: pointer;
+ font-size: 20px;
+ }
+
+ .content {
+ margin-top: 20px;
+ width: 1000px;
+ margin-left: 35px;
+ }
+
+ .heading {
+ font-size: 30px;
+ color: black;
+ font-weight: bold;
+ }
+
+ .card {
+ padding: 25px;
+ }
+
+ .btnCustom {
+ color: white;
+ background-color: #ff6600;
+ padding: 10px 25px;
+ border: 1px solid #ff6600;
+ border-radius: 8px;
+ }
+
+ .btnCustom:hover {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .btnCustom:focus {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .inputLabels {
+ color: black;
+ font-weight: bold;
+ }
+</style>
\ No newline at end of file
diff --git a/custos-demo-gateway/src/components/admin-portal/Tenant.vue b/custos-demo-gateway/src/components/admin-portal/Tenant.vue
new file mode 100644
index 0000000..a864919
--- /dev/null
+++ b/custos-demo-gateway/src/components/admin-portal/Tenant.vue
@@ -0,0 +1,553 @@
+<template>
+ <div>
+ <div class="row">
+ <div class="col">
+ <h1 class="h4 mb-4 heading">{{this.$props.tenantRequest.client_name}} Details</h1>
+ </div>
+ </div>
+ <div align="left">
+ <b-form @submit="onSubmit" class="card" align="left">
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Client Name"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.client_name"
+ :state="!$v.form.client_name.$invalid"
+ disabled
+ trim>
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Requester Email"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.requester_email"
+ :state="!$v.form.requester_email.$invalid"
+ disabled
+ trim>
+ </b-form-input>
+ </b-form-group>
+
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Admin Username"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.admin_username"
+ :state="!$v.form.admin_username.$invalid"
+ disabled
+ trim>
+ </b-form-input>
+ </b-form-group>
+ <b-form-row>
+ <b-col>
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Admin First Name"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.admin_first_name"
+ :state="!$v.form.admin_first_name.$invalid"
+ disabled
+ trim>
+ </b-form-input>
+ </b-form-group>
+ </b-col>
+ <b-col>
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Admin Last Name"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.admin_last_name"
+ :state="!$v.form.admin_last_name.$invalid"
+ disabled
+ trim>
+ </b-form-input>
+ </b-form-group>
+ </b-col>
+ </b-form-row>
+
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Admin Email"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.admin_email"
+ :state="!$v.form.admin_email.$invalid"
+ disabled
+ trim>
+ </b-form-input>
+ </b-form-group>
+ <div v-for="(redirect_uri, index) in this.tenantRequest.redirect_uris" :key="index">
+ <b-form-row class="align-items-center">
+ <b-col>
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Redirect URI"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-input-group>
+ <b-form-input
+ id="input-1"
+ v-model="form.redirect_uris[index]"
+ :state="!$v.form.redirect_uris.$each[index].$invalid"
+ trim>
+ </b-form-input>
+ <b-input-group-append>
+ <b-button @click="deleteRedirectUri(index)">Delete URI</b-button>
+ <b-button @click="addRedirectUri(index)">Add another URI</b-button>
+
+ </b-input-group-append>
+ </b-input-group>
+ </b-form-group>
+ </b-col>
+ </b-form-row>
+ </div>
+ <b-form-group label="Scope:" class="inputLabels">
+ <b-form-checkbox-group
+ id="checkbox-group-1"
+ v-model="form.scope"
+ :options="scopeOptions"
+ name="flavour-1"
+ disabled
+ ></b-form-checkbox-group>
+ </b-form-group>
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Domain"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.domain"
+ :state="!$v.form.domain.$invalid"
+ trim>
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Client URI"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.client_uri"
+ :state="!$v.form.client_uri.$invalid"
+ trim>
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ id="fieldset-1"
+ description=""
+ label="Logo URI"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-input
+ id="input-1"
+ v-model="form.logo_uri"
+ :state="!$v.form.logo_uri.$invalid"
+ trim>
+ </b-form-input>
+ </b-form-group>
+ <b-form-group
+ id="fieldset-1"
+ description="(At least 15 characters long) Provide description of the new tenant and any other comments here."
+ label="Comment"
+ label-for="input-1"
+ :invalid-feedback="invalidFeedback"
+ :valid-feedback="validFeedback"
+ class="inputLabels"
+ >
+ <b-form-textarea
+ rows="3"
+ textarea
+ id="input-1"
+ v-model="form.comment"
+ :state="!$v.form.comment.$invalid"
+ trim>
+ </b-form-textarea>
+ </b-form-group>
+ <b-form-group label="Application Type" class="inputLabels">
+ <b-form-radio-group
+ id="radio-group-1"
+ v-model="form.application_type"
+ :options="application_typeOptions"
+ name="radio-options"
+ disabled
+ ></b-form-radio-group>
+ </b-form-group>
+ <div>
+ <div class="text-center" v-if="operating">
+ <b-spinner variant="primary" label="Text Centered"></b-spinner>
+ </div>
+ <b-button
+ v-b-modal.modal-1
+ v-on:click="handleClose"
+ variant="primary"
+ class="btnClose">
+ Close
+ </b-button>
+ <b-button v-if="isUpdateDisable"
+ v-b-modal.modal-1
+ type="submit"
+ variant="primary"
+ class="btnUpdate">
+ Update
+ </b-button>
+ <b-button v-if="isActivatable"
+ v-b-modal.modal-1
+ v-on:click="activate"
+ variant="primary"
+ class="btnActivate">
+ Activate
+ </b-button>
+ <b-button v-if="isDeActivatable"
+ v-b-modal.modal-1
+ v-on:click="deactivate"
+ variant="primary"
+ class="btnDeActivate">
+ DeActivate
+ </b-button>
+ </div>
+ </b-form>
+ </div>
+ </div>
+</template>
+
+<script>
+ import {email, required, minLength} from "vuelidate/lib/validators";
+ import config from "@/config";
+ // import urls from "./utils/urls";
+ // import axios from 'axios';
+ // // import {CLIENT_ID, CLIENT_SECRET} from '../config/config';
+ //
+ // let CLIENT_ID, CLIENT_SECRET
+ export default {
+ computed: {
+ state() {
+ return this.name.length >= 4 ? true : false
+ },
+ invalidFeedback() {
+ return ''
+ },
+ validFeedback() {
+ return ''
+ },
+ isUpdateDisable() {
+ if (!this.isUpdateClicked)
+ return !this.$v.form.$invalid
+ return this.isUpdateClicked;
+ },
+
+ },
+ props: {
+ tenantRequest: Object
+
+ },
+ data() {
+ return {
+ isUpdateClicked: false,
+ isActivatable: false,
+ isDeActivatable: false,
+ operating: false,
+ custosId: null,
+ custosSec: null,
+ form: {
+ admin_email: '',
+ admin_first_name: '',
+ admin_last_name: '',
+ admin_username: '',
+ application_type: '',
+ client_id: '',
+ client_name: '',
+ client_uri: '',
+ comment: '',
+ domain: '',
+ logo_uri: '',
+ redirect_uris: '',
+ requester_email: '',
+ scope: '',
+ tenant_id: '',
+ tenant_status: ''
+ },
+ scopeOptions: [
+ {text: "openId", value: "openid"},
+ {text: "email", value: "email"},
+ {text: "profile", value: "profile"},
+ {text: "org.cilogon.userinfo", value: "org.cilogon.userinfo"},
+ ],
+ application_typeOptions: [
+ {text: "web", value: "web"}
+ ]
+ }
+ },
+ validations: {
+ form: {
+ client_name: {required},
+ requester_email: {required, email},
+ admin_username: {required},
+ admin_first_name: {required},
+ admin_last_name: {required},
+ admin_email: {required},
+ scope: {required},
+ domain: {
+ required,
+ validDomain(domain) {
+ return (
+ /^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,}\.?((xn--)?([a-z0-9\-.]{1,61}|[a-z0-9-]{1,30})\.?[a-z]{2,})$/.test(domain)
+ )
+ }
+ },
+ client_uri: {required},
+ logo_uri: {},
+ application_type: {required},
+ redirect_uris: {
+ $each: {
+ required
+ }
+ },
+ comment: {required, minLength: minLength(15)}
+ }
+ },
+ methods: {
+ async onSubmit(event) {
+ this.operating = true;
+ event.preventDefault();
+ this.isUpdateClicked = true;
+
+ let contacts = [];
+
+ contacts.push(this.$v.form.$model.admin_email)
+
+ let body = {
+ "admin_email": this.$v.form.$model.admin_email,
+ "admin_first_name": this.$v.form.$model.admin_first_name,
+ "admin_last_name": this.$v.form.$model.admin_last_name,
+ "admin_username": this.$v.form.$model.admin_username,
+ "application_type": this.$v.form.$model.application_type,
+ "client_id": this.$v.form.$model.client_id,
+ "client_name": this.$v.form.$model.client_name,
+ "client_uri": this.$v.form.$model.client_uri,
+ "comment": this.$v.form.$model.comment,
+ "contacts": contacts,
+ "domain": this.$v.form.$model.domain,
+ "logo_uri": this.$v.form.$model.logo_uri,
+ "redirect_uris": [...this.$v.form.$model.redirect_uris],
+ "requester_email": this.$v.form.$model.requester_email,
+ "tenant_status":this.$props.tenantRequest.tenant_status,
+ "scope": this.$v.form.$model.scope.join(' ')
+ }
+
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ usertoken:accessToken,
+ body: body
+ }
+
+ await this.$store.dispatch('tenant/updateTenant', data)
+
+ this.$emit('reloadParent')
+ },
+ addRedirectUri: function () {
+ this.form.redirect_uris.push("");
+ },
+ deleteRedirectUri: function (index) {
+ this.form.redirect_uris.splice(index, 1);
+ },
+ async handleClose() {
+ this.$emit('reloadParent')
+ },
+ async sleep(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ },
+
+ async activate() {
+ this.operating = true;
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ updating_status: "ACTIVE",
+ updating_client_id: this.$props.tenantRequest.client_id,
+ user_token: accessToken
+ }
+
+ await this.$store.dispatch('tenant/updateTenantStatus', data)
+ this.operating = false;
+ this.$emit('reloadParent')
+
+ },
+
+ async deactivate() {
+ this.operating = true;
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ updating_status: "DEACTIVATED",
+ updating_client_id: this.$props.tenantRequest.client_id,
+ user_token: accessToken
+ }
+
+ await this.$store.dispatch('tenant/updateTenantStatus', data)
+ this.operating = false;
+ this.$emit('reloadParent')
+ }
+
+ },
+ created() {
+ setTimeout(() => {
+ this.tenantRequest.scope = this.tenantRequest.scope.split(" ")
+ if (this.isAdminUser) {
+ if (this.tenantRequest.tenant_status === 'ACTIVE') {
+ this.isDeActivatable = true
+ } else if (this.tenantRequest.tenant_status === 'REQUESTED') {
+ this.isDeActivatable = true
+ this.isActivatable = true
+ }else if (this.tenantRequest.tenant_status === 'DEACTIVATED') {
+ this.isActivatable = true
+ }
+ }
+ this.form = Object.assign(this.form, {...this.tenantRequest});
+ }, 1000);
+ },
+
+ async beforeMount() {
+ this.custosId = config.value('clientId')
+ this.custosSec = config.value('clientSec')
+ this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
+ }
+
+ }
+</script>
+<style scoped>
+ .btnUpdate {
+ color: white;
+ background-color: #ff6600;
+ padding: 10px 25px;
+ border: 1px solid #ff6600;
+ border-radius: 8px;
+ margin-left: 1%;
+ }
+
+ .btnClose {
+ color: white;
+ background-color: #afafae;
+ padding: 10px 25px;
+ border: 1px solid #afafae;
+ border-radius: 8px;
+ }
+
+ .btnActivate {
+ color: white;
+ background-color: blue;
+ padding: 10px 25px;
+ border: 1px solid blue;
+ border-radius: 8px;
+ margin-left: 1%;
+ }
+
+ .btnDeActivate {
+ color: white;
+ background-color: red;
+ padding: 10px 25px;
+ border: 1px solid red;
+ border-radius: 8px;
+ margin-left: 1%;
+ }
+
+ .btnUpdate:hover {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .btnUpdate:focus {
+ color: white;
+ background-color: #944203;
+ padding: 10px 25px;
+ border: 1px solid #944203;
+ border-radius: 8px;
+ }
+
+ .inputLabels {
+ color: black;
+ font-weight: bold;
+ }
+
+ .inputText {
+ width: 300px;
+ border: 1px solid black;
+ margin-bottom: 15px;
+ }
+
+ .heading {
+ font-size: 30px;
+ color: black;
+ font-weight: bold;
+ }
+
+ .card {
+ padding: 25px;
+ width: 70%;
+ }
+
+ .content {
+ margin-top: 20px;
+ width: 1000px;
+ margin-left: 35px;
+ }
+</style>
\ No newline at end of file
diff --git a/custos-demo-gateway/src/components/admin-portal/Tenants.vue b/custos-demo-gateway/src/components/admin-portal/Tenants.vue
new file mode 100644
index 0000000..8a008a3
--- /dev/null
+++ b/custos-demo-gateway/src/components/admin-portal/Tenants.vue
@@ -0,0 +1,136 @@
+<template>
+ <div class="row">
+ <div class="left-column">
+ <div class="upper-row">
+ <router-link to="/tenants">
+ <div style="font-size: 1.5rem; margin-right:98%; margin-bottom: 100% ">
+ <b-icon icon="house-door-fill"></b-icon>
+ </div>
+ </router-link>
+ </div>
+ <div class="lower-row">
+ <div class="side-buttons">
+ <b-button class="border border-info rounded p-2" v-b-tooltip.right title="Create New Tenant"
+ v-on:click="this.createNewTenant" variant="outline-primary">
+ <b-icon icon="plus"></b-icon>
+ </b-button>
+ </div>
+ <div class="side-buttons">
+ <b-button class="border border-info rounded p-2" v-b-tooltip.right title="List tenants"
+ v-on:click="this.viewTenants" variant="outline-primary">
+ <b-icon icon="list"></b-icon>
+ </b-button>
+ </div>
+
+ </div>
+ </div>
+ <div class="right-column">
+ <div class="upper-row">
+
+ </div>
+ <div class="lower-row">
+ <div v-if="this.addTenant">
+ <NewTenant :tenantId="parentId"></NewTenant>
+ </div>
+ <div v-if="!this.addTenant">
+ <ListTenants :key="this.refresh" @loginToTenant="loginToTenant" @createChildTenant="createChildTenant"></ListTenants>
+ </div>
+ </div>
+ </div>
+ </div>
+
+
+</template>
+
+<script>
+ import NewTenant from "@/components/admin-portal/NewTenant";
+ import ListTenants from "@/components/admin-portal/ListTenants";
+ import config from "@/config";
+ export default {
+ name: "tenants",
+ components: {ListTenants, NewTenant},
+ data: function () {
+ return {
+ addTenant:false,
+ custosId:'',
+ custosSec:'',
+ refresh:false,
+ parentId:null
+
+ }
+ },
+
+ methods: {
+ async createNewTenant() {
+ this.addTenant = true
+ },
+ async viewTenants() {
+ this.addTenant = false
+ this.refresh = !this.refresh
+ this.parentId = null
+ },
+ async loginToTenant(item) {
+ await this.$router.push({name:'tenantLogin', params:{tenantId:item.tenantId, tenantName:item.tenantName}})
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async createChildTenant(item){
+ this.addTenant = true
+ this.parentId = item.tenantId
+ }
+ },
+
+ async mounted() {
+ this.custosId = config.value('clientId')
+ this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ await this.$router.push({name:'workspace', params:{tenantId: this.custosId}})
+ }
+ }
+
+
+ }
+</script>
+
+<style scoped>
+ .left-column {
+ float: left;
+ width: 3%;
+ padding: 0px;
+ height: 100vh;
+ background: #fe8c00;
+ background: -webkit-linear-gradient(to bottom, #afafae, #afafae);
+ background: linear-gradient(to bottom, #afafae, #afafae);
+ }
+
+ .right-column {
+ float: left;
+ width: 97%;
+ padding: 0px;
+ height: 100vh;
+ }
+
+ .upper-row {
+ float: left;
+ width: 100%;
+ padding: 0px;
+ background: #fe8c00;
+ background: -webkit-linear-gradient(to right, #f83600, #fe8c00);
+ background: linear-gradient(to right, #f83600, #fe8c00);
+ height: 3.5%;
+ }
+
+ .lower-row {
+
+ }
+
+ .side-buttons {
+ position: relative;
+ margin-top: 3%;
+ }
+
+
+</style>
\ No newline at end of file
diff --git a/custos-demo-gateway/src/components/landing/Landing.vue b/custos-demo-gateway/src/components/landing/Landing.vue
index d733488..ff2462a 100644
--- a/custos-demo-gateway/src/components/landing/Landing.vue
+++ b/custos-demo-gateway/src/components/landing/Landing.vue
@@ -6,10 +6,10 @@
<p class="h2-sub">Sign up and start authenticating</p>
<div class="main-links">
<b-link href="http://airavata.apache.org/custos/" target="_blank">Custos Website</b-link>
- <b-link class="ml-5"
- href="https://cwiki.apache.org/confluence/display/CUSTOS/Gateways+2020%3ACustos+Tutorial" target="_blank">
- Tutorial Instructions
- </b-link>
+<!-- <b-link class="ml-5"-->
+<!-- href="https://cwiki.apache.org/confluence/display/CUSTOS/Gateways+2020%3ACustos+Tutorial" target="_blank">-->
+<!-- Tutorial Instructions-->
+<!-- </b-link>-->
</div>
<img class="w-100" src="./../../assets/custos_home.png">
</b-col>
@@ -44,12 +44,20 @@
<div v-if="this.loginError" class="text-danger w-100 mt-4 text-left form-error-message">
Invalid Username or Password
</div>
- <p class="mt-3 w-100 additional-links text-center">
- Don't have an account?
- <router-link to="/register">Create an account</router-link>
- </p>
+<!-- <p class="mt-3 w-100 additional-links text-center">-->
+<!-- Don't have an account?-->
+<!-- <router-link to="/register">Create an account</router-link>-->
+<!-- </p>-->
</form>
</b-card>
+ <p class="mt-3 w-100 additional-links">
+<!-- How to use Custos?-->
+<!-- <b-link href="https://cwiki.apache.org/confluence/display/CUSTOS/Gateways+2020%3ACustos+Tutorial">-->
+<!-- Tutorial-->
+<!-- </b-link>-->
+ All about
+ <b-link href="http://airavata.apache.org/custos/">Custos</b-link>
+ </p>
</b-col>
</b-row>
</b-container>
@@ -93,7 +101,31 @@
await this.$store.dispatch('identity/authenticateLocally', params)
let resp = await this.$store.dispatch('identity/isAuthenticated', data)
if (resp) {
- await this.$router.push('workspace')
+
+ let data = {
+ offset: 0, limit: 1, client_id: this.custosId, client_sec: this.custosSec,
+ username: this.username
+ }
+ let resp = await this.$store.dispatch('user/users', data)
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ if (Array.isArray(resp) && resp.length > 0) {
+ resp.forEach(user => {
+ let data = {
+ usertoken:accessToken,
+ body: {
+ username: user.username,
+ first_name: user.first_name,
+ last_name: user.last_name,
+ email: user.email,
+ }
+ }
+ this.$store.dispatch('user/updateUserProfile', data)
+
+ })
+ }
+
+ await this.$router.push('tenants')
+
} else {
this.loginError = true
}
@@ -121,7 +153,7 @@
client_sec: this.custosSec
}
if (await store.dispatch('identity/isAuthenticated', data) === true) {
- await this.$router.push('workspace')
+ await this.$router.push('tenants')
}
}
}
diff --git a/custos-demo-gateway/src/components/landing/TenantLogin.vue b/custos-demo-gateway/src/components/landing/TenantLogin.vue
new file mode 100644
index 0000000..eda8877
--- /dev/null
+++ b/custos-demo-gateway/src/components/landing/TenantLogin.vue
@@ -0,0 +1,241 @@
+<template>
+ <b-container>
+ <b-row align-v="start" align-h="center">
+ <b-col style="min-width: 300px; max-width: 100%" class="text-center">
+ <h2>Welcome to {{this.$props.tenantName}}</h2>
+ <p class="h2-sub">Tenant Explorer</p>
+ <div class="main-links">
+ </div>
+ <img class="w-100" src="./../../assets/custos_home.png">
+ </b-col>
+ <b-col style="max-width: 600px;min-width: 300px;" align-h="center">
+ <b-card class="w-100 mt-3 login-card">
+ <form v-on:submit.prevent="this.login" class="p-2">
+ <h3 class="mb-3">Login with Tenant Admin Account</h3>
+ <div class="p-2">
+ <label class="form-input-label" for="form-input-username">Tenant Id</label>
+ <b-form-input id="form-input-username" v-model="this.$props.tenantId"
+ disabled></b-form-input>
+ </div>
+ <div class="p-2">
+ <label class="form-input-label" for="form-input-password">Tenant Secret</label>
+ <b-form-input id="form-input-password" type="password" v-model="tenantSecret"
+ placeholder="Tenant Secret"></b-form-input>
+ </div>
+ <div class="p-2">
+ <label class="form-input-label" for="form-input-username">Username</label>
+ <b-form-input id="form-input-username" v-model="username"
+ placeholder="Admin Username"></b-form-input>
+ </div>
+ <div class="p-2">
+ <label class="form-input-label" for="form-input-password">Password</label>
+ <b-form-input id="form-input-password" type="password" v-model="password"
+ placeholder="Admin Password"></b-form-input>
+ </div>
+ <b-button class="primary-btn w-100 text-center mt-3" type="submit" variant="warning"
+ v-on:click="this.login" :disabled="this.loginDisabled">
+ Login
+ <b-spinner small v-if="this.loginDisabled"></b-spinner>
+ </b-button>
+ <div v-if="this.loginError" class="text-danger w-100 mt-4 text-left form-error-message">
+ Invalid TenantSecret, Username or Password
+ </div>
+
+ </form>
+ </b-card>
+ </b-col>
+ </b-row>
+ </b-container>
+</template>
+
+<script>
+
+ import config from "@/config";
+ // import store from "@/store";
+
+ export default {
+ name: 'Landing',
+ props: {
+ msg: String,
+ seen: Boolean,
+ todos: Array,
+ tenantName: String,
+ tenantId: String
+ },
+ data: function () {
+ return {
+ username: "",
+ password: "",
+ loginDisabled: false,
+ redirectURI: null,
+ loginError: false,
+ tenantSecret: null
+ }
+ },
+ methods: {
+ async login() {
+ this.loginDisabled = true
+ if (this.username != null && this.username != '' && this.tenantSecret != null &&
+ this.tenantSecret != '' && this.password != null && this.password != '') {
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let validationData = {
+ usertoken:accessToken,
+ body: {
+ clientId: this.$props.tenantId,
+ clientSec: this.tenantSecret
+ }
+ }
+ let resp = await this.$store.dispatch('tenant/validateTenant', validationData)
+ if (resp) {
+ let params = {
+ client_id: this.$props.tenantId, client_sec: this.tenantSecret, username: this.username,
+ password: this.password, token_endpoint: this.tokenEndpoint
+ };
+ let data = {
+ client_id: this.$props.tenantId,
+ client_sec: this.tenantSecret
+ }
+ let tokenResp = await this.$store.dispatch('identity/authenticateTenantAdmin', params)
+ if (tokenResp) {
+ let resp = await this.$store.dispatch('identity/isAuthenticated', data)
+ if (resp) {
+
+ let data = {
+ offset: 0, limit: 1, client_id: this.$props.tenantId, client_sec: this.tenantSecret,
+ username: this.username
+ }
+ let resp = await this.$store.dispatch('user/users', data)
+ if (Array.isArray(resp) && resp.length > 0) {
+ resp.forEach(user => {
+ let data = {
+ client_id: this.$props.tenantId,
+ client_sec: this.tenantSecret,
+ body: {
+ username: user.username,
+ first_name: user.first_name,
+ last_name: user.last_name,
+ email: user.email,
+ }
+ }
+ this.$store.dispatch('user/updateUserProfile', data)
+
+ })
+ }
+
+ let str = '/tenant/' + this.$props.tenantId + '/workspace'
+
+ await this.$router.push(str)
+
+ } else {
+ this.loginError = true
+ }
+ }else {
+ this.loginError = true
+ }
+
+ } else {
+ this.loginError = true
+ }
+
+ } else {
+ this.loginError = true
+ }
+ this.loginDisabled = false
+ },
+ async callDismissed() {
+ this.loginError = false
+ }
+ },
+ async mounted() {
+ this.redirectURI = config.value('redirectURI')
+ this.tokenEndpoint = "https://custos.scigap.org/apiserver/identity-management/v1.0.0/token"
+ }
+ }
+</script>
+
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+ h2 {
+ font-family: Avenir;
+ font-size: 35px;
+ font-weight: 900;
+ color: #203a43;
+ }
+
+ .h2-sub {
+ font-family: Avenir-Roman;
+ font-size: 22px;
+ color: #203a43;
+ }
+
+ h3 {
+ font-family: Avenir;
+ font-size: 15px;
+ font-weight: 600;
+ text-align: center;
+ color: #203a43;
+ }
+
+ .h3-sub {
+ font-family: Avenir-Roman;
+ font-size: 20px;
+ text-align: left;
+ color: #203a43;
+ }
+
+ .form-input-label {
+ font-family: Avenir;
+ font-weight: 900;
+ text-align: left;
+ float: left;
+ color: #203a43;
+ }
+
+ .primary-btn {
+ background-color: #ea6a0a;
+
+ font-family: Avenir;
+ font-size: 14px;
+ font-weight: 900;
+ text-align: left;
+ color: #ffffff;
+ }
+
+ .primary-btn:hover {
+ background-color: #da640b;
+ }
+
+ .form-error-message {
+ font-family: Avenir;
+ font-size: 14px;
+ font-weight: 900;
+ text-align: left;
+ }
+
+ .login-card {
+ box-shadow: -1px 1px 6px 2px #ebebeb;
+ border-radius: 10px;
+ border: none;
+ }
+
+ .login-card .form-input-label {
+ font-weight: 500;
+ font-size: 15px;
+ }
+
+ .main-links a {
+ font-family: Avenir;
+ font-size: 20px;
+ font-weight: 600;
+ color: #ea6a0a;
+ }
+
+ .additional-links {
+ font-size: 13px;
+ }
+
+ .additional-links a {
+ color: #ea6a0a;
+ }
+</style>
diff --git a/custos-demo-gateway/src/components/registration/CreateAccount.vue b/custos-demo-gateway/src/components/registration/CreateAccount.vue
index 9c429ce..091a394 100644
--- a/custos-demo-gateway/src/components/registration/CreateAccount.vue
+++ b/custos-demo-gateway/src/components/registration/CreateAccount.vue
@@ -6,10 +6,10 @@
<p class="h2-sub">Sign up and start authenticating</p>
<div class="main-links">
<b-link href="http://airavata.apache.org/custos/" target="_blank">Custos Website</b-link>
- <b-link class="ml-5"
- href="https://cwiki.apache.org/confluence/display/CUSTOS/Gateways+2020%3ACustos+Tutorial" target="_blank">
- Tutorial Instructions
- </b-link>
+<!-- <b-link class="ml-5"-->
+<!-- href="https://cwiki.apache.org/confluence/display/CUSTOS/Gateways+2020%3ACustos+Tutorial" target="_blank">-->
+<!-- Tutorial Instructions-->
+<!-- </b-link>-->
</div>
<img class="w-100" src="./../../assets/custos_home.png">
</b-col>
diff --git a/custos-demo-gateway/src/components/workspace/Agents.vue b/custos-demo-gateway/src/components/workspace/Agents.vue
index 30423ea..ab6679b 100644
--- a/custos-demo-gateway/src/components/workspace/Agents.vue
+++ b/custos-demo-gateway/src/components/workspace/Agents.vue
@@ -158,7 +158,7 @@
return {
community_fields: ["id", "status"],
communityAccounts: [],
- statusOptions: ['ACTIVE', 'DISABLED'],
+ statusOptions: ['ACTIVE', 'DEACTIVE'],
scopes: ['TENANT', 'CLIENT'],
checked: true,
newAccountName: null,
@@ -242,6 +242,7 @@
},
async registerAgent() {
+ this.loadingAgents = true
let accessToken = await this.$store.getters['identity/getAccessToken']
let data = {
user_token: accessToken,
@@ -250,11 +251,19 @@
}
}
let response = await this.$store.dispatch('agent/registerAgent', data)
- let agents = await this.$store.getters['agent/getAgents']
- this.communityAccounts = agents
this.agentId = response.id
this.agentSec = response.secret
this.$refs.enablePopOver.show()
+ this.loadingAgents = false
+ this.communityAccounts = await this.$store.dispatch('agent/get_all_agents', data)
+ this.communityAccounts.forEach(com=>{
+ if (com.isEnabled){
+ com.status = 'ACTIVE'
+ } else {
+ com.status = 'DEACTIVE'
+ }
+ })
+
},
async addAtrOkPressed() {
@@ -323,6 +332,13 @@
async mounted() {
this.custosId = config.value('clientId')
this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ } else {
+ await this.$router.push({name:'tenants'})
+ }
this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
let accessToken = await this.$store.getters['identity/getAccessToken']
@@ -332,6 +348,13 @@
this.loadingAgents = true
await this.enableAgents()
this.communityAccounts = await this.$store.dispatch('agent/get_all_agents', data)
+ this.communityAccounts.forEach(com=>{
+ if (com.isEnabled){
+ com.status = 'ACTIVE'
+ } else {
+ com.status = 'DEACTIVE'
+ }
+ })
this.loadingAgents = false
}
}
diff --git a/custos-demo-gateway/src/components/workspace/Groups.vue b/custos-demo-gateway/src/components/workspace/Groups.vue
index 319aa38..1ccaad4 100644
--- a/custos-demo-gateway/src/components/workspace/Groups.vue
+++ b/custos-demo-gateway/src/components/workspace/Groups.vue
@@ -7,7 +7,7 @@
<div>
<b-alert v-model="groupError" variant="danger" dismissible
@dismissed="callDismissed">
- Group name not available
+ Group name already exists
</b-alert>
</div>
<div v-if="this.groupsLoading" class="d-flex justify-content-center mb-3">
@@ -294,7 +294,7 @@
this.selectedId = this.selectedItem[0].id
this.selectedName = this.selectedItem[0].name
this.selectedDescription = this.selectedItem[0].description
- this.selectedOwnerId = this.selectedItem[0].ownerId
+ this.selectedOwnerId = this.selectedItem[0].owner_id
let data = {
client_id: this.custosId,
@@ -312,8 +312,10 @@
})
let response = await this.$store.dispatch('group/getAllChildGroups', data)
+
this.childGroupMembers = response.groups
+
if (!this.isAdminUser && this.selectedOwnerId != this.currentUser) {
let data = {
@@ -366,7 +368,7 @@
}
let parentGroups = await this.$store.dispatch('group/getAllParentGroups', dat)
- this.groupItems.forEach(gr => {
+ for (const gr of this.groupItems) {
let addToGroup = true
this.childGroupMembers.forEach(lx => {
if (gr.id === lx.id) {
@@ -388,9 +390,31 @@
}
if (addToGroup) {
- grs.push(gr)
+
+
+ if (gr.owner_id != this.currentUser) {
+ let data = {
+ client_id: this.custosId,
+ client_sec: this.custosSec,
+ groupId: gr.id,
+ username: this.currentUser,
+ type: 'ADMIN'
+ }
+
+ let resp = await this.$store.dispatch('group/hasAccess', data)
+
+ if (resp.status) {
+ grs.push(gr)
+
+ }
+ } else {
+ grs.push(gr)
+ }
+
+
}
- })
+ }
+
this.feasibleGroupMembers = grs
this.$refs.addGrMembershipModel.show()
@@ -434,6 +458,8 @@
},
addGr: function () {
+ this.selectedNewGrName = null
+ this.selectedNewGrDesc = null
this.$refs.addGrModel.show()
},
@@ -445,7 +471,7 @@
client_sec: this.custosSec,
username: this.currentUser,
body: {
- groups: [{
+ group: {
name: this.selectedNewGrName,
description: this.selectedNewGrDesc,
ownerId: username,
@@ -453,11 +479,10 @@
client_roles: [],
attributes: [],
sub_groups: []
- }]
+ }
}
}
let response = await this.$store.dispatch('group/createGroup', data)
- console.log(response)
if (!response) {
this.groupError = true
this.groupsLoading = false
@@ -640,18 +665,18 @@
async loadGroups(data) {
+ let grs = []
if (this.isAdminUser) {
- this.groupItems = await this.$store.dispatch('group/loadAllGroups', data)
+ grs = await this.$store.dispatch('group/loadAllGroups', data)
} else {
- let grs = []
grs = await this.$store.dispatch('group/getAllGroupsOfUser', data)
- let groups = []
- grs.forEach(gr => {
- gr.ownerId = gr.owner_id
- groups.push(gr)
- })
- this.groupItems = groups
}
+ let groups = []
+ grs.forEach(gr => {
+ gr.ownerId = gr.owner_id
+ groups.push(gr)
+ })
+ this.groupItems = groups
},
async goToWorkspace() {
@@ -668,6 +693,13 @@
this.groupsLoading = true
this.custosId = config.value('clientId')
this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ } else {
+ await this.$router.push({name:'tenants'})
+ }
this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
this.currentUser = await this.$store.dispatch('identity/getCurrentUserName')
let data = {
diff --git a/custos-demo-gateway/src/components/workspace/Logs.vue b/custos-demo-gateway/src/components/workspace/Logs.vue
index ea4dc9c..8d32e69 100644
--- a/custos-demo-gateway/src/components/workspace/Logs.vue
+++ b/custos-demo-gateway/src/components/workspace/Logs.vue
@@ -174,12 +174,21 @@
async mounted() {
this.custosId = config.value('clientId')
this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ } else {
+ await this.$router.push({name:'tenants'})
+ }
+
this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
let data = {
client_id: this.custosId,
client_sec: this.custosSec
}
+
this.isLoggingEnabled = await this.$store.dispatch('log/isLoggingEnabled', data)
this.activateLogEnabling = this.isAdminUser && !this.isLoggingEnabled
this.isCheckedBtnDisabled = this.isLoggingEnabled
diff --git a/custos-demo-gateway/src/components/workspace/Profile.vue b/custos-demo-gateway/src/components/workspace/Profile.vue
index 0d6c50f..31826fd 100644
--- a/custos-demo-gateway/src/components/workspace/Profile.vue
+++ b/custos-demo-gateway/src/components/workspace/Profile.vue
@@ -1,5 +1,14 @@
<template>
<div>
+ <div class="navigation text-left" v-if="!this.tenantModeactivated">
+ <router-link to="/tenants">
+
+ <b-icon icon="house-door-fill"></b-icon>
+
+ </router-link>
+
+
+ </div>
<div class="w-100 mb-5">
<h2>User Profile</h2>
</div>
@@ -225,7 +234,7 @@
// eslint-disable-next-line no-useless-escape
let emailRegs = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
- let regexPucn = /[~!" "@#$%^&*()+=;"'<>,.]/
+ let regexPucn = /[~!@#$%^&*()+=;"'<>.]/
if (this.first_name == null || this.first_name == '' || regexPucn.test(this.first_name) || this.first_name.length > 20) {
this.firstNameError = true
@@ -244,10 +253,9 @@
}
if (!(this.firstNameError || this.lastnameError || this.emailError)) {
-
+ let accessToken = await this.$store.getters['identity/getAccessToken']
let data = {
- client_id: this.custosId,
- client_sec: this.custosSec,
+ usertoken:accessToken,
body: {
username: this.currentUserName,
first_name: this.first_name,
@@ -260,7 +268,7 @@
}
},
async goToWorkspace() {
- await this.$router.push('/workspace')
+ await this.$router.push({name: 'workspace'})
},
@@ -276,49 +284,55 @@
async mounted() {
this.custosId = config.value('clientId')
this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ }
this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
this.currentUserName = await this.$store.dispatch('identity/getCurrentUserName')
- let data = {
- offset: 0, limit: 1, client_id: this.custosId, client_sec: this.custosSec,
- username: this.currentUserName
- }
- let resp = await this.$store.dispatch('user/users', data)
- if (Array.isArray(resp) && resp.length > 0) {
- resp.forEach(obj => {
- this.user = {
- username: obj.username,
- first_name: obj.first_name,
- last_name: obj.last_name,
- email: obj.email,
- status: obj.state,
- attributes: [],
- roles: []
- }
-
- obj.realm_roles.forEach(role => {
- let r = {
- name: role
+ let accessToken = await this.$store.getters['identity/getAccessToken']
+ let data = {
+ offset: 0, limit: 1, usertoken:accessToken,
+ username: this.currentUserName
+ }
+ let resp = await this.$store.dispatch('user/users', data)
+ if (Array.isArray(resp) && resp.length > 0) {
+ resp.forEach(obj => {
+ this.user = {
+ username: obj.username,
+ first_name: obj.first_name,
+ last_name: obj.last_name,
+ email: obj.email,
+ status: obj.state,
+ attributes: [],
+ roles: []
}
- this.roles.push(r)
+
+ obj.realm_roles.forEach(role => {
+ let r = {
+ name: role
+ }
+ this.roles.push(r)
+ })
+ let attribs = obj.attributes
+ attribs.forEach(r => {
+ let newAt = {
+ key: r.key,
+ value: r.values.join(",")
+ }
+ this.attributes.push(newAt)
+ })
+
+
+ this.user = obj
+ this.first_name = obj.first_name
+ this.last_name = obj.last_name
+ this.email = obj.email
+ this.status = obj.state
+
+
})
- let attribs = obj.attributes
- attribs.forEach(r => {
- let newAt = {
- key: r.key,
- value: r.values.join(",")
- }
- this.attributes.push(newAt)
- })
-
-
- this.user = obj
- this.first_name = obj.first_name
- this.last_name = obj.last_name
- this.email = obj.email
- this.status = obj.state
-
-
- })
}
}
}
@@ -333,4 +347,15 @@
text-align: left;
color: #203a43;
}
+
+ .navigation a {
+ font-family: Avenir;
+ font-size: 15px;
+ font-weight: 600;
+ text-align: left;
+ color: white;
+ padding: 5px 15px;
+ display: inline-block;
+ transition: all 0.1s;
+ }
</style>
\ No newline at end of file
diff --git a/custos-demo-gateway/src/components/workspace/Secrets.vue b/custos-demo-gateway/src/components/workspace/Secrets.vue
index 9899b43..a50e946 100644
--- a/custos-demo-gateway/src/components/workspace/Secrets.vue
+++ b/custos-demo-gateway/src/components/workspace/Secrets.vue
@@ -339,6 +339,15 @@
this.secretsLoading = true
this.custosId = config.value('clientId')
this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ } else {
+ await this.$router.push({name:'tenants'})
+ }
+
this.currentUserName = await this.$store.dispatch('identity/getCurrentUserName')
this.secItems = await this.getAllCredentials()
diff --git a/custos-demo-gateway/src/components/workspace/Sharing.vue b/custos-demo-gateway/src/components/workspace/Sharing.vue
index e1e98d1..73ce74f 100644
--- a/custos-demo-gateway/src/components/workspace/Sharing.vue
+++ b/custos-demo-gateway/src/components/workspace/Sharing.vue
@@ -444,7 +444,7 @@
return {
isAdminUser: false,
fields: ['id', 'name', 'description'],
- sharingFields: ['entity_id', 'permission_type_id', 'owner_id', 'type'],
+ sharingFields: ['entity_id', 'permission_type_id', 'type', 'id'],
entityFields: ['id', 'name', 'type', 'description'],
permissionTypes: [],
entityTypes: [],
@@ -707,9 +707,9 @@
this.sharings = await this.loadSharings()
}
} else {
- console.log(this.defaultGroupName)
+
data.body.owner_id = [this.defaultGroupName.id]
- console.log(data)
+
let response = await this.$store.dispatch('sharing/shareEntityWithGroups', data)
if (response) {
this.sharings = await this.loadSharings()
@@ -782,7 +782,9 @@
this.selectedEnName = this.selectedEn[0].name
this.selectedEnDesc = this.selectedEn[0].description
this.selectedEntityType = this.selectedEn[0].type
- this.$refs.selectedEnModel.show()
+ if (this.selectedEn[0].owner_id === this.currentUserName) {
+ this.$refs.selectedEnModel.show()
+ }
}
},
@@ -791,9 +793,18 @@
this.selectedSh = items
this.selectedShEnId = this.selectedSh[0].entity_id
this.selectedShPrId = this.selectedSh[0].permission_type_id
- this.selectedShOwId = this.selectedSh[0].owner_id
+ this.selectedShOwId = this.selectedSh[0].id
this.selectedShOwType = this.selectedSh[0].type
- this.$refs.selectedShraingModel.show()
+ let show = false;
+ for (const entity of this.entities) {
+ if (entity.id === this.selectedShEnId && entity.owner_id === this.currentUserName) {
+ show = true;
+ break;
+ }
+ }
+ if (show) {
+ this.$refs.selectedShraingModel.show()
+ }
}
},
onNewPrTyAdd: function () {
@@ -886,7 +897,7 @@
let shItem = {
entity_id: en.id,
permission_type_id: pr.id,
- owner_id: uId,
+ id: uId,
type: 'USER'
}
shars.push(shItem)
@@ -900,7 +911,7 @@
let shItem = {
entity_id: en.id,
permission_type_id: pr.id,
- owner_id: uId,
+ id: uId,
type: 'GROUP'
}
shars.push(shItem)
@@ -936,6 +947,15 @@
async mounted() {
this.custosId = config.value('clientId')
this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ } else {
+ await this.$router.push({name:'tenants'})
+ }
+
this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
this.currentUserName = await this.$store.dispatch('identity/getCurrentUserName')
@@ -967,26 +987,38 @@
this.permissionTypes = await this.$store.dispatch('sharing/createPermissionType', data)
}
-
this.entityTypes = await this.$store.dispatch('sharing/getEntityTypes', permTypesData)
- let searchEntitiesData = {
- client_id: this.custosId,
- client_sec: this.custosSec,
- body: {
- client_id: this.custosId,
- owner_id: this.currentUserName,
- search_criteria: [
- {
- search_field: "OWNER_ID",
- value: this.currentUserName,
- condition: "EQUAL"
+ if (this.entityTypes.length > 0)
+ for (const enTy of this.entityTypes) {
+ let searchEntitiesData = {
+ client_id: this.custosId,
+ client_sec: this.custosSec,
+ body: {
+ client_id: this.custosId,
+ owner_id: this.currentUserName,
+ search_criteria: [
+ {
+ search_field: "ENTITY_TYPE_ID",
+ value: enTy.id,
+ condition: "EQUAL"
+ }
+ ]
}
- ]
- }
- }
+ }
- this.entities = await this.$store.dispatch('sharing/getEntities', searchEntitiesData)
+
+ let enties = await this.$store.dispatch('sharing/getEntities', searchEntitiesData)
+
+ if (enties != null && enties.length > 0) {
+ for (const en of enties) {
+ this.entities.push(en)
+ }
+
+ }
+
+ }
+
this.sharings = await this.loadSharings()
}
diff --git a/custos-demo-gateway/src/components/workspace/Users.vue b/custos-demo-gateway/src/components/workspace/Users.vue
index 33c4426..8c97b6a 100644
--- a/custos-demo-gateway/src/components/workspace/Users.vue
+++ b/custos-demo-gateway/src/components/workspace/Users.vue
@@ -322,7 +322,7 @@
await this.loadUsers()
} else {
let data = {
- offset: 0, limit: 5, client_id: this.custosId, client_sec: this.custosSec,
+ offset: 0, limit: 15, client_id: this.custosId, client_sec: this.custosSec,
username: this.searchUsername
}
await this.$store.dispatch('user/users', data)
@@ -484,24 +484,38 @@
async addRoleOkPressed() {
this.operationCompleted = false
let accessToken = await this.$store.getters['identity/getAccessToken']
- let bd = {
- user_token: accessToken,
- body: {
- roles: [this.selectedRole],
- usernames: [this.selectedUsername],
- client_level: (this.selectedScope === 'CLIENT')
- }
- }
- let userAtr = await this.$store.dispatch('user/addRoleToUser', bd)
- if (userAtr) {
- if (this.selectedScope === 'CLIENT') {
- let role = {name: this.selectedRole, scope: "CLIENT"}
- this.selectedRoles.push(role)
- } else {
- let role = {name: this.selectedRole, scope: "TENANT"}
- this.selectedRoles.push(role)
+
+ if (this.selectedScope === 'TENANT' && this.selectedRole === 'admin'){
+ let bd = {
+ user_token: accessToken,
+ body: {
+ username: this.selectedUsername,
+ }
}
+ await this.$store.dispatch('user/grantAdminPrivilages', bd)
+ let role = {name: this.selectedRole, scope: "TENANT"}
+ this.selectedRoles.push(role)
+ } else {
+ let bd = {
+ user_token: accessToken,
+ body: {
+ roles: [this.selectedRole],
+ usernames: [this.selectedUsername],
+ client_level: (this.selectedScope === 'CLIENT')
+ }
+ }
+ let userAtr = await this.$store.dispatch('user/addRoleToUser', bd)
+ if (userAtr) {
+ if (this.selectedScope === 'CLIENT') {
+ let role = {name: this.selectedRole, scope: "CLIENT"}
+ this.selectedRoles.push(role)
+ } else {
+ let role = {name: this.selectedRole, scope: "TENANT"}
+ this.selectedRoles.push(role)
+ }
+
+ }
}
this.operationCompleted = true
this.selectedRole = null
@@ -512,25 +526,38 @@
this.operationCompleted = false
let accessToken = await this.$store.getters['identity/getAccessToken']
let bd = {};
- if (this.rowSelectedScope === 'TENANT') {
- bd = {
+ let deleted = false
+ if (this.rowSelectedScope === 'TENANT' && this.rowSelectedRole === 'admin'){
+ let bd = {
user_token: accessToken,
body: {
- roles: [this.rowSelectedRole],
- username: this.selectedUsername
+ username: this.selectedUsername,
}
}
- } else {
- bd = {
- user_token: accessToken,
- body: {
- client_roles: [this.rowSelectedRole],
- username: this.selectedUsername
- }
- }
- }
- let deleted = await this.$store.dispatch('user/deleteRoleFromUser', bd)
+ deleted = await this.$store.dispatch('user/removeAdminPrivilages', bd)
+ } else {
+
+ if (this.rowSelectedScope === 'TENANT') {
+ bd = {
+ user_token: accessToken,
+ body: {
+ roles: [this.rowSelectedRole],
+ username: this.selectedUsername
+ }
+ }
+ } else {
+ bd = {
+ user_token: accessToken,
+ body: {
+ client_roles: [this.rowSelectedRole],
+ username: this.selectedUsername
+ }
+ }
+ }
+
+ deleted = await this.$store.dispatch('user/deleteRoleFromUser', bd)
+ }
if (deleted) {
let newRoles = []
@@ -539,8 +566,9 @@
if (atr.name != this.rowSelectedRole) {
newRoles.push(atr)
}
- this.selectedRoles = newRoles
+
})
+ this.selectedRoles = newRoles
}
this.operationCompleted = true
this.loadUsers()
@@ -653,6 +681,14 @@
async mounted() {
this.custosId = config.value('clientId')
this.custosSec = config.value('clientSec')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (this.tenantModeactivated) {
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+ } else {
+ await this.$router.push({name:'tenants'})
+ }
+
this.isAdminUser = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
this.currentUserName = await this.$store.dispatch('identity/getCurrentUserName')
await this.loadUsers()
@@ -660,6 +696,7 @@
let params = {client_id: this.custosId, client_sec: this.custosSec}
this.tenantroles = await this.$store.dispatch('user/getTenantLevelRoles', params)
this.clientroles = await this.$store.dispatch('user/getClientLevelRoles', params)
+
}
,
computed: {
diff --git a/custos-demo-gateway/src/components/workspace/Workspace.vue b/custos-demo-gateway/src/components/workspace/Workspace.vue
index 13d5eb1..d1e2b3a 100644
--- a/custos-demo-gateway/src/components/workspace/Workspace.vue
+++ b/custos-demo-gateway/src/components/workspace/Workspace.vue
@@ -4,37 +4,37 @@
<b-card-group columns style="max-width: 800px;">
<b-card class="menu-card" v-if="this.isAdmin" :img-src="require('../../assets/users.png')" img-top>
<b-button href="#"
- v-on:click="loadRoute($event, '/workspace/users')">
+ v-on:click="loadRoute($event, 'users')">
Manage Users
</b-button>
</b-card>
<b-card class="menu-card" :img-src="require('../../assets/groups_web.png')" img-top>
<b-button href="#"
- v-on:click="loadRoute($event, '/workspace/groups')">
+ v-on:click="loadRoute($event, 'groups')">
Manage Groups
</b-button>
</b-card>
<b-card class="menu-card" :img-src="require('../../assets/credentials.png')" img-top>
<b-button href="#"
- v-on:click="loadRoute($event, '/workspace/secrets')">
+ v-on:click="loadRoute($event, 'secrets')">
Manage Secrets
</b-button>
</b-card>
<b-card class="menu-card" :img-src="require('../../assets/sharings.png')" img-top>
<b-button href="#"
- v-on:click="loadRoute($event, '/workspace/sharings')">
+ v-on:click="loadRoute($event, 'sharings')">
Sharing
</b-button>
</b-card>
<b-card class="menu-card" v-if="isAdmin" :img-src="require('../../assets/bots.png')" img-top>
<b-button href="#" :disabled="!isAdmin"
- v-on:click="loadRoute($event, '/workspace/agents')">
+ v-on:click="loadRoute($event, 'agents')">
Service Accounts
</b-button>
</b-card>
<b-card class="menu-card" v-if="isAdmin" :img-src="require('../../assets/dblogs.png')" img-top>
<b-button href="#" :disabled="!isAdmin"
- v-on:click="loadRoute($event, '/workspace/logs')">
+ v-on:click="loadRoute($event, 'logs')">
Logs
</b-button>
</b-card>
@@ -52,12 +52,13 @@
custosSec: null,
isAdmin: false,
user: null,
- currentUserName: null
+ currentUserName: null,
+ tenantModeactivated: false
}
},
methods: {
loadRoute: function (event, route) {
- this.$router.push(route)
+ this.$router.push({name:route, params:{tenantId:this.custosId}} )
},
async logout() {
let data = {
@@ -75,6 +76,13 @@
},
async mounted() {
this.isAdmin = await this.$store.dispatch('identity/isLoggedUserHasAdminAccess')
+ this.tenantModeactivated = await this.$store.dispatch('tenant/isTenantModeActivated')
+ if (!this.tenantModeactivated) {
+ await this.$router.push('tenants')
+ }
+ this.custosId = await this.$store.dispatch('tenant/getActivatedClientId')
+ this.custosSec = await this.$store.dispatch('tenant/getActivatedClientSecret');
+
}
}
</script>
diff --git a/custos-demo-gateway/src/config.js b/custos-demo-gateway/src/config.js
index 0ba2735..9a39d23 100644
--- a/custos-demo-gateway/src/config.js
+++ b/custos-demo-gateway/src/config.js
@@ -11,6 +11,7 @@
}
static value (name) {
+
if (!(name in this.CONFIG)) {
console.log(`Configuration: There is no key named "${name}"`)
return
@@ -18,6 +19,7 @@
const value = this.CONFIG[name]
+
if (!value) {
console.log(`Configuration: Value for "${name}" is not defined`)
return
diff --git a/custos-demo-gateway/src/router.js b/custos-demo-gateway/src/router.js
index 8f9d072..e735cae 100644
--- a/custos-demo-gateway/src/router.js
+++ b/custos-demo-gateway/src/router.js
@@ -2,7 +2,7 @@
import Router from "vue-router";
import Landing from "./components/landing/Landing.vue";
import store from './store/index'
-
+import auth from "@/service/auth";
Vue.use(Router)
@@ -21,37 +21,19 @@
import(/*webpackChunkName:"account"*/ "./components/registration/CreateAccount")
},
{
- path: "/workspace",
+ path: "/tenant/:tenantId/workspace",
name: "workspace",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"workspace"*/ "./components/workspace/Workspace")
},
{
- path: "/workspace/groups",
+ path: "/tenant/:tenantId/workspace/groups",
name: "groups",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"groups"*/ "./components/workspace/Groups")
@@ -60,119 +42,115 @@
path: "/workspace/profile",
name: "profile",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"groups"*/ "./components/workspace/Profile")
},
{
- path: "/workspace/logs",
+ path: "/tenant/:tenantId/workspace/profile",
+ name: "tenantUserProfile",
+ beforeEnter: async (to, from, next) => {
+ await validate(next)
+ },
+ component: () =>
+ import(/*webpackChunkName:"groups"*/ "./components/workspace/Profile")
+ },
+ {
+ path: "/tenant/:tenantId/workspace/logs",
name: "logs",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"logs"*/ "./components/workspace/Logs")
},
{
- path: "/workspace/secrets",
+ path: "/tenant/:tenantId/workspace/secrets",
name: "secrets",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"secrets"*/ "./components/workspace/Secrets")
},
{
- path: "/workspace/sharings",
+ path: "/tenant/:tenantId/workspace/sharings",
name: "sharings",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"sharings"*/ "./components/workspace/Sharing")
},
{
- path: "/workspace/users",
+ path: "/tenant/:tenantId/workspace/users",
name: "users",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"users"*/ "./components/workspace/Users")
},
{
- path: "/workspace/agents",
+ path: "/tenant/:tenantId/workspace/agents",
name: "agents",
beforeEnter: async (to, from, next) => {
- let data = {
- client_id: process.env.VUE_APP_CLIENT_ID,
- client_sec: process.env.VUE_APP_CLIENT_SEC
- }
- if (await store.dispatch('identity/isAuthenticated', data) == true) {
- // You can use store variable here to access globalError or commit mutation
- next(true)
- } else {
- next('/')
- }
+ await validate(next)
},
component: () =>
import(/*webpackChunkName:"account"*/ "./components/workspace/Agents")
},
{
+ path: "/tenants",
+ name: "tenants",
+ beforeEnter: async (to, from, next) => {
+ await validate(next)
+ },
+ component: () =>
+ import(/*webpackChunkName:"account"*/ "./components/admin-portal/Tenants")
+ },
+ {
path: "/callback",
name: "callback",
component: () =>
import(/*webpackChunkName:"users"*/ "./components/Callback")
},
+ {
+ path: "*",
+ name: "notFound",
+ component:()=>
+ import(/*webpackChunkName:"users"*/ "./components/404")
+ },
+ {
+ path: "/tenant/:tenantId/login",
+ name: "tenantLogin",
+ props: true,
+ component: () =>
+ import(/*webpackChunkName:"users"*/ "./components/landing/TenantLogin")
+ },
]
+
+
})
-
-
+async function validate(next) {
+ let data = {
+ client_id: process.env.VUE_APP_CLIENT_ID,
+ client_sec: process.env.VUE_APP_CLIENT_SEC
+ }
+ if (auth.isTenantModeActivated()) {
+ data = {
+ client_id: auth.getClientId(),
+ client_sec: auth.getClientSec()
+ }
+ }
+ if (await store.dispatch('identity/isAuthenticated', data) == true) {
+ // You can use store variable here to access globalError or commit mutation
+ console.log("Authenticationed")
+ next(true)
+ } else {
+ next('/')
+ }
+}
diff --git a/custos-demo-gateway/src/service/auth.js b/custos-demo-gateway/src/service/auth.js
index e256ab4..fe65811 100644
--- a/custos-demo-gateway/src/service/auth.js
+++ b/custos-demo-gateway/src/service/auth.js
@@ -1,9 +1,19 @@
import decode from 'jwt-decode';
+
const ID_TOKEN_KEY = 'id_token';
const ACCESS_TOKEN_KEY = 'access_token';
const REFRESH_TOKEN_KEY = 'refresh_token';
+const ACTIVE_CLIENT_ID = 'active_client_id';
+const ACTIVE_CLEINT_SEC = 'active_client_sec';
+
+
+const TENANT_ADMIN_CUSTOS_ID_TOKEN = 'tenant_admin_id_token';
+const TENANT_ADMIN_CUSTOS_ACCESS_TOKEN = 'tenant_admin_access_token';
+const TENANT_ADMIN_CUSTOS_REFRESH_TOKEN = 'tenant_admin_refresh_token';
+
+
export default {
isLoggedIn() {
@@ -16,6 +26,7 @@
return expirationDate < new Date();
},
+
getTokenExpirationDate(encodedToken) {
const token = decode(encodedToken);
if (!token.exp) {
@@ -48,6 +59,26 @@
localStorage.setItem(REFRESH_TOKEN_KEY, token)
},
+
+ setClientId(client_id) {
+ this.clearActiveClientID()
+ localStorage.setItem(ACTIVE_CLIENT_ID, client_id);
+ },
+
+ setClientSec(client_sec) {
+ this.clearActiveClientSec()
+ localStorage.setItem(ACTIVE_CLEINT_SEC, client_sec);
+ },
+
+
+ getClientId() {
+ return localStorage.getItem(ACTIVE_CLIENT_ID);
+ },
+
+ getClientSec() {
+ return localStorage.getItem(ACTIVE_CLEINT_SEC);
+ },
+
getIdToken() {
return localStorage.getItem(ID_TOKEN_KEY);
},
@@ -56,7 +87,7 @@
return localStorage.getItem(ACCESS_TOKEN_KEY);
},
- getRefreshToken(){
+ getRefreshToken() {
return localStorage.getItem(REFRESH_TOKEN_KEY)
},
@@ -72,6 +103,53 @@
localStorage.removeItem(REFRESH_TOKEN_KEY)
},
+ clearActiveClientID() {
+ localStorage.removeItem(ACTIVE_CLIENT_ID);
+ },
+
+ clearActiveClientSec() {
+ localStorage.removeItem(ACTIVE_CLEINT_SEC)
+ },
+
+ clearTenantAdminCachedIdToken() {
+ localStorage.removeItem(TENANT_ADMIN_CUSTOS_ID_TOKEN);
+ },
+
+ clearTenantAdminCachedAccessToken() {
+ localStorage.removeItem(TENANT_ADMIN_CUSTOS_ACCESS_TOKEN);
+ },
+
+ clearTenantAdminCachedRefreshToken() {
+ localStorage.removeItem(TENANT_ADMIN_CUSTOS_REFRESH_TOKEN)
+ },
+
+ getTenantAdminCachedIdToken() {
+ return localStorage.getItem(TENANT_ADMIN_CUSTOS_ID_TOKEN);
+ },
+
+ getTenantAdminCachedAccessToken() {
+ return localStorage.getItem(TENANT_ADMIN_CUSTOS_ACCESS_TOKEN);
+ },
+
+ getTenantAdminCachedRefreshToken() {
+ return localStorage.getItem(TENANT_ADMIN_CUSTOS_REFRESH_TOKEN)
+ },
+
+ setTenantAdminCachedIdToken(token) {
+ this.clearTenantAdminCachedIdToken()
+ localStorage.setItem(TENANT_ADMIN_CUSTOS_ID_TOKEN, token);
+ },
+
+ setTenantAdminCachedAccessToken(token) {
+ this.clearTenantAdminCachedAccessToken()
+ localStorage.setItem(TENANT_ADMIN_CUSTOS_ACCESS_TOKEN, token);
+ },
+
+ setTenantAdminCachedRefreshToken(token) {
+ this.clearTenantAdminCachedRefreshToken()
+ localStorage.setItem(TENANT_ADMIN_CUSTOS_REFRESH_TOKEN, token)
+ },
+
isUserHasAdminAccess() {
let token = localStorage.getItem(ACCESS_TOKEN_KEY)
let decodedToken = decode(token)
@@ -91,6 +169,12 @@
let token = localStorage.getItem(ACCESS_TOKEN_KEY)
let decodedToken = decode(token)
return decodedToken.preferred_username
- }
+ },
+
+ isTenantModeActivated() {
+ const clientId = localStorage.getItem(ACTIVE_CLIENT_ID)
+ const clientSec = localStorage.getItem(ACTIVE_CLEINT_SEC)
+ return !!clientId && !!clientSec;
+ },
}
\ No newline at end of file
diff --git a/custos-demo-gateway/src/service/group_management.js b/custos-demo-gateway/src/service/group_management.js
index 4f7f6e0..ba98673 100644
--- a/custos-demo-gateway/src/service/group_management.js
+++ b/custos-demo-gateway/src/service/group_management.js
@@ -8,7 +8,7 @@
createGroup(params) {
let authHeader = {'Authorization': 'Bearer ' + btoa(params.client_id + ':' + params.client_sec)}
- let endpoint = groupMgtEndpoint + "/groups"
+ let endpoint = groupMgtEndpoint + "/group"
return api().post(endpoint, params.body, {
headers: authHeader
})
diff --git a/custos-demo-gateway/src/service/tenant_management.js b/custos-demo-gateway/src/service/tenant_management.js
new file mode 100644
index 0000000..c02588b
--- /dev/null
+++ b/custos-demo-gateway/src/service/tenant_management.js
@@ -0,0 +1,69 @@
+import api from "./api.js";
+
+const tenantMgtEndpoint = "/tenant-management/v1.0.0"
+
+export default {
+
+ isVaildTenant(params) {
+ try {
+ let authHeader = {'Authorization': 'Bearer ' + params.usertoken}
+ let endpoint = tenantMgtEndpoint + "/tenant/credentials/status"
+ return api().post(endpoint, params.body, {
+ headers: authHeader
+ })
+ } catch (e) {
+ return false
+ }
+ },
+
+
+ getTenants(data) {
+ let authHeader = {'Authorization': 'Bearer ' + data.usertoken}
+ let endpoint = tenantMgtEndpoint + "/tenants"
+ let params = {
+ limit: data.limit,
+ offset: data.offset,
+ status: data.status,
+ requester_email: data.requester_email
+ }
+ return api().get(endpoint, {params: params, headers: authHeader})
+ },
+
+ getTenantByClientId(data) {
+ let authHeader = {'Authorization': 'Bearer ' + data.usertoken}
+ let endpoint = tenantMgtEndpoint + "/oauth2/tenant"
+ let params = {
+ client_id: data.requesting_client_id
+ }
+ return api().get(endpoint, {params: params, headers: authHeader})
+ },
+
+ updateTenantStatus(data) {
+ let authHeader = {'Authorization': 'Bearer ' + data.user_token}
+ let endpoint = tenantMgtEndpoint + "/status"
+ let body = {
+ client_id: data.updating_client_id,
+ status: data.updating_status
+ }
+ return api().post(endpoint, body, {headers: authHeader})
+ },
+
+ updateTenant(data) {
+ let authHeader = {'Authorization': 'Bearer ' + data.usertoken}
+ let endpoint = tenantMgtEndpoint + "/oauth2/tenant"
+ return api().put(endpoint, data.body, {headers: authHeader})
+ },
+
+ createAdminTenant(data) {
+ let endpoint = tenantMgtEndpoint + "/oauth2/tenant"
+ return api().post(endpoint, data.body)
+ },
+
+ createChildTenant(data) {
+ let authHeader = {'Authorization': 'Bearer ' + btoa(data.client_id + ':' + data.client_sec)}
+ let endpoint = tenantMgtEndpoint + "/oauth2/tenant"
+ return api().post(endpoint, data.body, {headers: authHeader})
+ }
+
+
+}
\ No newline at end of file
diff --git a/custos-demo-gateway/src/service/user_management.js b/custos-demo-gateway/src/service/user_management.js
index d7b7483..4feac90 100644
--- a/custos-demo-gateway/src/service/user_management.js
+++ b/custos-demo-gateway/src/service/user_management.js
@@ -58,15 +58,28 @@
},
findUsers(params) {
- let authHeader = {'Authorization': 'Bearer ' + btoa(params.client_id + ':' + params.client_sec)}
- let endpoint = usermgtEndpoint + "/users";
- let id = params.username
- let param = {offset: params.offset, limit: params.limit, client_id: params.client_id, 'user.id': id}
- return api().get(endpoint,
- {
- params: param,
- headers: authHeader
- })
+ if (params.usertoken) {
+ let authHeader = {'Authorization': 'Bearer ' + params.usertoken, 'user-token': params.usertoken}
+ let endpoint = usermgtEndpoint + "/users";
+ let id = params.username
+ let param = {offset: params.offset, limit: params.limit, client_id: params.client_id, 'user.id': id}
+ return api().get(endpoint,
+ {
+ params: param,
+ headers: authHeader
+ })
+ } else {
+ let authHeader = {'Authorization': 'Bearer ' + btoa(params.client_id + ':' + params.client_sec)}
+ let endpoint = usermgtEndpoint + "/users";
+ let id = params.username
+ let param = {offset: params.offset, limit: params.limit, client_id: params.client_id, 'user.id': id}
+ return api().get(endpoint,
+ {
+ params: param,
+ headers: authHeader
+ })
+ }
+
},
addUserAttribute(params) {
@@ -125,13 +138,23 @@
},
updateProfile(params) {
- let authHeader = {'Authorization': 'Bearer ' + btoa(params.client_id + ':' + params.client_sec)}
- let endpoint = usermgtEndpoint + "/user/profile";
- console.log(authHeader)
- return api().put(endpoint, params.body
- , {
- headers: authHeader
- })
+ if (params.usertoken) {
+ let authHeader = {'Authorization': 'Bearer ' + params.usertoken, 'user-token': params.usertoken}
+ let endpoint = usermgtEndpoint + "/user/profile";
+
+ return api().put(endpoint, params.body
+ , {
+ headers: authHeader
+ })
+ } else {
+ let authHeader = {'Authorization': 'Bearer ' + btoa(params.client_id + ':' + params.client_sec)}
+ let endpoint = usermgtEndpoint + "/user/profile";
+
+ return api().put(endpoint, params.body
+ , {
+ headers: authHeader
+ })
+ }
},
@@ -155,6 +178,32 @@
headers: authHeader
})
+ },
+
+ grantAdminPrivilages(params) {
+ let authHeader = {'Authorization': 'Bearer ' + params.user_token}
+ let endpoint = usermgtEndpoint + "/user/admin"
+ return api().post(endpoint, params.body
+ , {
+ headers: authHeader
+ })
+ },
+
+ removeAdminPrivilages(params) {
+ let authHeader = {'Authorization': 'Bearer ' + params.user_token}
+ let endpoint = usermgtEndpoint + "/user/admin"
+ return new Promise((resolve, reject) => {
+ axios({
+ method: 'delete',
+ url: endpoint,
+ data: params.body,
+ headers: authHeader
+ }).then((resp) => {
+ resolve(resp)
+ }).catch(errr => {
+ reject(errr)
+ })
+ })
}
diff --git a/custos-demo-gateway/src/store/index.js b/custos-demo-gateway/src/store/index.js
index 4affb81..0c11190 100644
--- a/custos-demo-gateway/src/store/index.js
+++ b/custos-demo-gateway/src/store/index.js
@@ -8,6 +8,7 @@
import secret from './modules/secret.store'
import log from './modules/log.store'
import sharing from './modules/sharing.store'
+import tenant from './modules/tenant.store'
Vue.use(Vuex);
@@ -22,7 +23,8 @@
group,
secret,
log,
- sharing
+ sharing,
+ tenant
},
strict: debug,
plugins: debug ? [createLogger()] : [],
diff --git a/custos-demo-gateway/src/store/modules/agent.store.js b/custos-demo-gateway/src/store/modules/agent.store.js
index 1dcfd5d..eb783ff 100644
--- a/custos-demo-gateway/src/store/modules/agent.store.js
+++ b/custos-demo-gateway/src/store/modules/agent.store.js
@@ -110,7 +110,7 @@
SET_DEACTIVATED_AGENT(state, data) {
state.agents.forEach((agent) => {
if (agent.id == data) {
- agent.status = "DISABLED"
+ agent.status = "DEACTIVE"
}
})
},
diff --git a/custos-demo-gateway/src/store/modules/group.store.js b/custos-demo-gateway/src/store/modules/group.store.js
index 7735523..83b389d 100644
--- a/custos-demo-gateway/src/store/modules/group.store.js
+++ b/custos-demo-gateway/src/store/modules/group.store.js
@@ -18,7 +18,7 @@
try {
let resp = await group_management.createGroup(data)
if (resp.data != null) {
- let group = resp.data.groups[0];
+ let group = resp.data;
commit('SET_GROUP', group)
return group
}
diff --git a/custos-demo-gateway/src/store/modules/identity.store.js b/custos-demo-gateway/src/store/modules/identity.store.js
index 0bd66eb..37f5da1 100644
--- a/custos-demo-gateway/src/store/modules/identity.store.js
+++ b/custos-demo-gateway/src/store/modules/identity.store.js
@@ -17,7 +17,7 @@
let resp = await identity_management.getOpenIdConfig(data)
let baseURL = resp.data.authorization_endpoint
this.authorizartionURL = baseURL + "?response_type=code&client_id=" + data.client_id + "&" +
- "redirect_uri="+data.redirect_uri+"&scope=openid&kc_idp_hint=oidc"
+ "redirect_uri=" + data.redirect_uri + "&scope=openid&kc_idp_hint=oidc"
commit('SET_AUTH_ENDPOINT', this.authorizartionURL)
},
@@ -31,7 +31,7 @@
try {
let resp = await identity_management.localLogin(data)
commit('SET_AUTH_TOKEN', resp.data)
- }catch (e) {
+ } catch (e) {
return false
}
},
@@ -43,7 +43,7 @@
refresh_token: auth.getRefreshToken()
}
await identity_management.logout(dat)
- commit('CLEAR_AUTH_TOKEN', data)
+ await commit('CLEAR_AUTH_TOKEN', data)
},
// eslint-disable-next-line no-unused-vars
@@ -51,32 +51,58 @@
try {
let resp = auth.isLoggedIn()
if (!resp) {
- let dat = {
- client_id: data.client_id,
- client_sec: data.client_sec,
- refresh_token: auth.getRefreshToken()
+ if (auth.getRefreshToken() != null && auth.getRefreshToken() != '') {
+
+ let dat = {
+ client_id: data.client_id,
+ client_sec: data.client_sec,
+ refresh_token: auth.getRefreshToken()
+ }
+ let response = await identity_management.getTokenUsingRefreshToken(dat)
+ commit('SET_AUTH_TOKEN', response.data)
+ return auth.isLoggedIn()
}
- let response = await identity_management.getTokenUsingRefreshToken(dat)
- commit('SET_AUTH_TOKEN', response.data)
- return auth.isLoggedIn()
+ return false
}
return true
} catch (e) {
commit('CLEAR_AUTH_TOKEN')
+ return false
}
},
+ async authenticateTenantAdmin({commit}, data) {
+ try {
+ let resp = await identity_management.localLogin(data)
+ commit('SET_TENANT_CACHED_TOKENS', data)
+ commit('SET_AUTH_TOKEN', resp.data)
+ return true
+ } catch (e) {
+ return false
+ }
+ },
+
+ async logoutTenantAdmin({commit}, data) {
+ let dat = {
+ client_id: auth.getClientId(),
+ client_sec: auth.getClientSec(),
+ refresh_token: auth.getRefreshToken()
+ }
+ await identity_management.logout(dat)
+ await commit('RESET_TENANT_CACHED_TOKENS', data)
+ },
+
// eslint-disable-next-line no-unused-vars
- async isLoggedUserHasAdminAccess({commit, data}){
+ async isLoggedUserHasAdminAccess({commit, data}) {
return auth.isUserHasAdminAccess()
},
// eslint-disable-next-line no-unused-vars
- async getCurrentUserName({commit}, data){
- return auth.getLoggedUsername()
- }
+ async getCurrentUserName({commit}, data) {
+ return auth.getLoggedUsername()
+ }
}
@@ -99,11 +125,44 @@
state.refreshToken = data.refresh_token
},
+
+ // eslint-disable-next-line no-unused-vars
+ SET_TENANT_CACHED_TOKENS(state, data) {
+ auth.clearTenantAdminCachedAccessToken()
+ auth.clearTenantAdminCachedIdToken()
+ auth.clearTenantAdminCachedRefreshToken()
+ auth.setTenantAdminCachedIdToken(auth.getIdToken())
+ auth.setTenantAdminCachedAccessToken(auth.getAccessToken())
+ auth.setTenantAdminCachedRefreshToken(auth.getRefreshToken())
+ auth.setClientId(data.client_id)
+ auth.setClientSec(data.client_sec)
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ RESET_TENANT_CACHED_TOKENS(state, data) {
+ auth.clearIdToken()
+ auth.clearAccessToken()
+ auth.clearRefreshToken()
+ auth.setIdToken(auth.getTenantAdminCachedIdToken())
+ auth.setAccessToken(auth.getTenantAdminCachedAccessToken())
+ auth.setRefreshToken(auth.getTenantAdminCachedRefreshToken())
+ auth.clearTenantAdminCachedAccessToken()
+ auth.clearTenantAdminCachedIdToken()
+ auth.clearTenantAdminCachedRefreshToken()
+ auth.clearActiveClientID()
+ auth.clearActiveClientSec()
+ },
+
// eslint-disable-next-line no-unused-vars
CLEAR_AUTH_TOKEN(state, data) {
auth.clearIdToken()
auth.clearAccessToken()
auth.clearRefreshToken()
+ auth.clearTenantAdminCachedAccessToken()
+ auth.clearTenantAdminCachedIdToken()
+ auth.clearTenantAdminCachedRefreshToken()
+ auth.clearActiveClientID()
+ auth.clearActiveClientSec()
state.idToken = ''
state.accessToken = ''
state.refreshToken = ''
@@ -118,8 +177,9 @@
return auth.isLoggedIn()
},
+ // eslint-disable-next-line no-unused-vars
getAccessToken(state) {
- return state.accessToken;
+ return auth.getAccessToken()
},
diff --git a/custos-demo-gateway/src/store/modules/secret.store.js b/custos-demo-gateway/src/store/modules/secret.store.js
index 68897cf..3a808df 100644
--- a/custos-demo-gateway/src/store/modules/secret.store.js
+++ b/custos-demo-gateway/src/store/modules/secret.store.js
@@ -64,7 +64,7 @@
accessible_tokens: data.accessible_tokens
}
}
- console.log(dat)
+
let response = await secret_management.getAllCredentials(dat)
return response.data.metadata
},
diff --git a/custos-demo-gateway/src/store/modules/tenant.store.js b/custos-demo-gateway/src/store/modules/tenant.store.js
new file mode 100644
index 0000000..7e9a096
--- /dev/null
+++ b/custos-demo-gateway/src/store/modules/tenant.store.js
@@ -0,0 +1,93 @@
+import tenant_management from "@/service/tenant_management";
+import auth from "@/service/auth";
+
+
+const getDefaultState = () => {
+ return {
+ tenants: [],
+ activeClientId: '',
+ activeClientSec: ''
+ }
+}
+
+const state = getDefaultState()
+
+const actions = {
+
+
+ // eslint-disable-next-line no-unused-vars
+ async validateTenant({commit}, data) {
+ let response = await tenant_management.isVaildTenant(data)
+ if (response) {
+ return response.data.status
+ } else {
+ return false
+ }
+ },
+
+ async isTenantModeActivated() {
+ return auth.isTenantModeActivated()
+ },
+
+ async getActivatedClientId() {
+ //return auth.getClientId()
+ return auth.getClientId();
+ },
+
+ async getActivatedClientSecret() {
+ //return auth.getClientId()
+ return auth.getClientSec()
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async getTenants({commit}, data) {
+
+ let resp = await tenant_management.getTenants(data)
+ return resp.data
+ },
+
+
+ // eslint-disable-next-line no-unused-vars
+ async getTenantByClientId({commit}, data) {
+ let resp = await tenant_management.getTenantByClientId(data)
+ return resp.data
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async updateTenantStatus({commit}, data) {
+ let resp = await tenant_management.updateTenantStatus(data)
+ return resp.data
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async updateTenant({commit}, data) {
+ let resp = await tenant_management.updateTenant(data)
+ return resp.data
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async createAdminTenant({commit}, data) {
+ let resp = await tenant_management.createAdminTenant(data)
+ return resp.data
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async createChildTenant({commit}, data) {
+ let resp = await tenant_management.createChildTenant(data)
+ return resp.data
+ }
+
+}
+
+const mutations = {}
+
+const getters = {}
+
+
+export default {
+ namespaced: true,
+ state,
+ getters,
+ actions,
+ mutations
+}
\ No newline at end of file
diff --git a/custos-demo-gateway/src/store/modules/user.store.js b/custos-demo-gateway/src/store/modules/user.store.js
index 24b80be..9ed4af2 100644
--- a/custos-demo-gateway/src/store/modules/user.store.js
+++ b/custos-demo-gateway/src/store/modules/user.store.js
@@ -101,6 +101,17 @@
return await user_management.updateProfile(data)
},
+
+ // eslint-disable-next-line no-unused-vars
+ async grantAdminPrivilages({commit}, data) {
+ return await user_management.grantAdminPrivilages(data)
+ },
+
+ // eslint-disable-next-line no-unused-vars
+ async removeAdminPrivilages({commit}, data) {
+ return await user_management.removeAdminPrivilages(data)
+ },
+
// eslint-disable-next-line no-unused-vars
async reset({commit}, data){
commit('RESET')