Cleanup
This commit is contained in:
parent
5b70d4bbea
commit
90cfdb66dd
2 changed files with 33 additions and 18 deletions
|
@ -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",
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue