Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intergrate Authorisation into embedded ui #311

Merged
merged 16 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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"
}
}
12 changes: 6 additions & 6 deletions dashboard/pkg/epinio/config/epinio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,27 +53,27 @@ 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,
showState: false,
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, {
Expand Down Expand Up @@ -266,7 +266,7 @@ export function init($plugin: any, store: any) {
AGE
]);

headers(EPINIO_TYPES.INSTANCE, [
headers(EPINIO_TYPES.CLUSTER, [
STATE,
{
name: 'name',
Expand Down
199 changes: 199 additions & 0 deletions dashboard/pkg/epinio/dialog/LoginDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<script>
import GenericPrompt from '@shell/dialog/GenericPrompt';
import Tabbed from '@shell/components/Tabbed/index.vue';
import Tab from '@shell/components/Tabbed/Tab.vue';
import epinioAuth, { EpinioAuthTypes } from '../utils/auth';
import Password from '@shell/components/form/Password';
import { LabeledInput } from '@components/Form/LabeledInput';

export default {
name: 'LoginDialog',

components: {
GenericPrompt, Tabbed, Tab, LabeledInput, Password
},

props: {
resources: {
type: Array,
required: true
}
},

data() {
return {
selectedTab: '',
username: '',
password: '',
config: {
applyMode: 'login',
applyAction: this.login,
},
tab: {
local: 'local',
dex: 'dex'
}
};
},

computed: {
cluster() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason to define cluster as computed value ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for readability. This makes it clearer that it's a cluster, instead of an odd first entry in an array

return this.resources[0];
}
},

mounted() {
if (!this.cluster.oidcEnabled) {
this.selectedTab = this.tab.local;
}
},

methods: {
async login() {
const errors = [];

switch (this.selectedTab) {
case this.tab.local:
if (!this.username) {
errors.push('Username');
}
if (!this.password) {
errors.push('Password');
}
if (errors.length) {
return Promise.reject(new Error(`${ errors.join('/') } Required`));
}

await epinioAuth.login(this.cluster.createAuthConfig(EpinioAuthTypes.LOCAL, {
username: this.username,
password: this.password,
$axios: this.$axios,
}));
break;
case this.tab.dex:
await epinioAuth.login(this.cluster.createAuthConfig(EpinioAuthTypes.DEX));

break;
default:
throw new Error(`Unknown log in type: ${ this.selectedTab }`);
}

this.cluster.loggedIn = true;

this.$router.push({
name: 'epinio-c-cluster-dashboard',
params: { cluster: this.cluster.id }
});
},

tabChanged({ selectedName }) {
this.selectedTab = selectedName;
},

close() {
this.$emit('close', false);
}
}
};
</script>

<template>
<GenericPrompt
v-bind="config"
@close="close"
>
<h4
slot="title"
class="text-default-text login-dialog__title"
>
{{ t('epinio.login.modal.title') }}
</h4>

<template slot="body">
<Tabbed
v-if="cluster.oidcEnabled"
@changed="tabChanged"
>
<Tab
label-key="epinio.login.modal.local.tabLabel"
:name="tab.local"
:weight="3"
class="login-dialog__tab"
>
<form>
<div class="span-10 offset-1">
<div class="mb-20">
<LabeledInput
id="username"
ref="username"
v-model.trim="username"
data-testid="local-login-username"
:label="t('login.username')"
autocomplete="epinio-username"
:required="true"
/>
</div>
<div class="">
<Password
id="password"
ref="password"
v-model="password"
data-testid="local-login-password"
:label="t('login.password')"
autocomplete="epinio-password"
:required="true"
/>
</div>
</div>
</form>
</Tab>
<Tab
label-key="epinio.login.modal.dex.tabLabel"
:name="tab.dex"
:weight="2"
class="login-dialog__tab"
>
<p>
{{ t('epinio.login.modal.dex.prompt') }}
</p>
</Tab>
</Tabbed>
<form v-else>
<div class="span-10 offset-1 mt-15">
<div class="mb-20">
<LabeledInput
id="username"
ref="username"
v-model.trim="username"
data-testid="local-login-username"
:label="t('login.username')"
autocomplete="epinio-username"
:required="true"
/>
</div>
<div class="">
<Password
id="password"
ref="password"
v-model="password"
data-testid="local-login-password"
:label="t('login.password')"
autocomplete="epinio-password"
:required="true"
/>
</div>
</div>
</form>
</template>
</GenericPrompt>
</template>
<style lang='scss' scoped>
.login-dialog {
&__title {
margin-bottom: 0;
}
&__tab {
min-height: 145px;
}
}
</style>
12 changes: 12 additions & 0 deletions dashboard/pkg/epinio/l10n/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ asyncButton:
action: Export
success: Exported
waiting: Exporting&hellip;
login:
action: Log In
success: Log In
waiting: Log In
epinio:
label: Epinio
about:
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion dashboard/pkg/epinio/list/namespaces.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import ResourceTable from '@shell/components/ResourceTable';
import Masthead from '@shell/components/ResourceList/Masthead';
import { Banner } from '@components/Banner';
import Banner from '@components/Banner/Banner.vue';
import { Card } from '@components/Card';
import { mapGetters, mapState } from 'vuex';
import LabeledInput from '@components/Form/LabeledInput/LabeledInput.vue';
Expand Down
81 changes: 81 additions & 0 deletions dashboard/pkg/epinio/models/cluster.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import Resource from '@shell/plugins/dashboard-store/resource-class';
import { EPINIO_TYPES } from '../types';
import epinioAuth, { EpinioAuthConfig, EpinioAuthLocalConfig, EpinioAuthTypes } from '../utils/auth';

export const EpinioInfoPath = `/api/v1/info`;

export default class EpinioCluster extends Resource {
type = EPINIO_TYPES.CLUSTER;

id: string;
name: string;
state?: string;
metadata?: { state: { transitioning: boolean, error: boolean, message: string }};
loggedIn: boolean;
api: string;
mgmtCluster: any;
oidcEnabled: boolean = false;

constructor(data: {
id: string,
name: string,
loggedIn: boolean,
api: string,
mgmtCluster: any,
}, ctx: any) {
super(data, ctx);
this.id = data.id;
this.name = data.name;
this.api = data.api;
this.loggedIn = data.loggedIn;
this.mgmtCluster = data.mgmtCluster;
}

get availableActions() {
return [
{
action: 'logOut',
enabled: this.loggedIn,
icon: 'icon icon-fw icon-chevron-right',
label: this.t('nav.userMenu.logOut'),
disabled: false,
},
];
}

get infoUrl() {
return this.api + EpinioInfoPath;
}

async logOut() {
try {
await epinioAuth.logout(this.createAuthConfig(EpinioAuthTypes.AGNOSTIC));

this.loggedIn = false;
} catch (err) {
console.error(`Failed to log out: ${ err }`);// eslint-disable-line no-console

this.metadata = {
state: {
transitioning: false,
error: true,
message: 'Failed to log out'
}
};
}
}

createAuthConfig(type: EpinioAuthTypes, localConfig?: EpinioAuthLocalConfig): EpinioAuthConfig {
const config: EpinioAuthConfig = {
type,
epinioUrl: this.api,
dexConfig: {
dashboardUrl: window.origin,
dexUrl: this.api.replace('epinio', 'auth')
},
localConfig
};

return config;
}
}
2 changes: 1 addition & 1 deletion dashboard/pkg/epinio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "epinio",
"description": "Application Development Engine for Kubernetes",
"icon": "https://raw.githubusercontent.com/rancher/dashboard/0b6cbe93e9ed3292294da178f119a500cc494db9/pkg/epinio/assets/logo-epinio.svg",
"version": "1.9.0-0",
"version": "1.11.0-0",
"private": false,
"rancher": true,
"license": "Apache-2.0",
Expand Down
Loading
Loading