Fix OAuth

This commit is contained in:
Mawoka
2026-06-24 18:09:00 +02:00
parent a9b9aa6e96
commit 0f5a581ead
3 changed files with 100 additions and 66 deletions
+41 -27
View File
@@ -6,15 +6,15 @@
import uuid import uuid
import asyncpg import asyncpg
from fastapi import APIRouter, Request, HTTPException, Response from fastapi import APIRouter, HTTPException, Request, Response
from classquiz.config import settings from pydantic import BaseModel, ValidationError
from classquiz.db.models import User, UserAuthTypes
from classquiz.auth import check_token from classquiz.auth import check_token
from classquiz.config import settings
from classquiz.db.models import User, UserAuthTypes
from classquiz.helpers.avatar import gzipped_user_avatar from classquiz.helpers.avatar import gzipped_user_avatar
from classquiz.oauth.authenticate_user import log_user_in, rememberme_check from classquiz.oauth.authenticate_user import log_user_in, rememberme_check
from classquiz.oauth.init_oauth import init_oauth from classquiz.oauth.init_oauth import init_oauth
from pydantic import BaseModel, ValidationError
settings = settings() settings = settings()
@@ -47,17 +47,29 @@ class OpenIDResponse(BaseModel):
@router.get("/login") @router.get("/login")
async def openid_login(req: Request): async def openid_login(req: Request):
if settings.custom_openid_provider.client_id is None or settings.custom_openid_provider.client_secret is None: if (
raise HTTPException(status_code=501, detail="Custom-OAuth-Login isn't available on this server") settings.custom_openid_provider.client_id is None
or settings.custom_openid_provider.client_secret is None
):
raise HTTPException(
status_code=501, detail="Custom-OAuth-Login isn't available on this server"
)
oauth = init_oauth() oauth = init_oauth()
return await oauth.custom.authorize_redirect(req, f"{settings.root_address}/api/v1/users/oauth/custom/auth") return await oauth.custom.authorize_redirect(
req, f"{settings.root_address}/api/v1/users/oauth/custom/auth"
)
@router.get("/auth") @router.get("/auth")
async def auth(request: Request, response: Response): 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: if (
raise HTTPException(status_code=501, detail="Custom-OAuth-Login isn't available on this server") settings.custom_openid_provider.client_id is None
or settings.custom_openid_provider.client_secret is None
):
raise HTTPException(
status_code=501, detail="Custom-OAuth-Login isn't available on this server"
)
access_token = request.cookies.get("access_token") access_token = request.cookies.get("access_token")
rememberme_token = request.cookies.get("rememberme_token") rememberme_token = request.cookies.get("rememberme_token")
if access_token is not None: if access_token is not None:
@@ -68,7 +80,9 @@ async def auth(request: Request, response: Response):
except HTTPException: except HTTPException:
pass pass
if rememberme_token is not None: if rememberme_token is not None:
return await rememberme_check(rememberme_token=rememberme_token, response=response) return await rememberme_check(
rememberme_token=rememberme_token, response=response
)
oauth = init_oauth() oauth = init_oauth()
user_data = await oauth.custom.authorize_access_token(request) user_data = await oauth.custom.authorize_access_token(request)
@@ -77,29 +91,29 @@ async def auth(request: Request, response: Response):
except (TypeError, ValidationError): except (TypeError, ValidationError):
raise HTTPException(status_code=401, detail="Something went wrong.") raise HTTPException(status_code=401, detail="Something went wrong.")
try:
await User.objects.create(
id=uuid.uuid4(),
email=user_data.email,
username=user_data.preferred_username,
verified=user_data.email_verified,
auth_type=UserAuthTypes.CUSTOM,
google_uid=user_data.sub.hex,
avatar=gzipped_user_avatar(),
)
# skipcq: PYL-W0703
except asyncpg.exceptions.UniqueViolationError:
# Most likely a duplicate email/username, not UUID.
raise HTTPException(status_code=400, detail="User already exists.")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
user = await User.objects.get_or_none( user = await User.objects.get_or_none(
email=user_data.email, email=user_data.email,
google_uid=user_data.sub.hex, google_uid=user_data.sub.hex,
auth_type=UserAuthTypes.CUSTOM, auth_type=UserAuthTypes.CUSTOM,
verified=True, verified=True,
) )
print(user_data) if user is None:
try:
user = await User.objects.create(
id=uuid.uuid4(),
email=user_data.email,
username=user_data.preferred_username,
verified=user_data.email_verified,
auth_type=UserAuthTypes.CUSTOM,
google_uid=user_data.sub.hex,
avatar=gzipped_user_avatar(),
)
# skipcq: PYL-W0703
except asyncpg.exceptions.UniqueViolationError:
# Most likely a duplicate email/username, not UUID.
raise HTTPException(status_code=400, detail="User already exists.")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
await log_user_in(user=user, request=request, response=response) await log_user_in(user=user, request=request, response=response)
response.headers.append("Location", "/account/login") response.headers.append("Location", "/account/login")
+30 -21
View File
@@ -4,19 +4,19 @@
import uuid import uuid
from datetime import datetime
import asyncpg import asyncpg
import authlib.integrations.base_client import authlib.integrations.base_client
from fastapi import APIRouter, Request, HTTPException, Response from fastapi import APIRouter, HTTPException, Request, Response
from fastapi.responses import RedirectResponse
from pydantic import BaseModel
from classquiz.auth import check_token from classquiz.auth import check_token
from classquiz.config import settings from classquiz.config import settings
from fastapi.responses import RedirectResponse
from classquiz.db.models import User, UserAuthTypes from classquiz.db.models import User, UserAuthTypes
from pydantic import BaseModel
from classquiz.helpers.avatar import gzipped_user_avatar from classquiz.helpers.avatar import gzipped_user_avatar
from classquiz.oauth.authenticate_user import log_user_in, rememberme_check from classquiz.oauth.authenticate_user import log_user_in, rememberme_check
from datetime import datetime
from classquiz.oauth.init_oauth import init_oauth from classquiz.oauth.init_oauth import init_oauth
settings = settings() settings = settings()
@@ -76,15 +76,21 @@ class GitHubOauthResponse(BaseModel):
@router.get("/login") @router.get("/login")
async def github_login(req: Request): async def github_login(req: Request):
if settings.github_client_id is None or settings.github_client_secret is None: if settings.github_client_id is None or settings.github_client_secret is None:
raise HTTPException(status_code=501, detail="GitHub-Login isn't available on this server") raise HTTPException(
status_code=501, detail="GitHub-Login isn't available on this server"
)
oauth = init_oauth() oauth = init_oauth()
return await oauth.github.authorize_redirect(req, f"{settings.root_address}/api/v1/users/oauth/github/auth") return await oauth.github.authorize_redirect(
req, f"{settings.root_address}/api/v1/users/oauth/github/auth"
)
@router.get("/auth") @router.get("/auth")
async def auth(request: Request, response: Response): async def auth(request: Request, response: Response):
if settings.github_client_id is None or settings.github_client_secret is None: if settings.github_client_id is None or settings.github_client_secret is None:
raise HTTPException(status_code=501, detail="GitHub-Login isn't available on this server") raise HTTPException(
status_code=501, detail="GitHub-Login isn't available on this server"
)
access_token = request.cookies.get("access_token") access_token = request.cookies.get("access_token")
rememberme_token = request.cookies.get("rememberme_token") rememberme_token = request.cookies.get("rememberme_token")
if access_token is not None: if access_token is not None:
@@ -95,7 +101,9 @@ async def auth(request: Request, response: Response):
except HTTPException: except HTTPException:
pass pass
if rememberme_token is not None: if rememberme_token is not None:
return await rememberme_check(rememberme_token=rememberme_token, response=response) return await rememberme_check(
rememberme_token=rememberme_token, response=response
)
oauth = init_oauth() oauth = init_oauth()
try: try:
token = await oauth.github.authorize_access_token(request) token = await oauth.github.authorize_access_token(request)
@@ -107,25 +115,26 @@ async def auth(request: Request, response: Response):
if user_data.email is None: if user_data.email is None:
return RedirectResponse("/account/oauth-error?error=email") return RedirectResponse("/account/oauth-error?error=email")
# REGISTER USER # REGISTER USER
try:
await User.objects.create(
id=uuid.uuid4(),
email=user_data.email,
username=user_data.login,
verified=True,
auth_type=UserAuthTypes.GITHUB,
avatar=gzipped_user_avatar(),
)
except asyncpg.exceptions.UniqueViolationError:
raise HTTPException(status_code=400, detail="User already exists.")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
user = await User.objects.get_or_none( user = await User.objects.get_or_none(
email=user_data.email, email=user_data.email,
username=user_data.login, username=user_data.login,
auth_type=UserAuthTypes.GITHUB, auth_type=UserAuthTypes.GITHUB,
verified=True, verified=True,
) )
if user is None:
try:
user = await User.objects.create(
id=uuid.uuid4(),
email=user_data.email,
username=user_data.login,
verified=True,
auth_type=UserAuthTypes.GITHUB,
avatar=gzipped_user_avatar(),
)
except asyncpg.exceptions.UniqueViolationError:
raise HTTPException(status_code=400, detail="User already exists.")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
await log_user_in(user=user, request=request, response=response) await log_user_in(user=user, request=request, response=response)
response.headers.append("Location", "/account/login") response.headers.append("Location", "/account/login")
+29 -18
View File
@@ -51,16 +51,22 @@ class OauthGoogleResponse(BaseModel):
@router.get("/login") @router.get("/login")
async def google_login(req: Request): async def google_login(req: Request):
if settings.google_client_secret is None or settings.google_client_id is None: if settings.google_client_secret is None or settings.google_client_id is None:
raise HTTPException(status_code=501, detail="Google-Login isn't available on this server") raise HTTPException(
status_code=501, detail="Google-Login isn't available on this server"
)
oauth = init_oauth() oauth = init_oauth()
return await oauth.google.authorize_redirect(req, f"{settings.root_address}/api/v1/users/oauth/google/auth") return await oauth.google.authorize_redirect(
req, f"{settings.root_address}/api/v1/users/oauth/google/auth"
)
@router.get("/auth") @router.get("/auth")
async def auth(request: Request, response: Response): async def auth(request: Request, response: Response):
if settings.google_client_secret is None or settings.google_client_id is None: if settings.google_client_secret is None or settings.google_client_id is None:
raise HTTPException(status_code=501, detail="Google-Login isn't available on this server") raise HTTPException(
status_code=501, detail="Google-Login isn't available on this server"
)
access_token = request.cookies.get("access_token") access_token = request.cookies.get("access_token")
rememberme_token = request.cookies.get("rememberme_token") rememberme_token = request.cookies.get("rememberme_token")
if access_token is not None: if access_token is not None:
@@ -71,7 +77,9 @@ async def auth(request: Request, response: Response):
except HTTPException: except HTTPException:
pass pass
if rememberme_token is not None: if rememberme_token is not None:
return await rememberme_check(rememberme_token=rememberme_token, response=response) return await rememberme_check(
rememberme_token=rememberme_token, response=response
)
oauth = init_oauth() oauth = init_oauth()
user_data = await oauth.google.authorize_access_token(request) user_data = await oauth.google.authorize_access_token(request)
@@ -80,26 +88,29 @@ async def auth(request: Request, response: Response):
except (TypeError, ValidationError): except (TypeError, ValidationError):
raise HTTPException(status_code=401, detail="Something went wrong.") raise HTTPException(status_code=401, detail="Something went wrong.")
# REGISTER USER # 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 asyncpg.exceptions.UniqueViolationError:
raise HTTPException(status_code=400, detail="User already exists.")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
user = await User.objects.get_or_none( user = await User.objects.get_or_none(
email=user_data.email, email=user_data.email,
google_uid=user_data.sub, google_uid=user_data.sub,
auth_type=UserAuthTypes.GOOGLE, auth_type=UserAuthTypes.GOOGLE,
verified=True, verified=True,
) )
if user is None:
if user_data.email_verified is False:
raise HTTPException(status_code=401, detail="Email isn't verified")
try:
user = await User.objects.create(
id=uuid.uuid4(),
email=user_data.email,
username=user_data.name,
verified=True,
auth_type=UserAuthTypes.GOOGLE,
google_uid=user_data.sub,
avatar=gzipped_user_avatar(),
)
except asyncpg.exceptions.UniqueViolationError:
raise HTTPException(status_code=400, detail="User already exists.")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
await log_user_in(user=user, request=request, response=response) await log_user_in(user=user, request=request, response=response)
response.headers.append("Location", "/account/login") response.headers.append("Location", "/account/login")