Cleanup
Some checks failed
/ build (push) Failing after 15s
/ test (push) Successful in 5s

This commit is contained in:
phil 2025-01-19 16:27:12 +01:00
parent 5b70d4bbea
commit 90cfdb66dd
2 changed files with 33 additions and 18 deletions

View file

@ -13,13 +13,15 @@ from fastapi import Depends, FastAPI, HTTPException, Request, status
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from fastapi.security import OpenIdConnect
from starlette.middleware.sessions import SessionMiddleware from starlette.middleware.sessions import SessionMiddleware
from authlib.integrations.starlette_client.apps import StarletteOAuth2App from authlib.integrations.starlette_client.apps import StarletteOAuth2App
from authlib.integrations.base_client import OAuthError from authlib.integrations.base_client import OAuthError
from authlib.integrations.httpx_client import AsyncOAuth2Client
from authlib.oauth2.rfc6749 import OAuth2Token from authlib.oauth2.rfc6749 import OAuth2Token
from pkce import generate_code_verifier, generate_pkce_pair
# TODO: PKCE
# from authlib.integrations.httpx_client import AsyncOAuth2Client
# from fastapi.security import OpenIdConnect
# from pkce import generate_code_verifier, generate_pkce_pair
from .settings import settings, OIDCProvider from .settings import settings, OIDCProvider
from .models import User from .models import User
@ -91,7 +93,12 @@ async def home(
) -> HTMLResponse: ) -> HTMLResponse:
now = datetime.now() now = datetime.now()
if oidc_provider and ( if oidc_provider and (
(provider := providers_settings.get(oidc_provider.name)) is not None (
provider := providers_settings.get(
request.session.get("oidc_provider_id", "")
)
)
is not None
): ):
resources = provider.resources resources = provider.resources
else: else:
@ -127,22 +134,22 @@ async def login(request: Request, oidc_provider_id: str) -> RedirectResponse:
provider: StarletteOAuth2App = getattr(authlib_oauth, oidc_provider_id) provider: StarletteOAuth2App = getattr(authlib_oauth, oidc_provider_id)
except AttributeError: except AttributeError:
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "No such provider") raise HTTPException(status.HTTP_401_UNAUTHORIZED, "No such provider")
if ( # if (
code_challenge_method := providers_settings[ # code_challenge_method := providers_settings[
oidc_provider_id # oidc_provider_id
].code_challenge_method # ].code_challenge_method
) is not None: # ) is not None:
client = AsyncOAuth2Client(..., code_challenge_method=code_challenge_method) # #client = AsyncOAuth2Client(..., code_challenge_method=code_challenge_method)
code_verifier = generate_code_verifier() # code_verifier = generate_code_verifier()
logger.debug("TODO: PKCE") # logger.debug("TODO: PKCE")
else: # else:
code_verifier = None # code_verifier = None
try: try:
response = await provider.authorize_redirect( response = await provider.authorize_redirect(
request, request,
redirect_uri, redirect_uri,
access_type="offline", access_type="offline",
code_verifier=code_verifier, code_verifier=None,
) )
return response return response
except HTTPError: except HTTPError:
@ -261,11 +268,14 @@ async def get_resource(
token: Annotated[OAuth2Token, Depends(get_token)], token: Annotated[OAuth2Token, Depends(get_token)],
) -> JSONResponse: ) -> JSONResponse:
"""Generic path for testing a resource provided by a provider""" """Generic path for testing a resource provided by a provider"""
assert user is not None
if oidc_provider is None: if oidc_provider is None:
raise HTTPException( raise HTTPException(
status.HTTP_406_NOT_ACCEPTABLE, detail="No such oidc provider" status.HTTP_406_NOT_ACCEPTABLE, detail="No such oidc provider"
) )
if (provider := providers_settings.get(oidc_provider.name)) is None: if (
provider := providers_settings.get(request.session.get("oidc_provider_id", ""))
) is None:
raise HTTPException( raise HTTPException(
status.HTTP_406_NOT_ACCEPTABLE, detail="No oidc provider setting" status.HTTP_406_NOT_ACCEPTABLE, detail="No oidc provider setting"
) )
@ -299,18 +309,21 @@ async def public() -> HTMLResponse:
async def get_protected( async def get_protected(
user: Annotated[User, Depends(get_current_user)] user: Annotated[User, Depends(get_current_user)]
) -> HTMLResponse: ) -> HTMLResponse:
assert user is not None
return HTMLResponse("<h1>Only authenticated users can see this</h1>") return HTMLResponse("<h1>Only authenticated users can see this</h1>")
@app.get("/protected-by-foorole") @app.get("/protected-by-foorole")
@hasrole("foorole") @hasrole("foorole")
async def get_protected_by_foorole(request: Request) -> HTMLResponse: async def get_protected_by_foorole(request: Request) -> HTMLResponse:
assert request is not None
return HTMLResponse("<h1>Only users with foorole can see this</h1>") return HTMLResponse("<h1>Only users with foorole can see this</h1>")
@app.get("/protected-by-barrole") @app.get("/protected-by-barrole")
@hasrole("barrole") @hasrole("barrole")
async def get_protected_by_barrole(request: Request) -> HTMLResponse: async def get_protected_by_barrole(request: Request) -> HTMLResponse:
assert request is not None
return HTMLResponse("<h1>Protected by barrole</h1>") return HTMLResponse("<h1>Protected by barrole</h1>")
@ -318,12 +331,14 @@ async def get_protected_by_barrole(request: Request) -> HTMLResponse:
@hasrole("barrole") @hasrole("barrole")
@hasrole("foorole") @hasrole("foorole")
async def get_protected_by_foorole_and_barrole(request: Request) -> HTMLResponse: async def get_protected_by_foorole_and_barrole(request: Request) -> HTMLResponse:
assert request is not None
return HTMLResponse("<h1>Only users with foorole and barrole can see this</h1>") return HTMLResponse("<h1>Only users with foorole and barrole can see this</h1>")
@app.get("/protected-by-foorole-or-barrole") @app.get("/protected-by-foorole-or-barrole")
@hasrole(["foorole", "barrole"]) @hasrole(["foorole", "barrole"])
async def get_protected_by_foorole_or_barrole(request: Request) -> HTMLResponse: async def get_protected_by_foorole_or_barrole(request: Request) -> HTMLResponse:
assert request is not None
return HTMLResponse("<h1>Only users with foorole or barrole can see this</h1>") return HTMLResponse("<h1>Only users with foorole or barrole can see this</h1>")
@ -333,6 +348,7 @@ async def get_introspect(
oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)], oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
token: Annotated[OAuth2Token, Depends(get_token)], token: Annotated[OAuth2Token, Depends(get_token)],
) -> JSONResponse: ) -> JSONResponse:
assert request is not None
if ( if (
response := await oidc_provider.post( response := await oidc_provider.post(
oidc_provider.server_metadata["introspection_endpoint"], oidc_provider.server_metadata["introspection_endpoint"],
@ -352,6 +368,7 @@ async def get_forgejo_user_info(
oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)], oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
token: Annotated[OAuth2Token, Depends(get_token)], token: Annotated[OAuth2Token, Depends(get_token)],
) -> HTMLResponse: ) -> HTMLResponse:
assert request is not None
if ( if (
response := await oidc_provider.get( response := await oidc_provider.get(
"/api/v1/user/repos", "/api/v1/user/repos",

View file

@ -58,8 +58,6 @@
<a href="protected-by-barrole">Auth + barrole protected content</a> <a href="protected-by-barrole">Auth + barrole protected content</a>
<a href="protected-by-foorole-and-barrole">Auth + foorole and barrole protected content</a> <a href="protected-by-foorole-and-barrole">Auth + foorole and barrole protected content</a>
<a href="fast_api_depends" class="hidden">Using FastAPI Depends</a> <a href="fast_api_depends" class="hidden">Using FastAPI Depends</a>
<a href="other">Other</a>
<a href="oauth2-forgejo-test">OAuth2 test (forgejo user info)</a>
<a href="introspect">Introspect token (401 expected)</a> <a href="introspect">Introspect token (401 expected)</a>
</div> </div>
{% if resources %} {% if resources %}