From 86821e2eb365c2f5abcff6331659b1915e5ebbe6 Mon Sep 17 00:00:00 2001 From: Mawoka Date: Thu, 16 Feb 2023 20:11:57 +0100 Subject: [PATCH] :wip: Some changes in custom-oauth --- classquiz/config.py | 1 + classquiz/oauth/__init__.py | 3 +- classquiz/oauth/custom.py | 95 +++++++++++++++++++++++++++++++++++ classquiz/oauth/init_oauth.py | 2 +- 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 classquiz/oauth/custom.py diff --git a/classquiz/config.py b/classquiz/config.py index d3e4eb7..760979a 100644 --- a/classquiz/config.py +++ b/classquiz/config.py @@ -61,6 +61,7 @@ class Settings(BaseSettings): class Config: env_file = ".env" env_file_encoding = "utf-8" + env_nested_delimiter = "__" @lru_cache() diff --git a/classquiz/oauth/__init__.py b/classquiz/oauth/__init__.py index af8115a..4cbf500 100644 --- a/classquiz/oauth/__init__.py +++ b/classquiz/oauth/__init__.py @@ -9,7 +9,7 @@ from jose import jws, jwt, JWTError, JWSError from classquiz.auth import ACCESS_TOKEN_EXPIRE_MINUTES, create_access_token from classquiz.db.models import UserSession -from classquiz.oauth import google, github +from classquiz.oauth import google, github, custom from classquiz.config import settings settings = settings() @@ -17,6 +17,7 @@ settings = settings() router = APIRouter() router.include_router(google.router, prefix="/google") router.include_router(github.router, prefix="/github") +router.include_router(custom.router, prefix="/custom") async def rememberme_middleware(request: Request, call_next): diff --git a/classquiz/oauth/custom.py b/classquiz/oauth/custom.py new file mode 100644 index 0000000..e166cd2 --- /dev/null +++ b/classquiz/oauth/custom.py @@ -0,0 +1,95 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +import uuid + +import asyncpg +from fastapi import APIRouter, Request, HTTPException, Response +from classquiz.config import settings + +from classquiz.db.models import User, UserAuthTypes +from classquiz.auth import check_token +from classquiz.helpers.avatar import gzipped_user_avatar +from classquiz.oauth.authenticate_user import log_user_in, rememberme_check +from classquiz.oauth.init_oauth import init_oauth + +settings = settings() + +router = APIRouter() + + +@router.get("/login") +async def openid_login(req: Request): + print(settings.custom_openid_provider) + if settings.google_client_secret is None or settings.google_client_id is None: + raise HTTPException(status_code=501, detail="Custom-OAuth-Login isn't available on this server") + oauth = init_oauth() + + return await oauth.custom.authorize_redirect(req, f"{settings.root_address}/api/v1/users/oauth/custom/auth") + + +@router.get("/auth") +async def auth(request: Request, response: Response): + if settings.custom_openid_provider.client_id is None or settings.custom_openid_provider.client_secret is None: + raise HTTPException(status_code=501, detail="Google-Login isn't available on this server") + access_token = request.cookies.get("access_token") + rememberme_token = request.cookies.get("rememberme_token") + if access_token is not None: + try: + data = await check_token(access_token) + if data is not None: + return + except HTTPException: + pass + if rememberme_token is not None: + return await rememberme_check(rememberme_token=rememberme_token, response=response) + oauth = init_oauth() + + user_data = await oauth.google.authorize_access_token(request) + print(user_data) + # try: + # user_data = OauthGoogleResponse(**user_data).userinfo + # except (TypeError, ValidationError): + # raise HTTPException(status_code=401, detail="Something went wrong.") + user_in_db = await User.objects.get_or_none(email=user_data.email) + if user_in_db is None: + # REGISTER USER + try: + await User.objects.create( + id=uuid.uuid4(), + email=user_data.email, + username=user_data.name, + verified=user_data.email_verified, + auth_type=UserAuthTypes.GOOGLE, + google_uid=user_data.sub, + avatar=gzipped_user_avatar(), + ) + except Exception as e: + if type(e) == asyncpg.exceptions.UniqueViolationError: + error = True + counter = 1 + while error: + try: + await User.objects.create( + id=uuid.uuid4(), + email=user_data.email, + username=f"{user_data.name}{counter}", + verified=user_data.email_verified, + auth_type=UserAuthTypes.GOOGLE, + google_uid=user_data.sub, + avatar=gzipped_user_avatar(), + ) + error = False + except asyncpg.exceptions.UniqueViolationError: + counter += 1 + error = True + else: + raise HTTPException(status_code=500, detail=str(e)) + user = await User.objects.get_or_none( + email=user_data.email, google_uid=user_data.sub, auth_type=UserAuthTypes.GOOGLE, verified=True + ) + + await log_user_in(user=user, request=request, response=response) + response.headers.append("Location", "/account/login") + response.status_code = 302 + return response diff --git a/classquiz/oauth/init_oauth.py b/classquiz/oauth/init_oauth.py index 85d7d64..1f39e8d 100644 --- a/classquiz/oauth/init_oauth.py +++ b/classquiz/oauth/init_oauth.py @@ -34,7 +34,7 @@ def init_oauth() -> OAuth: oauth.register( name="custom", client_kwargs={"scope": settings.custom_openid_provider.scopes}, - server_metadata_url=settings.custom_openid_provider, + server_metadata_url=settings.custom_openid_provider.server_metadata_url, client_id=settings.custom_openid_provider.client_id, client_secret=settings.custom_openid_provider.client_secret, )