sso init
This commit is contained in:
@@ -22,6 +22,8 @@ export function setErrorMessage(data, message) {
|
|||||||
export default function ({ app, router }) {
|
export default function ({ app, router }) {
|
||||||
app.config.globalProperties.$axios = axios;
|
app.config.globalProperties.$axios = axios;
|
||||||
|
|
||||||
|
axios.defaults.withCredentials = true;
|
||||||
|
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
function (config) {
|
function (config) {
|
||||||
const auth = useAuthStore();
|
const auth = useAuthStore();
|
||||||
@@ -60,7 +62,15 @@ export default function ({ app, router }) {
|
|||||||
}
|
}
|
||||||
// unauthorized
|
// unauthorized
|
||||||
else if (error.response.status === 401) {
|
else if (error.response.status === 401) {
|
||||||
router.push({ path: "/expired" });
|
// bypass redirect for auth check endpoint
|
||||||
|
if (
|
||||||
|
error.config.url !== "_allauth/browser/v1/auth/session" ||
|
||||||
|
error.config.url !== "ws/dashinfo" // TODO once auth is working, need to extend it to websockets
|
||||||
|
) {
|
||||||
|
return Promise.reject({ ...error });
|
||||||
|
} else {
|
||||||
|
router.push({ path: "/expired" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// perms
|
// perms
|
||||||
else if (error.response.status === 403) {
|
else if (error.response.status === 403) {
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
<q-tab name="webhooks" label="Web Hooks" />
|
<q-tab name="webhooks" label="Web Hooks" />
|
||||||
<q-tab name="retention" label="Retention" />
|
<q-tab name="retention" label="Retention" />
|
||||||
<q-tab name="apikeys" label="API Keys" />
|
<q-tab name="apikeys" label="API Keys" />
|
||||||
|
<q-tab name="sso" label="SSO Integration" />
|
||||||
<!-- <q-tab name="openai" label="Open AI" /> -->
|
<!-- <q-tab name="openai" label="Open AI" /> -->
|
||||||
</q-tabs>
|
</q-tabs>
|
||||||
</template>
|
</template>
|
||||||
@@ -636,6 +637,11 @@
|
|||||||
<APIKeysTable />
|
<APIKeysTable />
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
|
<!-- sso integration -->
|
||||||
|
<q-tab-panel name="sso">
|
||||||
|
<SSOProvidersTable />
|
||||||
|
</q-tab-panel>
|
||||||
|
|
||||||
<!-- Open AI -->
|
<!-- Open AI -->
|
||||||
<!-- <q-tab-panel name="openai">
|
<!-- <q-tab-panel name="openai">
|
||||||
<div class="text-subtitle2">Open AI</div>
|
<div class="text-subtitle2">Open AI</div>
|
||||||
@@ -722,6 +728,7 @@ import CustomFields from "@/components/modals/coresettings/CustomFields.vue";
|
|||||||
import KeyStoreTable from "@/components/modals/coresettings/KeyStoreTable.vue";
|
import KeyStoreTable from "@/components/modals/coresettings/KeyStoreTable.vue";
|
||||||
import URLActionsTable from "@/components/modals/coresettings/URLActionsTable.vue";
|
import URLActionsTable from "@/components/modals/coresettings/URLActionsTable.vue";
|
||||||
import APIKeysTable from "@/components/core/APIKeysTable.vue";
|
import APIKeysTable from "@/components/core/APIKeysTable.vue";
|
||||||
|
import SSOProvidersTable from "@/ee/sso/components/SSOProvidersTable.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "EditCoreSettings",
|
name: "EditCoreSettings",
|
||||||
@@ -731,6 +738,7 @@ export default {
|
|||||||
KeyStoreTable,
|
KeyStoreTable,
|
||||||
URLActionsTable,
|
URLActionsTable,
|
||||||
APIKeysTable,
|
APIKeysTable,
|
||||||
|
SSOProvidersTable,
|
||||||
// ServerTasksTable,
|
// ServerTasksTable,
|
||||||
},
|
},
|
||||||
mixins: [mixins],
|
mixins: [mixins],
|
||||||
|
97
src/ee/sso/api/sso.ts
Normal file
97
src/ee/sso/api/sso.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { getCookie } from "@/ee/sso/utils/cookies";
|
||||||
|
import { getBaseUrl } from "@/boot/axios";
|
||||||
|
|
||||||
|
import type { SSOProvider } from "@/ee/sso/types/sso";
|
||||||
|
|
||||||
|
const baseUrl = "accounts";
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
provider: string;
|
||||||
|
process: string;
|
||||||
|
callback_url: string;
|
||||||
|
csrfmiddlewaretoken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCSRFToken() {
|
||||||
|
return getCookie("csrftoken");
|
||||||
|
}
|
||||||
|
|
||||||
|
// needed for sso provider redirect
|
||||||
|
function postForm(url: string, data: FormData) {
|
||||||
|
const f = document.createElement("form");
|
||||||
|
f.method = "POST";
|
||||||
|
f.action = url;
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
const d = document.createElement("input");
|
||||||
|
d.type = "hidden";
|
||||||
|
d.name = key;
|
||||||
|
d.value = data[key];
|
||||||
|
f.appendChild(d);
|
||||||
|
}
|
||||||
|
document.body.appendChild(f);
|
||||||
|
f.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// sso providers
|
||||||
|
export interface AllAuthResponse<T> {
|
||||||
|
data: T;
|
||||||
|
status: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchSSOProviders(): Promise<SSOProvider> {
|
||||||
|
const { data } = await axios.get(`${baseUrl}/ssoproviders/`);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addSSOProvider(payload: SSOProvider) {
|
||||||
|
const { data } = await axios.post(`${baseUrl}/ssoproviders/`, payload);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editSSOProvider(id: number, payload: SSOProvider) {
|
||||||
|
const { data } = await axios.put(`${baseUrl}/ssoproviders/${id}/`, payload);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removeSSOProvider(id: number) {
|
||||||
|
const { data } = await axios.delete(`${baseUrl}/ssoproviders/${id}/`);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCurrentSession() {
|
||||||
|
const { data } = await axios.get("_allauth/browser/v1/auth/session");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SSOProviderConfig {
|
||||||
|
client_id: string;
|
||||||
|
flows: string[];
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SSOConfigResponseProviders {
|
||||||
|
providers: SSOProviderConfig[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SSOConfigResponse {
|
||||||
|
socialaccount: SSOConfigResponseProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSSOConfig(): Promise<
|
||||||
|
AllAuthResponse<SSOConfigResponse>
|
||||||
|
> {
|
||||||
|
const { data } = await axios.get("_allauth/browser/v1/config");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function openSSOProviderRedirect(id: string) {
|
||||||
|
postForm(`${getBaseUrl()}/_allauth/browser/v1/auth/provider/redirect`, {
|
||||||
|
provider: id,
|
||||||
|
process: "login",
|
||||||
|
callback_url: `${location.origin}/account/provider/callback`,
|
||||||
|
csrfmiddlewaretoken: getCSRFToken() || "",
|
||||||
|
});
|
||||||
|
}
|
112
src/ee/sso/components/SSOProvidersForm.vue
Normal file
112
src/ee/sso/components/SSOProvidersForm.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<q-dialog ref="dialogRef" @hide="onDialogHide">
|
||||||
|
<q-card class="q-dialog-plugin" style="width: 50">
|
||||||
|
<q-bar>
|
||||||
|
{{ props.provider ? "Edit SSO Provider" : "Add SSO Provider" }}
|
||||||
|
<q-space />
|
||||||
|
<q-btn dense flat icon="close" v-close-popup>
|
||||||
|
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</q-bar>
|
||||||
|
|
||||||
|
<!-- name -->
|
||||||
|
<q-card-section>
|
||||||
|
<q-input
|
||||||
|
:readonly="!!props.provider"
|
||||||
|
label="Name"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
v-model="localProvider.name"
|
||||||
|
:rules="[(val) => !!val || '*Required']"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- url -->
|
||||||
|
<q-card-section>
|
||||||
|
<q-input
|
||||||
|
label="Server URL"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
v-model="localProvider.server_url"
|
||||||
|
:rules="[(val) => !!val || '*Required']"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- client id -->
|
||||||
|
<q-card-section>
|
||||||
|
<q-input
|
||||||
|
label="Client ID"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
v-model="localProvider.client_id"
|
||||||
|
:rules="[(val) => !!val || '*Required']"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- secret -->
|
||||||
|
<q-card-section>
|
||||||
|
<q-input
|
||||||
|
label="Secret"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
v-model="localProvider.secret"
|
||||||
|
:rules="[(val) => !!val || '*Required']"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat label="Cancel" v-close-popup />
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
label="Submit"
|
||||||
|
color="primary"
|
||||||
|
:loading="loading"
|
||||||
|
@click="submit"
|
||||||
|
/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// composition imports
|
||||||
|
import { ref, reactive } from "vue";
|
||||||
|
import { useDialogPluginComponent, extend } from "quasar";
|
||||||
|
import { editSSOProvider, addSSOProvider } from "@/ee/sso/api/sso";
|
||||||
|
import { notifySuccess } from "@/utils/notify";
|
||||||
|
import { SSOProvider } from "@/types/accounts";
|
||||||
|
|
||||||
|
// define emits
|
||||||
|
defineEmits([...useDialogPluginComponent.emits]);
|
||||||
|
|
||||||
|
// define props
|
||||||
|
const props = defineProps<{ provider?: SSOProvider }>();
|
||||||
|
|
||||||
|
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const localProvider: SSOProvider = props.provider
|
||||||
|
? reactive(extend({}, props.provider))
|
||||||
|
: reactive({
|
||||||
|
id: 0,
|
||||||
|
name: "",
|
||||||
|
client_id: "",
|
||||||
|
secret: "",
|
||||||
|
server_url: "",
|
||||||
|
} as SSOProvider);
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
props.provider
|
||||||
|
? await editSSOProvider(localProvider.id, localProvider)
|
||||||
|
: await addSSOProvider(localProvider);
|
||||||
|
onDialogOK();
|
||||||
|
notifySuccess("SSO Provider was edited!");
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
172
src/ee/sso/components/SSOProvidersTable.vue
Normal file
172
src/ee/sso/components/SSOProvidersTable.vue
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="text-subtitle2">SSO Providers</div>
|
||||||
|
<q-space />
|
||||||
|
<q-btn
|
||||||
|
size="sm"
|
||||||
|
color="grey-5"
|
||||||
|
icon="fas fa-plus"
|
||||||
|
text-color="black"
|
||||||
|
label="Add SSO Provider"
|
||||||
|
@click="addSSOProvider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<q-separator />
|
||||||
|
<q-table
|
||||||
|
dense
|
||||||
|
:rows="providers"
|
||||||
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 0, sortBy: 'name', descending: true }"
|
||||||
|
row-key="id"
|
||||||
|
binary-state-sort
|
||||||
|
hide-pagination
|
||||||
|
virtual-scroll
|
||||||
|
:rows-per-page-options="[0]"
|
||||||
|
no-data-label="No SSO Providers added yet"
|
||||||
|
:loading="loading"
|
||||||
|
>
|
||||||
|
<!-- body slots -->
|
||||||
|
<template v-slot:body="props">
|
||||||
|
<q-tr
|
||||||
|
:props="props"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@dblclick="editSSOProvider(props.row)"
|
||||||
|
>
|
||||||
|
<!-- context menu -->
|
||||||
|
<q-menu context-menu>
|
||||||
|
<q-list dense style="min-width: 200px">
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="editSSOProvider(props.row)"
|
||||||
|
>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="edit" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>Edit</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-close-popup
|
||||||
|
@click="deleteSSOProvider(props.row)"
|
||||||
|
>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon name="delete" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>Delete</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-separator></q-separator>
|
||||||
|
|
||||||
|
<q-item clickable v-close-popup>
|
||||||
|
<q-item-section>Close</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
<!-- name -->
|
||||||
|
<q-td>
|
||||||
|
{{ props.row.name }}
|
||||||
|
</q-td>
|
||||||
|
<!-- server_url -->
|
||||||
|
<q-td>
|
||||||
|
{{ props.row.server_url }}
|
||||||
|
</q-td>
|
||||||
|
<!-- pattern -->
|
||||||
|
<q-td>
|
||||||
|
{{ props.row.client_id }}
|
||||||
|
</q-td>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// composition imports
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { QTableColumn, useQuasar } from "quasar";
|
||||||
|
import { fetchSSOProviders, removeSSOProvider } from "@/ee/sso/api/sso";
|
||||||
|
import { notifySuccess } from "@/utils/notify";
|
||||||
|
|
||||||
|
// ui imports
|
||||||
|
import SSOProvidersForm from "@/components/modals/coresettings/SSOProvidersForm.vue";
|
||||||
|
|
||||||
|
// types
|
||||||
|
import { type SSOProvider } from "@/types/accounts";
|
||||||
|
|
||||||
|
// setup quasar
|
||||||
|
const $q = useQuasar();
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
const providers = ref([] as SSOProvider[]);
|
||||||
|
|
||||||
|
const columns: QTableColumn[] = [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
label: "Name",
|
||||||
|
field: "name",
|
||||||
|
align: "left",
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "server_url",
|
||||||
|
label: "Server Url",
|
||||||
|
field: "server_url",
|
||||||
|
align: "left",
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "client_id",
|
||||||
|
label: "Client ID",
|
||||||
|
field: "client_id",
|
||||||
|
align: "left",
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function getSSOProviders() {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
providers.value = await fetchSSOProviders();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSSOProvider() {
|
||||||
|
$q.dialog({
|
||||||
|
component: SSOProvidersForm,
|
||||||
|
}).onOk(getSSOProviders);
|
||||||
|
}
|
||||||
|
|
||||||
|
function editSSOProvider(provider: SSOProvider) {
|
||||||
|
$q.dialog({
|
||||||
|
component: SSOProvidersForm,
|
||||||
|
componentProps: {
|
||||||
|
provider: provider,
|
||||||
|
},
|
||||||
|
}).onOk(getSSOProviders);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteSSOProvider(provider: SSOProvider) {
|
||||||
|
$q.dialog({
|
||||||
|
title: `Delete SSO Provider: ${provider.name}?`,
|
||||||
|
cancel: true,
|
||||||
|
ok: { label: "Delete", color: "negative" },
|
||||||
|
}).onOk(async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
await removeSSOProvider(provider.id);
|
||||||
|
await getSSOProviders();
|
||||||
|
notifySuccess(`SSO Provider: ${provider.name} was deleted!`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onMounted(getSSOProviders);
|
||||||
|
</script>
|
8
src/ee/sso/types/sso.ts
Normal file
8
src/ee/sso/types/sso.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export interface SSOProvider {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
provider_id: string;
|
||||||
|
client_id: string;
|
||||||
|
secret: string;
|
||||||
|
server_url: string;
|
||||||
|
}
|
15
src/ee/sso/utils/cookies.ts
Normal file
15
src/ee/sso/utils/cookies.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export function getCookie(name: string) {
|
||||||
|
let cookieValue = null;
|
||||||
|
if (document.cookie && document.cookie !== "") {
|
||||||
|
const cookies = document.cookie.split(";");
|
||||||
|
for (let i = 0; i < cookies.length; i++) {
|
||||||
|
const cookie = cookies[i].trim();
|
||||||
|
// Does this cookie string begin with the name we want?
|
||||||
|
if (cookie.substring(0, name.length + 1) === name + "=") {
|
||||||
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
}
|
28
src/ee/sso/views/ProviderCallback.vue
Normal file
28
src/ee/sso/views/ProviderCallback.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div class="fixed-center text-center" v-if="error">
|
||||||
|
<p class="text-faded">There was an error logging into your provider.</p>
|
||||||
|
<q-btn color="secondary" style="width: 200px" to="/login"
|
||||||
|
>Go back to Login</q-btn
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import { useAuthStore } from "@/stores/auth";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const error = route.params.error;
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const auth = useAuthStore();
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
if (auth.loggedIn) {
|
||||||
|
router.push({ name: "Dashboard" });
|
||||||
|
} else {
|
||||||
|
router.push({ name: "Login" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@@ -75,6 +75,11 @@ const routes = [
|
|||||||
name: "SessionExpired",
|
name: "SessionExpired",
|
||||||
component: () => import("@/views/SessionExpired.vue"),
|
component: () => import("@/views/SessionExpired.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/account/provider/callback",
|
||||||
|
name: "ProviderCallback",
|
||||||
|
component: () => import("@/ee/sso/views/ProviderCallback.vue"),
|
||||||
|
},
|
||||||
{ path: "/:catchAll(.*)", component: () => import("@/views/NotFound.vue") },
|
{ path: "/:catchAll(.*)", component: () => import("@/views/NotFound.vue") },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -49,7 +49,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</q-form>
|
</q-form>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section v-if="ssoProviders.length > 0">
|
||||||
|
<q-list dense v-for="provider in ssoProviders" :key="provider.id">
|
||||||
|
<q-item @click="openSSOProviderRedirect(provider.id)" clickable>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{ provider.name }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
<!-- 2 factor modal -->
|
<!-- 2 factor modal -->
|
||||||
<q-dialog persistent v-model="prompt">
|
<q-dialog persistent v-model="prompt">
|
||||||
<q-card style="min-width: 400px">
|
<q-card style="min-width: 400px">
|
||||||
@@ -84,10 +95,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from "vue";
|
import { ref, reactive, onMounted } from "vue";
|
||||||
import { type QForm, useQuasar } from "quasar";
|
import { type QForm, useQuasar } from "quasar";
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
import {
|
||||||
|
openSSOProviderRedirect,
|
||||||
|
getSSOConfig,
|
||||||
|
getCurrentSession,
|
||||||
|
type SSOProviderConfig,
|
||||||
|
} from "@/ee/sso/api/sso";
|
||||||
|
|
||||||
// setup quasar
|
// setup quasar
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
@@ -107,6 +124,7 @@ const credentials = reactive({ username: "", password: "" });
|
|||||||
const twofactor = ref("");
|
const twofactor = ref("");
|
||||||
const prompt = ref(false);
|
const prompt = ref(false);
|
||||||
const showPassword = ref(true);
|
const showPassword = ref(true);
|
||||||
|
const ssoProviders = ref([] as SSOProviderConfig[]);
|
||||||
|
|
||||||
async function checkCreds() {
|
async function checkCreds() {
|
||||||
try {
|
try {
|
||||||
@@ -135,6 +153,13 @@ async function onSubmit() {
|
|||||||
prompt.value = false;
|
prompt.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const result = await getSSOConfig();
|
||||||
|
ssoProviders.value = result.data.socialaccount.providers;
|
||||||
|
|
||||||
|
await getCurrentSession();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
Reference in New Issue
Block a user