diff options
author | Frédéric Mangano-Tarumi <fmang@mg0.fr> | 2020-06-08 20:16:49 +0200 |
---|---|---|
committer | Lukas Fleischer <lfleischer@archlinux.org> | 2021-02-20 17:24:30 +0100 |
commit | 42f8f160b6c556a8c2006788a25b6fafe7be1c08 (patch) | |
tree | 2358467765ef190b34a3cd396fa7f056c2846b27 | |
parent | c77e9d1de0d14253ab3c3b958f459b04b233aeb8 (diff) | |
download | aur-42f8f160b6c556a8c2006788a25b6fafe7be1c08.tar.gz aur-42f8f160b6c556a8c2006788a25b6fafe7be1c08.tar.xz |
Open AUR sessions from SSO
Only the core functionality is implemented here. See the TODOs.
Signed-off-by: Lukas Fleischer <lfleischer@archlinux.org>
-rw-r--r-- | aurweb/routers/sso.py | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index b16edffb..d0802c34 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -1,9 +1,18 @@ +import time +import uuid + import fastapi from authlib.integrations.starlette_client import OAuth +from fastapi import Depends, HTTPException +from fastapi.responses import RedirectResponse +from sqlalchemy.sql import select from starlette.requests import Request import aurweb.config +import aurweb.db + +from aurweb.schema import Sessions, Users router = fastapi.APIRouter() @@ -23,8 +32,46 @@ async def login(request: Request): return await oauth.sso.authorize_redirect(request, redirect_uri, prompt="login") +def open_session(conn, user_id): + """ + Create a new user session into the database. Return its SID. + """ + # TODO check for account suspension + # TODO apply [options] max_sessions_per_user + sid = uuid.uuid4().hex + conn.execute(Sessions.insert().values( + UsersID=user_id, + SessionID=sid, + LastUpdateTS=time.time(), + )) + # TODO update Users.LastLogin and Users.LastLoginIPAddress + return sid + + @router.get("/sso/authenticate") -async def authenticate(request: Request): +async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): + """ + Receive an OpenID Connect ID token, validate it, then process it to create + an new AUR session. + """ + # TODO check for banned IPs token = await oauth.sso.authorize_access_token(request) user = await oauth.sso.parse_id_token(request, token) - return dict(user) + sub = user.get("sub") # this is the SSO account ID in JWT terminology + if not sub: + raise HTTPException(status_code=400, detail="JWT is missing its `sub` field.") + + aur_accounts = conn.execute(select([Users.c.ID]).where(Users.c.SSOAccountID == sub)) \ + .fetchall() + if not aur_accounts: + return "Sorry, we don’t seem to know you Sir " + sub + elif len(aur_accounts) == 1: + sid = open_session(conn, aur_accounts[0][Users.c.ID]) + response = RedirectResponse("/") + # TODO redirect to the referrer + response.set_cookie(key="AURSID", value=sid, httponly=True, + secure=request.url.scheme == "https") + return response + else: + # We’ve got a severe integrity violation. + raise Exception("Multiple accounts found for SSO account " + sub) |