Skip to content

Commit

Permalink
sso init
Browse files Browse the repository at this point in the history
  • Loading branch information
sadnub committed Sep 16, 2024
1 parent 4186b1c commit 263e891
Show file tree
Hide file tree
Showing 10 changed files with 482 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/boot/axios.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export function setErrorMessage(data, message) {
export default function ({ app, router }) {
app.config.globalProperties.$axios = axios;

axios.defaults.withCredentials = true;

axios.interceptors.request.use(
function (config) {
const auth = useAuthStore();
Expand Down Expand Up @@ -60,7 +62,15 @@ export default function ({ app, router }) {
}
// unauthorized
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
else if (error.response.status === 403) {
Expand Down
8 changes: 8 additions & 0 deletions src/components/modals/coresettings/EditCoreSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<q-tab name="webhooks" label="Web Hooks" />
<q-tab name="retention" label="Retention" />
<q-tab name="apikeys" label="API Keys" />
<q-tab name="sso" label="SSO Integration" />
<!-- <q-tab name="openai" label="Open AI" /> -->
</q-tabs>
</template>
Expand Down Expand Up @@ -636,6 +637,11 @@
<APIKeysTable />
</q-tab-panel>

<!-- sso integration -->
<q-tab-panel name="sso">
<SSOProvidersTable />
</q-tab-panel>

<!-- Open AI -->
<!-- <q-tab-panel name="openai">
<div class="text-subtitle2">Open AI</div>
Expand Down Expand Up @@ -722,6 +728,7 @@ import CustomFields from "@/components/modals/coresettings/CustomFields.vue";
import KeyStoreTable from "@/components/modals/coresettings/KeyStoreTable.vue";
import URLActionsTable from "@/components/modals/coresettings/URLActionsTable.vue";
import APIKeysTable from "@/components/core/APIKeysTable.vue";
import SSOProvidersTable from "@/ee/sso/components/SSOProvidersTable.vue";
export default {
name: "EditCoreSettings",
Expand All @@ -731,6 +738,7 @@ export default {
KeyStoreTable,
URLActionsTable,
APIKeysTable,
SSOProvidersTable,
// ServerTasksTable,
},
mixins: [mixins],
Expand Down
97 changes: 97 additions & 0 deletions src/ee/sso/api/sso.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 112 additions & 0 deletions src/ee/sso/components/SSOProvidersForm.vue
Original file line number Diff line number Diff line change
@@ -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>
Loading

0 comments on commit 263e891

Please sign in to comment.