diff --git a/dashboard/package.json b/dashboard/package.json index 61f3417..9f358c3 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -7,11 +7,12 @@ "node": ">=12" }, "dependencies": { - "@rancher/shell": "^0.3.23", + "@rancher/components": "0.1.3", + "@rancher/shell": "^0.3.28", + "@types/lodash": "4.14.184", "core-js": "3.21.1", "css-loader": "6.7.3", - "@types/lodash": "4.14.184", - "@rancher/components": "0.1.3", + "oidc-client-ts": "^2.2.4", "jszip": "3.10.1" }, "resolutions": { @@ -30,9 +31,10 @@ "lint": "./node_modules/.bin/eslint --max-warnings 0 --ext .js,.ts,.vue ." }, "devDependencies": { + "@babel/eslint-parser": "^7.22.5", "@rushstack/eslint-patch": "^1.3.2", "@vue/eslint-config-standard": "5.1.2", "@vue/eslint-config-typescript": "^11.0.3", - "@babel/eslint-parser": "^7.22.5" + "@types/is-url": "1.2.30" } } diff --git a/dashboard/pkg/epinio/config/epinio.ts b/dashboard/pkg/epinio/config/epinio.ts index d4075b1..30f32a5 100644 --- a/dashboard/pkg/epinio/config/epinio.ts +++ b/dashboard/pkg/epinio/config/epinio.ts @@ -53,19 +53,19 @@ export function init($plugin: any, store: any) { // Internal Types spoofedType({ - label: store.getters['type-map/labelFor']({ id: EPINIO_TYPES.INSTANCE }, 2), - type: EPINIO_TYPES.INSTANCE, + label: store.getters['type-map/labelFor']({ id: EPINIO_TYPES.CLUSTER }, 2), + type: EPINIO_TYPES.CLUSTER, product: EPINIO_PRODUCT_NAME, collectionMethods: [], schemas: [{ - id: EPINIO_TYPES.INSTANCE, + id: EPINIO_TYPES.CLUSTER, type: 'schema', collectionMethods: [], resourceFields: {}, }], getInstances: async() => await EpinioDiscovery.discover(store), }); - configureType(EPINIO_TYPES.INSTANCE, { + configureType(EPINIO_TYPES.CLUSTER, { isCreatable: false, isEditable: false, isRemovable: false, @@ -73,7 +73,7 @@ export function init($plugin: any, store: any) { showAge: false, canYaml: false, }); - configureType(EPINIO_TYPES.INSTANCE, { customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.INSTANCE }) }); + configureType(EPINIO_TYPES.CLUSTER, { customRoute: createEpinioRoute('c-cluster-resource', { resource: EPINIO_TYPES.CLUSTER }) }); // App resource configureType(EPINIO_TYPES.APP, { @@ -266,7 +266,7 @@ export function init($plugin: any, store: any) { AGE ]); - headers(EPINIO_TYPES.INSTANCE, [ + headers(EPINIO_TYPES.CLUSTER, [ STATE, { name: 'name', diff --git a/dashboard/pkg/epinio/dialog/LoginDialog.vue b/dashboard/pkg/epinio/dialog/LoginDialog.vue new file mode 100644 index 0000000..833b947 --- /dev/null +++ b/dashboard/pkg/epinio/dialog/LoginDialog.vue @@ -0,0 +1,199 @@ + + + + diff --git a/dashboard/pkg/epinio/l10n/en-us.yaml b/dashboard/pkg/epinio/l10n/en-us.yaml index 8bd7eee..90de0ae 100644 --- a/dashboard/pkg/epinio/l10n/en-us.yaml +++ b/dashboard/pkg/epinio/l10n/en-us.yaml @@ -45,6 +45,10 @@ asyncButton: action: Export success: Exported waiting: Exporting… + login: + action: Log In + success: Log In + waiting: Log In epinio: label: Epinio about: @@ -362,6 +366,14 @@ epinio: helmChart: Helm Chart warnings: noNamespace: There are no namespaces. Please create one before proceeding + login: + modal: + title: Log In + local: + tabLabel: Local + dex: + tabLabel: Auth Provider + prompt: Login via Auth Provider model: authConfig: provider: diff --git a/dashboard/pkg/epinio/list/namespaces.vue b/dashboard/pkg/epinio/list/namespaces.vue index 36cf703..d63d91f 100644 --- a/dashboard/pkg/epinio/list/namespaces.vue +++ b/dashboard/pkg/epinio/list/namespaces.vue @@ -1,7 +1,7 @@ + + diff --git a/dashboard/pkg/epinio/pages/c/_cluster/dashboard.vue b/dashboard/pkg/epinio/pages/c/_cluster/dashboard.vue index 3f69ed9..dd51951 100644 --- a/dashboard/pkg/epinio/pages/c/_cluster/dashboard.vue +++ b/dashboard/pkg/epinio/pages/c/_cluster/dashboard.vue @@ -119,7 +119,7 @@ export default Vue.extend({ const nodeMetrics = await this.$store.dispatch(`cluster/request`, { url: `/k8s/clusters/${ id }/v1/metrics.k8s.io.nodemetrics` }, { root: true }); - const currentCluster = this.$store.getters[`${ EPINIO_MGMT_STORE }/byId`](EPINIO_TYPES.INSTANCE, id); + const currentCluster = this.$store.getters[`${ EPINIO_MGMT_STORE }/byId`](EPINIO_TYPES.CLUSTER, id); const cpu = { total: parseSi(currentCluster.mgmtCluster?.status?.capacity?.cpu, null), diff --git a/dashboard/pkg/epinio/pages/index.vue b/dashboard/pkg/epinio/pages/index.vue index 30278ce..4cad827 100644 --- a/dashboard/pkg/epinio/pages/index.vue +++ b/dashboard/pkg/epinio/pages/index.vue @@ -5,14 +5,12 @@ import Loading from '@shell/components/Loading.vue'; import Link from '@shell/components/formatter/Link.vue'; import ResourceTable from '@shell/components/ResourceTable.vue'; import { EPINIO_MGMT_STORE, EPINIO_TYPES } from '../types'; -import Resource from '@shell/plugins/dashboard-store/resource-class'; + import AsyncButton from '@shell/components/AsyncButton.vue'; import { _MERGE } from '@shell/plugins/dashboard-store/actions'; - -interface Cluster extends Resource{ - id: string, - state: string, -} +import epinioAuth, { EpinioAuthTypes } from '../utils/auth'; +import EpinioCluster, { EpinioInfoPath } from '../models/cluster'; +import PromptModal from '@shell/components/PromptModal.vue'; interface Data { clustersSchema: any; @@ -21,19 +19,23 @@ interface Data { // Data, Methods, Computed, Props export default Vue.extend({ components: { - AsyncButton, Loading, Link, ResourceTable + AsyncButton, Loading, Link, ResourceTable, PromptModal }, layout: 'plain', async fetch() { - await this.$store.dispatch(`${ EPINIO_MGMT_STORE }/findAll`, { type: EPINIO_TYPES.INSTANCE }); + await this.$store.dispatch(`${ EPINIO_MGMT_STORE }/findAll`, { type: EPINIO_TYPES.CLUSTER }); - this.clusters.forEach((c: Cluster) => this.testCluster(c)); + this.clusters.forEach((c: EpinioCluster) => this.testCluster(c)); }, data() { - return { clustersSchema: this.$store.getters[`${ EPINIO_MGMT_STORE }/schemaFor`](EPINIO_TYPES.INSTANCE) }; + return { + clustersSchema: this.$store.getters[`${ EPINIO_MGMT_STORE }/schemaFor`](EPINIO_TYPES.CLUSTER), + version: null, + infoUrl: EpinioInfoPath + }; }, mounted() { @@ -54,18 +56,18 @@ export default Vue.extend({ }, canRediscover() { - return !this.clusters.find((c: Cluster) => c.state === 'updating'); + return !this.clusters.find((c: EpinioCluster) => c.state === 'updating'); }, clusters() { - return this.$store.getters[`${ EPINIO_MGMT_STORE }/all`](EPINIO_TYPES.INSTANCE); + return this.$store.getters[`${ EPINIO_MGMT_STORE }/all`](EPINIO_TYPES.CLUSTER); } }, methods: { async rediscover(buttonCb: (success: boolean) => void) { - await this.$store.dispatch(`${ EPINIO_MGMT_STORE }/findAll`, { type: EPINIO_TYPES.INSTANCE, opt: { force: true, load: _MERGE } }); - this.clusters.forEach((c: Cluster) => this.testCluster(c)); + await this.$store.dispatch(`${ EPINIO_MGMT_STORE }/findAll`, { type: EPINIO_TYPES.CLUSTER, opt: { force: true, load: _MERGE } }); + this.clusters.forEach((c: EpinioCluster) => this.testCluster(c)); buttonCb(true); }, @@ -75,12 +77,12 @@ export default Vue.extend({ } }, - setClusterState(cluster: Cluster, state: string, metadataStateObj: { transitioning: boolean, error: boolean, message: string }) { + setClusterState(cluster: EpinioCluster, state: string, metadataStateObj: { state: { transitioning: boolean, error: boolean, message: string }}) { Vue.set(cluster, 'state', state); Vue.set(cluster, 'metadata', metadataStateObj); }, - testCluster(c: Cluster) { + testCluster(c: EpinioCluster) { // Call '/ready' on each cluster. If there's a network error there's a good chance the user has to permit an invalid cert this.setClusterState(c, 'updating', { state: { @@ -89,12 +91,10 @@ export default Vue.extend({ } }); - // Calls to `/ready` currently throw CORS error (but not `/api/v1`). This code block will probably change given auth stuff - // this.$store.dispatch('epinio/request', { opt: { url: `/ready` }, clusterId: c.id }) - this.$store.dispatch(`epinio/request`, { opt: { url: `/api/v1/info` }, clusterId: c.id }) - // .then(() => this.$store.dispatch(`epinio/request`, { opt: { url: `/api/v1/info` }, clusterId: c.id })) + this.$store.dispatch(`epinio/request`, { opt: { url: this.infoUrl, redirectUnauthorized: false }, clusterId: c.id }) .then((res: any) => { Vue.set(c, 'version', res?.version); + Vue.set(c, 'oidcEnabled', res?.oidc_enabled); this.setClusterState(c, 'available', { state: { transitioning: false } }); }) .catch((e: Error) => { @@ -114,7 +114,24 @@ export default Vue.extend({ }); } }); - } + }, + + async login(c: EpinioCluster) { + const isLoggedIn = await epinioAuth.isLoggedIn(c.createAuthConfig(EpinioAuthTypes.AGNOSTIC)); + + if (isLoggedIn) { + this.$router.push({ + name: 'epinio-c-cluster-dashboard', + params: { cluster: c.id } + }); + } else { + await this.$store.dispatch('epinio/promptModal', { + resources: c, + component: 'LoginDialog', + modalWidth: '450px', + }, { root: true }); + } + }, } }); @@ -142,7 +159,6 @@ export default Vue.extend({ :rows="clusters" :schema="clustersSchema" :table-actions="false" - :row-actions="false" > - @@ -202,6 +216,10 @@ div.root { height: 40px; display: flex; align-items: center; + + a { + cursor: pointer; + } } } } diff --git a/dashboard/pkg/epinio/routing/epinio-routing.ts b/dashboard/pkg/epinio/routing/epinio-routing.ts index 6e5be8a..ac2727c 100644 --- a/dashboard/pkg/epinio/routing/epinio-routing.ts +++ b/dashboard/pkg/epinio/routing/epinio-routing.ts @@ -12,6 +12,7 @@ import ListEpinioResource from '../pages/c/_cluster/_resource/index.vue'; import CreateEpinioResource from '../pages/c/_cluster/_resource/create.vue'; import ViewEpinioResource from '../pages/c/_cluster/_resource/_id.vue'; import ViewEpinioNsResource from '../pages/c/_cluster/_resource/_namespace/_id.vue'; +import AuthVerify from '../pages/auth/verify.vue'; const meta = { product: EPINIO_PRODUCT_NAME, @@ -19,6 +20,11 @@ const meta = { }; const routes: RouteConfig[] = [{ + name: `${ EPINIO_PRODUCT_NAME }-auth-verify`, + path: `/:product/auth/verify`, + component: AuthVerify, + meta +}, { name: `${ EPINIO_PRODUCT_NAME }-c-cluster-dashboard`, path: `/:product/c/:cluster/dashboard`, component: Dashboard, diff --git a/dashboard/pkg/epinio/store/epinio-mgmt-store/actions.ts b/dashboard/pkg/epinio/store/epinio-mgmt-store/actions.ts index ca932d4..e168f1d 100644 --- a/dashboard/pkg/epinio/store/epinio-mgmt-store/actions.ts +++ b/dashboard/pkg/epinio/store/epinio-mgmt-store/actions.ts @@ -31,7 +31,7 @@ export default { // Load management style schemas const spoofedSchemas = rootGetters['type-map/spoofedSchemas'](EPINIO_PRODUCT_NAME); - const instances = spoofedSchemas.find((schema: any) => schema.id === EPINIO_TYPES.INSTANCE); + const instances = spoofedSchemas.find((schema: any) => schema.id === EPINIO_TYPES.CLUSTER); const res = { data: [instances] }; diff --git a/dashboard/pkg/epinio/store/epinio-store/actions.ts b/dashboard/pkg/epinio/store/epinio-store/actions.ts index 450bb50..031d4c9 100644 --- a/dashboard/pkg/epinio/store/epinio-store/actions.ts +++ b/dashboard/pkg/epinio/store/epinio-store/actions.ts @@ -3,12 +3,15 @@ import { handleSpoofedRequest } from '@shell/plugins/dashboard-store/actions'; import { classify } from '@shell/plugins/dashboard-store/classify'; import { normalizeType } from '@shell/plugins/dashboard-store/normalize'; import { NAMESPACE_FILTERS } from '@shell/store/prefs'; -import { base64Encode } from '@shell/utils/crypto'; import { createNamespaceFilterKeyWithId } from '@shell/utils/namespace-filter'; import { parse as parseUrl, stringify as unParseUrl } from '@shell/utils/url'; +import epinioAuth, { EpinioAuthTypes } from '../../utils/auth'; + import { EpinioInfo, EpinioVersion, EPINIO_MGMT_STORE, EPINIO_PRODUCT_NAME, EPINIO_STANDALONE_CLUSTER_NAME, EPINIO_TYPES } from '../../types'; +import EpinioCluster from '../../models/cluster'; +import { RedirectToError } from '@shell/utils/error'; const createId = (schema: any, resource: any) => { const name = resource.meta?.name || resource.name; @@ -36,17 +39,17 @@ export default { commit('remove', obj); }, - async request({ rootGetters, dispatch, getters }: any, { + async request(context: any, { opt, type, clusterId, growlOnError = false }: any) { + const { rootGetters, dispatch, getters } = context; + const spoofedRes = await handleSpoofedRequest(rootGetters, EPINIO_PRODUCT_NAME, opt, EPINIO_PRODUCT_NAME); if (spoofedRes) { return spoofedRes; } - // @TODO queue/defer duplicate requests - opt.depaginate = opt.depaginate !== false; opt.url = opt.url.replace(/\/*$/g, ''); const isSingleProduct = rootGetters['isSingleProduct']; @@ -58,13 +61,13 @@ export default { ps = dispatch('findSingleProductCNSI').then((cnsi: any) => `/pp/v1/direct/r/${ cnsi?.guid }`); } } else { - ps = dispatch(`${ EPINIO_MGMT_STORE }/findAll`, { type: EPINIO_TYPES.INSTANCE }, { root: true }).then(() => ''); + ps = dispatch(`${ EPINIO_MGMT_STORE }/findAll`, { type: EPINIO_TYPES.CLUSTER }, { root: true }).then(() => ''); } // opt.httpsAgent = new https.Agent({ rejectUnauthorized: false }); return await ps - .then((prependPath = opt?.prependPath) => { + .then(async(prependPath = opt?.prependPath) => { if (isSingleProduct) { if (opt.url.startsWith('/')) { opt.url = prependPath + opt.url; @@ -78,12 +81,14 @@ export default { } } else { const currentClusterId = clusterId || rootGetters['clusterId']; - const currentCluster = rootGetters[`${ EPINIO_MGMT_STORE }/byId`](EPINIO_TYPES.INSTANCE, currentClusterId); + const currentCluster: EpinioCluster = rootGetters[`${ EPINIO_MGMT_STORE }/byId`](EPINIO_TYPES.CLUSTER, currentClusterId); - opt.headers = { - ...opt.headers, - Authorization: `Basic ${ base64Encode(`${ currentCluster.username }:${ currentCluster.password }`) }` - }; + if (currentCluster.createAuthConfig) { + opt.headers = { + ...opt.headers, + Authorization: await epinioAuth.authHeader(currentCluster.createAuthConfig(EpinioAuthTypes.AGNOSTIC)) + }; + } opt.url = `${ currentCluster.api }${ opt.url }`; } @@ -92,17 +97,7 @@ export default { }) .then((res) => { if ( opt.depaginate ) { - // @TODO but API never sends it - /* - return new Promise((resolve, reject) => { - const next = res.pagination.next; - if (!next ) [ - return resolve(); - } - - dispatch('request') - }); - */ + throw Error('depaginate not supported'); } if ( opt.responseType ) { @@ -128,9 +123,12 @@ export default { const res = err.response; // Go to the logout page for 401s, unless redirectUnauthorized specifically disables (for the login page) - if ( opt.redirectUnauthorized !== false && (process as any).client && res.status === 401 ) { - // return Promise.reject(err); - dispatch('auth/logout', opt.logoutOnError, { root: true }); + if ( opt.redirectUnauthorized !== false && res.status === 401 ) { + if (isSingleProduct) { + dispatch('auth/logout', opt.logoutOnError, { root: true }); + } else { + return Promise.reject(new RedirectToError('Auth failed, return user to epinio cluster list', `/epinio`)); + } } else if (growlOnError) { dispatch('growl/fromError', { title: `Epinio Request to ${ opt.url }`, err }, { root: true }); } @@ -165,6 +163,12 @@ export default { } }, + redirect(ctx: any, location: any) { + const router = (this as any).$router; + + router.replace(location); + }, + async onLogout({ dispatch, commit }: any) { await dispatch(`unsubscribe`); await commit('reset'); @@ -228,7 +232,7 @@ export default { }; const spoofedSchemas = rootGetters['type-map/spoofedSchemas'](EPINIO_PRODUCT_NAME); - const excludeInstances = spoofedSchemas.filter((schema: any) => schema.id !== EPINIO_TYPES.INSTANCE); + const excludeInstances = spoofedSchemas.filter((schema: any) => schema.id !== EPINIO_TYPES.CLUSTER); const data = [ ...res.data, @@ -335,4 +339,5 @@ export default { return info; }, + }; diff --git a/dashboard/pkg/epinio/types.ts b/dashboard/pkg/epinio/types.ts index 89a6226..8b6b143 100644 --- a/dashboard/pkg/epinio/types.ts +++ b/dashboard/pkg/epinio/types.ts @@ -21,7 +21,7 @@ export const EPINIO_TYPES = { SERVICE_INSTANCE: 'services', // Internal DASHBOARD: 'dashboard', - INSTANCE: 'instance', + CLUSTER: 'cluster', APP_ACTION: 'application-action', APP_INSTANCE: 'application-instance', }; diff --git a/dashboard/pkg/epinio/utils/auth.ts b/dashboard/pkg/epinio/utils/auth.ts new file mode 100644 index 0000000..896fa00 --- /dev/null +++ b/dashboard/pkg/epinio/utils/auth.ts @@ -0,0 +1,225 @@ +import { User, UserManager } from 'oidc-client-ts'; +import { base64Encode } from '@shell/utils/crypto'; + +/* eslint-disable no-unused-vars */ +export enum EpinioAuthTypes { + LOCAL = 'local', + DEX = 'dex', + AGNOSTIC = 'agnostic' +} +/* eslint-enable no-unused-vars */ + +export interface EpinioAuthUser { + email: string, + name: string, +} + +export interface EpinioAuthDexConfig { + dashboardUrl: string, + dexUrl: string, +} + +export interface EpinioAuthLocalConfig { + username: string, + password: string, + $axios?: any, +} + +export interface EpinioAuthConfig { + type: EpinioAuthTypes, + epinioUrl: string, + dexConfig?: EpinioAuthDexConfig, + localConfig?: EpinioAuthLocalConfig +} + +class EpinioAuth { + private dexUserManager?: UserManager; + private localUserManager?: { + epinioUrl: string, + config: EpinioAuthLocalConfig + }; + + private isLocal() { + return this.localUserManager?.config.username && this.localUserManager?.config.password; + } + + async isLoggedIn(config: EpinioAuthConfig) { + if (!config || (config.type === EpinioAuthTypes.LOCAL || config.type === EpinioAuthTypes.AGNOSTIC)) { + if (this.isLocal()) { + return true; + } + } + + if (!config || (config.type === EpinioAuthTypes.DEX || config.type === EpinioAuthTypes.AGNOSTIC)) { + if (!this.dexUserManager && config?.dexConfig) { + await this.initialiseDex(config.dexConfig); + } + const dexUser = await this.dexUserManager?.getUser(); + + return dexUser && dexUser?.profile.iss === config?.dexConfig?.dexUrl; + } + + return false; + } + + async login(config: EpinioAuthConfig): Promise { + if (await this.isLoggedIn(config)) { + return; + } + + switch (config.type) { + case EpinioAuthTypes.DEX: + if (!config.dexConfig) { + throw new Error('dexConfig required'); + } + if (!this.dexUserManager) { + this.initialiseDex(config.dexConfig); + } + + await this.dexUserManager?.signinPopup(); + + delete this.localUserManager; + + return this.user(); + case EpinioAuthTypes.LOCAL: + if (!config.localConfig) { + throw new Error('localConfig required'); + } + + // Validate + try { + await config.localConfig.$axios({ + url: `${ config.epinioUrl }/api/v1/me`, + headers: { Authorization: `Basic ${ base64Encode(`${ config.localConfig?.username }:${ config.localConfig?.password }`) }` } + }); + } catch (err: any) { + if ( !err || !err.response ) { + return Promise.reject(err); + } + + const res = err.response; + + if (res.status === 401) { + return Promise.reject(new Error('Invalid Credentials')); + } + + return Promise.reject(res); + } + + await this.logout(); + + this.localUserManager = { + epinioUrl: config.epinioUrl, + config: config.localConfig + }; + + return this.user(); + default: + throw new Error(`Epinio Auth type not provided: ${ config.type }`); + } + } + + async user(): Promise { + if (this.isLocal()) { + return { + email: this.localUserManager?.config.username as string, + name: this.localUserManager?.config.username as string, + }; + } + + try { + const dexUser = await this.dexUserManager?.getUser(); + + if (!dexUser) { + return; + } + + return { + email: dexUser.profile.email || '', + name: dexUser.profile.name || '' + }; + } catch {} + } + + async authHeader(config: EpinioAuthConfig) { + let dexUser: User | null | undefined = null; + let type: string; + + if ((config.type === EpinioAuthTypes.LOCAL || config.type === EpinioAuthTypes.AGNOSTIC) && this.isLocal()) { + return `Basic ${ base64Encode(`${ this.localUserManager?.config.username }:${ this.localUserManager?.config.password }`) }`; + } + + if ((config.type === EpinioAuthTypes.DEX || config.type === EpinioAuthTypes.AGNOSTIC)) { + // Attempt dex + if (!this.dexUserManager && config.dexConfig) { + this.initialiseDex(config.dexConfig); + } + dexUser = await this.dexUserManager?.getUser(); + + if (dexUser) { + type = dexUser.token_type; + + return `${ dexUser.token_type[0].toUpperCase() + type.slice(1) } ${ dexUser?.access_token }`; + } + } + } + + async logout(config?: EpinioAuthConfig) { + if (!config || (config.type === EpinioAuthTypes.AGNOSTIC || config.type === EpinioAuthTypes.LOCAL)) { + delete this.localUserManager; + } + + if (!config || (config.type === EpinioAuthTypes.AGNOSTIC || config.type === EpinioAuthTypes.DEX )) { + if (!this.dexUserManager && config?.dexConfig) { + await this.initialiseDex(config.dexConfig); + } + + await this.dexUserManager?.removeUser(); + await this.dexUserManager?.clearStaleState(); + } + } + + async dexRedirect(route: { url: string, query: Record}, config: EpinioAuthDexConfig) { + if (!this.dexUserManager) { + await this.initialiseDex(config); + } + + await this.dexUserManager?.signinPopupCallback(route.url); + } + + async initialiseDex(config?: EpinioAuthDexConfig) { + if (!config) { + throw new Error('config is required'); + } + if (this.dexUserManager) { + this.logout(); + } + + const dexUrl = config.dexUrl; + + if (!dexUrl) { + throw new Error(`Missing dexUrl: ${ config }`); + } + + // Note - if you be thinking extraTokenParams, extraQueryParams, scope are used here, you be wrong + + this.dexUserManager = new UserManager({ + authority: dexUrl, + metadata: { // Supplying the metadata skips a network request to well-known/openid-configuration + issuer: dexUrl, + authorization_endpoint: `${ dexUrl }/auth`, + userinfo_endpoint: dexUrl, + end_session_endpoint: dexUrl, + token_endpoint: `${ dexUrl }/token`, + }, + client_id: 'rancher-dashboard', + redirect_uri: `${ config.dashboardUrl }/epinio/auth/verify/`, // Note - must contain trailing forward slash + scope: 'openid offline_access profile email groups audience:server:client_id:epinio-api federated:id', + response_type: 'code', + }); + } +} + +const epinioAuth = new EpinioAuth(); + +export default epinioAuth; diff --git a/dashboard/pkg/epinio/utils/epinio-discovery.ts b/dashboard/pkg/epinio/utils/epinio-discovery.ts index e65641e..dcc2817 100644 --- a/dashboard/pkg/epinio/utils/epinio-discovery.ts +++ b/dashboard/pkg/epinio/utils/epinio-discovery.ts @@ -1,8 +1,7 @@ -import { EPINIO_TYPES } from '../types'; - import { MANAGEMENT } from '@shell/config/types'; import { ingressFullPath } from '@shell/models/networking.k8s.io.ingress'; -import { allHash } from '@shell/utils/promise'; +import epinioAuth, { EpinioAuthTypes } from '../utils/auth'; +import EpinioCluster from '../models/cluster'; export default { ingressUrl(clusterId: string) { @@ -18,34 +17,22 @@ export default { // Get the url first, if it has this it's highly likely it's an epinio cluster const epinioIngress = await store.dispatch(`cluster/request`, { url: this.ingressUrl(c.id) }, { root: true }); const url = ingressFullPath(epinioIngress, epinioIngress.spec.rules?.[0]); + const loggedIn = await epinioAuth.isLoggedIn({ + type: EpinioAuthTypes.AGNOSTIC, + epinioUrl: url, + dexConfig: { + dashboardUrl: window.origin, + dexUrl: url.replace('epinio', 'auth') + }, + }); - let username; - let password; - - if (url) { - // TODO: RC hack - username = 'admin'; - password = 'password'; - } else { - // TODO: RC old - const epinio: any = await allHash({ authData: store.dispatch(`cluster/request`, { url: `/k8s/clusters/${ c.id }/v1/secrets/epinio/default-epinio-user` }, { root: true }) }); - - username = epinio.authData.data.username; - password = epinio.authData.data.password; - } - - epinioClusters.push({ + epinioClusters.push(new EpinioCluster({ id: c.id, name: c.spec.displayName, api: url, - readyApi: `${ url }/ready`, - // username: base64Decode(username), - // password: base64Decode(password), - username, - password, - type: EPINIO_TYPES.INSTANCE, + loggedIn: !!loggedIn, mgmtCluster: c - }); + }, { rootGetters: store.getters })); } catch (err) { console.info(`Skipping epinio discovery for ${ c.spec.displayName }`, err); // eslint-disable-line no-console } diff --git a/dashboard/pkg/epinio/windowComponents/ApplicationSocketMixin.js b/dashboard/pkg/epinio/windowComponents/ApplicationSocketMixin.js index 03d8f93..3b52513 100644 --- a/dashboard/pkg/epinio/windowComponents/ApplicationSocketMixin.js +++ b/dashboard/pkg/epinio/windowComponents/ApplicationSocketMixin.js @@ -61,7 +61,7 @@ export default { prependPath = `/pp/v1/direct/ws/${ cnsi?.guid }`; } else { const currentClusterId = this.$store.getters['clusterId']; - const currentCluster = this.$store.getters[`${ EPINIO_MGMT_STORE }/byId`](EPINIO_TYPES.INSTANCE, currentClusterId); + const currentCluster = this.$store.getters[`${ EPINIO_MGMT_STORE }/byId`](EPINIO_TYPES.CLUSTER, currentClusterId); api = currentCluster.api; } diff --git a/dashboard/yarn.lock b/dashboard/yarn.lock index 01b90e3..b737946 100644 --- a/dashboard/yarn.lock +++ b/dashboard/yarn.lock @@ -1008,7 +1008,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.3.tgz#cd502a6a0b6e37d7ad72ce7e71a7160a3ae36f7e" integrity sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ== -"@babel/core@^7.1.0", "@babel/core@^7.11.0", "@babel/core@^7.12.16", "@babel/core@^7.12.3", "@babel/core@^7.14.0", "@babel/core@^7.4.4", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": +"@babel/core@^7.1.0", "@babel/core@^7.11.0", "@babel/core@^7.12.16", "@babel/core@^7.12.3", "@babel/core@^7.14.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": version "7.22.1" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.1.tgz#5de51c5206f4c6f5533562838337a603c1033cfd" integrity sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA== @@ -1931,7 +1931,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.22.1" "@babel/helper-plugin-utils" "^7.21.5" -"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.14.1", "@babel/preset-env@^7.4.4": +"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.14.1": version "7.22.4" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.4.tgz#c86a82630f0e8c61d9bb9327b7b896732028cbed" integrity sha512-c3lHOjbwBv0TkhYCr+XCR6wKcSZ1QbQTVdSkZUaVpLv8CVWotBMArWUi5UAJrcrQaEnleVkkvaV8F/pmc/STZQ== @@ -2903,16 +2903,16 @@ webpack-node-externals "^3.0.0" webpackbar "^4.0.0" -"@nuxtjs/axios@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.12.0.tgz#50692340e64ec838f167d292d59b1cc2a0e2dbef" - integrity sha512-VQI9Nnf12jWknldrgCNGzCQxnWO3/CvMwrkWKNUr3WtGYuOKryUOd1XXxDbaJmopfX4SGjKvDL1G6qTkWLiPew== +"@nuxtjs/axios@5.13.6": + version "5.13.6" + resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.13.6.tgz#6f4bbd98a3a7799a5d2c0726c6ad2a98aa111881" + integrity sha512-XS+pOE0xsDODs1zAIbo95A0LKlilvJi8YW0NoXYuq3/jjxGgWDxizZ6Yx0AIIjZOoGsXJOPc0/BcnSEUQ2mFBA== dependencies: - "@nuxtjs/proxy" "^2.0.0" - axios "^0.19.2" - axios-retry "^3.1.8" - consola "^2.14.0" - defu "^2.0.4" + "@nuxtjs/proxy" "^2.1.0" + axios "^0.21.1" + axios-retry "^3.1.9" + consola "^2.15.3" + defu "^5.0.0" "@nuxtjs/eslint-config-typescript@6.0.1": version "6.0.1" @@ -2937,7 +2937,7 @@ eslint-plugin-unicorn "^28.0.2" eslint-plugin-vue "^7.9.0" -"@nuxtjs/proxy@^2.0.0": +"@nuxtjs/proxy@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@nuxtjs/proxy/-/proxy-2.1.0.tgz#fa7715a11d237fa1273503c4e9e137dd1bf5575b" integrity sha512-/qtoeqXgZ4Mg6LRg/gDUZQrFpOlOdHrol/vQYMnKu3aN3bP90UfOUB3QSDghUUK7OISAJ0xp8Ld78aHyCTcKCQ== @@ -2975,10 +2975,10 @@ dependencies: lodash.debounce "4.0.8" -"@rancher/shell@^0.3.23": - version "0.3.23" - resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-0.3.23.tgz#9f334f2e9034e27d7edf6f8a12af597790e31d14" - integrity sha512-nnfrpEBR/JMCS2MGRhgAygr9hIOsO1cVB+1jvbo/q8VVLZQTlNmVNcl2YyOuCvo+tE6J/svD4rQmPwyIeJ6EQA== +"@rancher/shell@^0.3.28": + version "0.3.28" + resolved "https://registry.yarnpkg.com/@rancher/shell/-/shell-0.3.28.tgz#6bd33632df298a210ee7d6a9a8bc7a2babdae64b" + integrity sha512-NONiaUDLS69mJKixF4HMOvackxUZPQtR1Dg0dNcDWQle6HzBV+WDVDzWtsSxBnSuav0FRZM9NCDDZkv0Od+nIQ== dependencies: "@aws-sdk/client-ec2" "3.1.0" "@aws-sdk/client-eks" "3.1.0" @@ -2990,7 +2990,7 @@ "@novnc/novnc" "1.2.0" "@nuxt/types" "2.14.6" "@nuxt/typescript-build" "2.1.0" - "@nuxtjs/axios" "5.12.0" + "@nuxtjs/axios" "5.13.6" "@nuxtjs/eslint-config-typescript" "6.0.1" "@nuxtjs/webpack-profile" "0.1.0" "@popperjs/core" "2.4.4" @@ -3059,9 +3059,6 @@ papaparse "5.3.0" portal-vue "2.1.7" rancher-icons rancher/icons#v2.0.16 - require-extension-hooks "0.3.3" - require-extension-hooks-babel "1.0.0" - require-extension-hooks-vue "3.0.0" sass "1.51.0" sass-loader "10.2.1" serve-static "1.14.1" @@ -3341,6 +3338,11 @@ dependencies: "@types/node" "*" +"@types/is-url@1.2.30": + version "1.2.30" + resolved "https://registry.yarnpkg.com/@types/is-url/-/is-url-1.2.30.tgz#85567e8bee4fee69202bc3448f9fb34b0d56c50a" + integrity sha512-AnlNFwjzC8XLda5VjRl4ItSd8qp8pSNowvsut0WwQyBWHpOxjxRJm8iO6uETWqEyLdYdb9/1j+Qd9gQ4l5I4fw== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" @@ -4032,21 +4034,6 @@ postcss "^8.4.14" source-map "^0.6.1" -"@vue/component-compiler-utils@^2.3.1": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz#aa46d2a6f7647440b0b8932434d22f12371e543b" - integrity sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw== - dependencies: - consolidate "^0.15.1" - hash-sum "^1.0.2" - lru-cache "^4.1.2" - merge-source-map "^1.1.0" - postcss "^7.0.14" - postcss-selector-parser "^5.0.0" - prettier "1.16.3" - source-map "~0.6.1" - vue-template-es2015-compiler "^1.9.0" - "@vue/component-compiler-utils@^3.1.0", "@vue/component-compiler-utils@^3.1.2": version "3.3.0" resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz#f9f5fb53464b0c37b2c8d2f3fbfe44df60f61dc9" @@ -4745,21 +4732,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -axios-retry@^3.1.8: - version "3.5.0" - resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.5.0.tgz#32206b3e6555169488eded232527e36c8ce6e545" - integrity sha512-g48qNrLX30VU6ECWltpFCPegKK6dWzMDYv2o83W2zUL/Zh/SLXbT6ksGoKqYZHtghzqeeXhZBcSXJkO1fPbCcw== +axios-retry@^3.1.9: + version "3.8.1" + resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.8.1.tgz#4bb53f87ea537bce904c477e5c2808571066acbb" + integrity sha512-4XseuArB4CEbfLRtMpUods2q8MLBvD4r8ifKgK4SP2FRgzQIPUDpzZ+cjQ/19eu3w2UpKgkJA+myEh2BYDSjqQ== dependencies: "@babel/runtime" "^7.15.4" is-retry-allowed "^2.2.0" -axios@^0.19.2: - version "0.19.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" - integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== - dependencies: - follow-redirects "1.5.10" - axios@^0.21.1: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" @@ -5973,7 +5953,7 @@ connect@^3.7.0: parseurl "~1.3.3" utils-merge "1.0.1" -consola@^2.10.0, consola@^2.14.0, consola@^2.15.0, consola@^2.15.3, consola@^2.6.0, consola@^2.9.0: +consola@^2.10.0, consola@^2.15.0, consola@^2.15.3, consola@^2.6.0, consola@^2.9.0: version "2.15.3" resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== @@ -6014,7 +5994,7 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^1.3.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -6254,6 +6234,11 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" + integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== + css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -6366,14 +6351,6 @@ css-select@^4.1.3: domutils "^2.8.0" nth-check "^2.0.1" -css-selector-tokenizer@^0.7.0: - version "0.7.3" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" - integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg== - dependencies: - cssesc "^3.0.0" - fastparse "^1.1.2" - css-tree@1.0.0-alpha.37: version "1.0.0-alpha.37" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" @@ -7174,13 +7151,6 @@ debug@4.3.2: dependencies: ms "2.1.2" -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -7294,11 +7264,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -defu@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/defu/-/defu-2.0.4.tgz#09659a6e87a8fd7178be13bd43e9357ebf6d1c46" - integrity sha512-G9pEH1UUMxShy6syWk01VQSRVs3CDWtlxtZu7A+NyqjxaCA4gSlWAKDBx6QiUEKezqS8+DUlXLI14Fp05Hmpwg== - defu@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/defu/-/defu-4.0.1.tgz#9d7d7a48f9295f08285d153dcff174c89b9bcb22" @@ -8645,11 +8610,6 @@ fast-xml-parser@^3.16.0: dependencies: strnum "^1.0.4" -fastparse@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - fastq@^1.6.0: version "1.15.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" @@ -8855,13 +8815,6 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - follow-redirects@^1.0.0, follow-redirects@^1.14.0: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" @@ -9109,13 +9062,6 @@ functions-have-names@^1.2.2, functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -generic-names@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-1.0.3.tgz#2d786a121aee508876796939e8e3bff836c20917" - integrity sha512-b6OHfQuKasIKM9b6YPkX+KUj/TLBTx3B/1aT1T5F12FEuEqyFMdr59OMS53aoaSw8eVtapdqieX6lbg5opaOhA== - dependencies: - loader-utils "^0.2.16" - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -9437,11 +9383,6 @@ has-bigints@^1.0.1, has-bigints@^1.0.2: resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - integrity sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -9879,11 +9820,6 @@ iconv-lite@0.6: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -icss-replace-symbols@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg== - icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" @@ -11103,11 +11039,6 @@ jquery@3.5.1: resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5" integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg== -js-base64@^2.1.9: - version "2.6.4" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" - integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ== - js-beautify@^1.6.12: version "1.14.8" resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.8.tgz#e0c570c15b5445b006de6d9a3e70fb62f9e408e9" @@ -11377,6 +11308,11 @@ just-extend@^4.0.2: resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.2.1.tgz#ef5e589afb61e5d66b24eca749409a8939a8c744" integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== +jwt-decode@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== + killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" @@ -11879,7 +11815,7 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== -merge-source-map@^1.0.3, merge-source-map@^1.1.0: +merge-source-map@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== @@ -12589,6 +12525,14 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== +oidc-client-ts@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/oidc-client-ts/-/oidc-client-ts-2.2.4.tgz#7d86b5efe2248f3637a6f3a0ee1af86764aea125" + integrity sha512-nOZwIomju+AmXObl5Oq5PjrES/qTt8bLsENJCIydVgi9TEWk7SCkOU6X3RNkY7yfySRM1OJJvDKdREZdmnDT2g== + dependencies: + crypto-js "^4.1.1" + jwt-decode "^3.1.2" + on-finished@2.4.1, on-finished@^2.3.0: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -13500,14 +13444,6 @@ postcss-modules-extract-imports@^3.0.0: resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== -postcss-modules-local-by-default@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" - integrity sha512-X4cquUPIaAd86raVrBwO8fwRfkIdbwFu7CTfEOjiZQHVQwlHRSkTgH5NLDmMm5+1hQO8u6dZ+TOOJDbay1hYpA== - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - postcss-modules-local-by-default@^3.0.2, postcss-modules-local-by-default@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" @@ -13527,14 +13463,6 @@ postcss-modules-local-by-default@^4.0.0: postcss-selector-parser "^6.0.2" postcss-value-parser "^4.1.0" -postcss-modules-scope@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" - integrity sha512-LTYwnA4C1He1BKZXIx1CYiHixdSe9LWYVKadq9lK5aCCMkoOkFyZ7aigt+srfjlRplJY3gIol6KUNefdMQJdlw== - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - postcss-modules-scope@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" @@ -13550,18 +13478,6 @@ postcss-modules-scope@^3.0.0: dependencies: postcss-selector-parser "^6.0.4" -postcss-modules-sync@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-sync/-/postcss-modules-sync-1.0.0.tgz#619a719cf78dd16a4834135140b324cf77334be1" - integrity sha512-kIDk2NYmxHshqUbjtFf1WdBij08IsvRdgDT0nOGWhvwkr8/z1piLSzxVrPt56J4DU6ON986h2H+5xcBnFhT8UQ== - dependencies: - generic-names "^1.0.2" - icss-replace-symbols "^1.0.2" - postcss "^5.2.5" - postcss-modules-local-by-default "^1.1.1" - postcss-modules-scope "^1.0.2" - string-hash "^1.1.0" - postcss-modules-values@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" @@ -13799,7 +13715,7 @@ postcss-selector-parser@^3.0.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-selector-parser@^5.0.0, postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: version "5.0.0" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== @@ -13872,25 +13788,6 @@ postcss@7.x.x, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, picocolors "^0.2.1" source-map "^0.6.1" -postcss@^5.2.5: - version "5.2.18" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" - integrity sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg== - dependencies: - chalk "^1.1.3" - js-base64 "^2.1.9" - source-map "^0.5.6" - supports-color "^3.2.3" - -postcss@^6.0.1: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - postcss@^8.4.14, postcss@^8.4.19: version "8.4.24" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df" @@ -13915,11 +13812,6 @@ prepend-http@^1.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg== -prettier@1.16.3: - version "1.16.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d" - integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw== - "prettier@^1.18.2 || ^2.0.0": version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" @@ -14481,36 +14373,6 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -require-extension-hooks-babel@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/require-extension-hooks-babel/-/require-extension-hooks-babel-1.0.0.tgz#78755c505ab884077d51fc393bfc3b2884249777" - integrity sha512-n8+KxBVMjUgNz3ipFOrGoflWgiabcoGul8PE+5JZk1oA3/Bb5jtCvne/sRZ4TjkFuqDDOiWxPfAVK/UsL0iMOw== - dependencies: - "@babel/core" "^7.4.4" - "@babel/preset-env" "^7.4.4" - -require-extension-hooks-vue@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/require-extension-hooks-vue/-/require-extension-hooks-vue-3.0.0.tgz#09126a5ef7db5cd25c21346b848ed95e6e5cb615" - integrity sha512-vxjepJ6JOvpplt1wjLZH7hcyW6I7hKGdCI5Btr5kr/7hr/8WP9Qqojy/kgtlIN6KUMkPKpjAmx1VRmcuaH+abQ== - dependencies: - "@vue/component-compiler-utils" "^2.3.1" - consolidate "^0.15.1" - postcss "^7.0.14" - postcss-modules-sync "^1.0.0" - source-map-support "^0.5.10" - -require-extension-hooks@0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/require-extension-hooks/-/require-extension-hooks-0.3.3.tgz#e5a4eb1c821bf70b84a7e8374e3c4166dc42a820" - integrity sha512-UrOSBIFHu2D1pVyeCl3+5/FBE4aTgoxyYu5iDR0BhtwRsdSzNzrKAvQGUlbELj1LgjI0HNWLUaOpns+iZpw3eQ== - dependencies: - convert-source-map "^1.3.0" - merge-source-map "^1.0.3" - minimatch "^3.0.4" - mkdirp "^0.5.1" - source-map "^0.5.6" - require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" @@ -15243,7 +15105,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.10, source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: +source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -15499,11 +15361,6 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== -string-hash@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" - integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A== - string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -15659,14 +15516,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== -supports-color@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - integrity sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A== - dependencies: - has-flag "^1.0.0" - -supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==