From 1cdea382d64bfa339807d0771870577b038f336d Mon Sep 17 00:00:00 2001 From: sd109 Date: Tue, 13 Aug 2024 13:28:43 +0100 Subject: [PATCH 1/6] Add x-remote header auth support --- backend/danswer/auth/users.py | 12 ++--- backend/danswer/db/auth.py | 10 ++-- web/src/app/auth/login/HeaderLogin.tsx | 69 ++++++++++++++++++++++++++ web/src/app/auth/login/page.tsx | 41 ++++++++------- web/src/lib/user.ts | 3 +- 5 files changed, 106 insertions(+), 29 deletions(-) create mode 100644 web/src/app/auth/login/HeaderLogin.tsx diff --git a/backend/danswer/auth/users.py b/backend/danswer/auth/users.py index dff6a60363c..eec1db412e0 100644 --- a/backend/danswer/auth/users.py +++ b/backend/danswer/auth/users.py @@ -204,12 +204,12 @@ async def create( ) -> models.UP: verify_email_is_invited(user_create.email) verify_email_domain(user_create.email) - if hasattr(user_create, "role"): - user_count = await get_user_count() - if user_count == 0 or user_create.email in get_default_admin_user_emails(): - user_create.role = UserRole.ADMIN - else: - user_create.role = UserRole.BASIC + # if hasattr(user_create, "role"): + # user_count = await get_user_count() + # if user_count == 0 or user_create.email in get_default_admin_user_emails(): + # user_create.role = UserRole.ADMIN + # else: + # user_create.role = UserRole.BASIC return await super().create(user_create, safe=safe, request=request) # type: ignore async def oauth_callback( diff --git a/backend/danswer/db/auth.py b/backend/danswer/db/auth.py index 161fdc8f10b..7710232d01f 100644 --- a/backend/danswer/db/auth.py +++ b/backend/danswer/db/auth.py @@ -46,11 +46,11 @@ async def get_user_count() -> int: # Need to override this because FastAPI Users doesn't give flexibility for backend field creation logic in OAuth flow class SQLAlchemyUserAdminDB(SQLAlchemyUserDatabase): async def create(self, create_dict: Dict[str, Any]) -> UP: - user_count = await get_user_count() - if user_count == 0 or create_dict["email"] in get_default_admin_user_emails(): - create_dict["role"] = UserRole.ADMIN - else: - create_dict["role"] = UserRole.BASIC + # user_count = await get_user_count() + # if user_count == 0 or create_dict["email"] in get_default_admin_user_emails(): + # create_dict["role"] = UserRole.ADMIN + # else: + # create_dict["role"] = UserRole.BASIC return await super().create(create_dict) diff --git a/web/src/app/auth/login/HeaderLogin.tsx b/web/src/app/auth/login/HeaderLogin.tsx new file mode 100644 index 00000000000..eb2d6b5c570 --- /dev/null +++ b/web/src/app/auth/login/HeaderLogin.tsx @@ -0,0 +1,69 @@ +"use client"; + +import { usePopup } from "@/components/admin/connectors/Popup"; +import { basicLogin, basicSignup } from "@/lib/user"; +import { useRouter } from "next/navigation"; +import { useEffect } from "react"; +import { Spinner } from "@/components/Spinner"; + +export function HeaderLoginLoading({ + user, groups +}: { + user: string; + groups: string[]; +}) { + console.log(user, groups); + + const router = useRouter(); + const { popup, setPopup } = usePopup(); + const email = `${user}@default.com`; + const password = `not-used-${window.crypto.randomUUID()}` + const role = groups.includes("/admins") ? "admin" : "basic" + + async function tryLogin() { + // TODO: Update user role here if groups have changed? + + // TODO: Use other API endpoints here to update user roles + // and check for existence instead of attempting sign up + // Endpoints: + // - /api/manage/users + // - /api/manage/promote-user-to-admin (auth required) + // - /api/manage/demote-admin-to-user (auth required) + + // signup every time. + // Ensure user exists + const response = await basicSignup(email, password, role); + if (!response.ok) { + const errorDetail = (await response.json()).detail; + + if (errorDetail !== "REGISTER_USER_ALREADY_EXISTS") { + setPopup({ + type: "error", + message: `Failed to sign up - ${errorDetail}`, + }); + } + } + // Login as user + const loginResponse = await basicLogin(email, password); + if (loginResponse.ok) { + router.push("/"); + } else { + const errorDetail = (await loginResponse.json()).detail; + setPopup({ + type: "error", + message: `Failed to login - ${errorDetail}`, + }); + } + } + + useEffect(() => { + tryLogin() + }, []); + + return ( + <> + {popup} + + + ); +} diff --git a/web/src/app/auth/login/page.tsx b/web/src/app/auth/login/page.tsx index 50f1d42d9b4..9b12b53bff0 100644 --- a/web/src/app/auth/login/page.tsx +++ b/web/src/app/auth/login/page.tsx @@ -14,6 +14,8 @@ import Link from "next/link"; import { Logo } from "@/components/Logo"; import { LoginText } from "./LoginText"; import { getSecondsUntilExpiration } from "@/lib/time"; +import { headers } from 'next/headers'; +import { HeaderLoginLoading } from "./HeaderLogin"; const Page = async ({ searchParams, @@ -69,6 +71,9 @@ const Page = async ({ return redirect(authUrl); } + const userHeader = headers().get('x-remote-user'); + const groupsHeader = headers().get('x-remote-group'); + return (
@@ -90,23 +95,25 @@ const Page = async ({ )} {authTypeMetadata?.authType === "basic" && ( - -
- - <LoginText /> - -
- -
- - Don't have an account?{" "} - - Create an account - - -
-
- )} + (userHeader && groupsHeader) ? + : ( + +
+ + <LoginText /> + +
+ +
+ + Don't have an account?{" "} + + Create an account + + +
+
+ ))}
diff --git a/web/src/lib/user.ts b/web/src/lib/user.ts index eb416c3c442..221cf3056c4 100644 --- a/web/src/lib/user.ts +++ b/web/src/lib/user.ts @@ -42,7 +42,7 @@ export const basicLogin = async ( return response; }; -export const basicSignup = async (email: string, password: string) => { +export const basicSignup = async (email: string, password: string, role = "basic") => { const response = await fetch("/api/auth/register", { method: "POST", credentials: "include", @@ -53,6 +53,7 @@ export const basicSignup = async (email: string, password: string) => { email, username: email, password, + role, }), }); return response; From 659bc4a167f382a503e560a857c16f6b3dca4b35 Mon Sep 17 00:00:00 2001 From: sd109 Date: Mon, 2 Sep 2024 20:04:14 +0100 Subject: [PATCH 2/6] Bump helm chart version --- deployment/helm/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/helm/Chart.yaml b/deployment/helm/Chart.yaml index 1212e84b2a2..d78e280eb6d 100644 --- a/deployment/helm/Chart.yaml +++ b/deployment/helm/Chart.yaml @@ -5,7 +5,7 @@ home: https://www.danswer.ai/ sources: - "https://github.com/danswer-ai/danswer" type: application -version: 0.1.0-azimuth.1 +version: 0.2.0 appVersion: v0.5.10 dependencies: - name: postgresql From 12d00bbbe9985579cd39416ba2388f791d4daa78 Mon Sep 17 00:00:00 2001 From: sd109 Date: Mon, 2 Sep 2024 20:15:03 +0100 Subject: [PATCH 3/6] Use pre-release chart and app versions for testing --- deployment/helm/Chart.yaml | 2 +- deployment/helm/values.yaml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deployment/helm/Chart.yaml b/deployment/helm/Chart.yaml index d78e280eb6d..81543649ea7 100644 --- a/deployment/helm/Chart.yaml +++ b/deployment/helm/Chart.yaml @@ -5,7 +5,7 @@ home: https://www.danswer.ai/ sources: - "https://github.com/danswer-ai/danswer" type: application -version: 0.2.0 +version: 0.1.0-remote-user-header appVersion: v0.5.10 dependencies: - name: postgresql diff --git a/deployment/helm/values.yaml b/deployment/helm/values.yaml index 97eb1d1fe9e..0d12c8bd2e4 100644 --- a/deployment/helm/values.yaml +++ b/deployment/helm/values.yaml @@ -11,7 +11,8 @@ appVersionOverride: # e.g "v0.3.93" # tags to refer to downstream StackHPC-modified images. # The full image ref will be: # {{ image-name }}:{{ image-tag or appVersion }}-{{ tagSuffix }} -tagSuffix: stackhpc.1 +# tagSuffix: stackhpc.1 +tagSuffix: stackhpc-remote-user-header.1 zenithClient: iconUrl: https://raw.githubusercontent.com/danswer-ai/danswer/1fabd9372d66cd54238847197c33f091a724803b/Danswer.png From af2bc2b2959bfec595b92b670ab76411c44035e2 Mon Sep 17 00:00:00 2001 From: sd109 Date: Mon, 2 Sep 2024 20:38:06 +0100 Subject: [PATCH 4/6] Use client-side-compatible uuid generator --- web/src/app/auth/login/HeaderLogin.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/app/auth/login/HeaderLogin.tsx b/web/src/app/auth/login/HeaderLogin.tsx index eb2d6b5c570..6b8f9d7fcf4 100644 --- a/web/src/app/auth/login/HeaderLogin.tsx +++ b/web/src/app/auth/login/HeaderLogin.tsx @@ -5,6 +5,7 @@ import { basicLogin, basicSignup } from "@/lib/user"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; import { Spinner } from "@/components/Spinner"; +import { v4 as uuidv4 } from 'uuid'; export function HeaderLoginLoading({ user, groups @@ -17,7 +18,7 @@ export function HeaderLoginLoading({ const router = useRouter(); const { popup, setPopup } = usePopup(); const email = `${user}@default.com`; - const password = `not-used-${window.crypto.randomUUID()}` + const password = `not-used-${uuidv4()}` const role = groups.includes("/admins") ? "admin" : "basic" async function tryLogin() { From 371994a044c8a4e1396bd305a2da456bb69f1bca Mon Sep 17 00:00:00 2001 From: sd109 Date: Mon, 2 Sep 2024 21:04:34 +0100 Subject: [PATCH 5/6] Bump version tags for testing --- deployment/helm/Chart.yaml | 2 +- deployment/helm/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/helm/Chart.yaml b/deployment/helm/Chart.yaml index 81543649ea7..cc268cfebc1 100644 --- a/deployment/helm/Chart.yaml +++ b/deployment/helm/Chart.yaml @@ -5,7 +5,7 @@ home: https://www.danswer.ai/ sources: - "https://github.com/danswer-ai/danswer" type: application -version: 0.1.0-remote-user-header +version: 0.1.0-remote-user-header.2 appVersion: v0.5.10 dependencies: - name: postgresql diff --git a/deployment/helm/values.yaml b/deployment/helm/values.yaml index 0d12c8bd2e4..ead5f79ba14 100644 --- a/deployment/helm/values.yaml +++ b/deployment/helm/values.yaml @@ -12,7 +12,7 @@ appVersionOverride: # e.g "v0.3.93" # The full image ref will be: # {{ image-name }}:{{ image-tag or appVersion }}-{{ tagSuffix }} # tagSuffix: stackhpc.1 -tagSuffix: stackhpc-remote-user-header.1 +tagSuffix: stackhpc-remote-user-header.2 zenithClient: iconUrl: https://raw.githubusercontent.com/danswer-ai/danswer/1fabd9372d66cd54238847197c33f091a724803b/Danswer.png From 07f60cc8603e4603a6a9f0fdf1121d46c71ce46d Mon Sep 17 00:00:00 2001 From: sd109 Date: Wed, 4 Sep 2024 12:15:20 +0100 Subject: [PATCH 6/6] Bump chart and image tags --- deployment/helm/Chart.yaml | 2 +- deployment/helm/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/helm/Chart.yaml b/deployment/helm/Chart.yaml index cc268cfebc1..d78e280eb6d 100644 --- a/deployment/helm/Chart.yaml +++ b/deployment/helm/Chart.yaml @@ -5,7 +5,7 @@ home: https://www.danswer.ai/ sources: - "https://github.com/danswer-ai/danswer" type: application -version: 0.1.0-remote-user-header.2 +version: 0.2.0 appVersion: v0.5.10 dependencies: - name: postgresql diff --git a/deployment/helm/values.yaml b/deployment/helm/values.yaml index ead5f79ba14..56588150074 100644 --- a/deployment/helm/values.yaml +++ b/deployment/helm/values.yaml @@ -12,7 +12,7 @@ appVersionOverride: # e.g "v0.3.93" # The full image ref will be: # {{ image-name }}:{{ image-tag or appVersion }}-{{ tagSuffix }} # tagSuffix: stackhpc.1 -tagSuffix: stackhpc-remote-user-header.2 +tagSuffix: stackhpc.2 zenithClient: iconUrl: https://raw.githubusercontent.com/danswer-ai/danswer/1fabd9372d66cd54238847197c33f091a724803b/Danswer.png