diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py index e1ec7efe..a8d4b141 100644 --- a/aurweb/routers/sso.py +++ b/aurweb/routers/sso.py @@ -1,6 +1,8 @@ import time import uuid +from urllib.parse import urlencode + import fastapi from authlib.integrations.starlette_client import OAuth @@ -82,3 +84,19 @@ async def authenticate(request: Request, conn=Depends(aurweb.db.connect)): else: # We’ve got a severe integrity violation. raise Exception("Multiple accounts found for SSO account " + sub) + + +@router.get("/sso/logout") +async def logout(): + """ + Disconnect the user from the SSO provider, potentially affecting every + other Arch service. AUR logout is performed by `/logout`, before it + redirects to `/sso/logout`. + + Based on the OpenID Connect Session Management specification: + https://openid.net/specs/openid-connect-session-1_0.html#RPLogout + """ + metadata = await oauth.sso.load_server_metadata() + # TODO Supply id_token_hint to the end session endpoint. + query = urlencode({'post_logout_redirect_uri': aurweb.config.get('options', 'aur_location')}) + return RedirectResponse(metadata["end_session_endpoint"] + '?' + query) diff --git a/web/html/logout.php b/web/html/logout.php index 14022001..9fd63943 100644 --- a/web/html/logout.php +++ b/web/html/logout.php @@ -5,16 +5,28 @@ set_include_path(get_include_path() . PATH_SEPARATOR . '../lib'); include_once("aur.inc.php"); # access AUR common functions include_once("acctfuncs.inc.php"); # access AUR common functions +$redirect_uri = '/'; + # if they've got a cookie, log them out - need to do this before # sending any HTML output. # if (isset($_COOKIE["AURSID"])) { + $uid = uid_from_sid($_COOKIE['AURSID']); delete_session_id($_COOKIE["AURSID"]); # setting expiration to 1 means '1 second after midnight January 1, 1970' setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); unset($_COOKIE['AURSID']); clear_expired_sessions(); + + # If the account is linked to an SSO account, disconnect the user from the SSO too. + if (isset($uid)) { + $dbh = DB::connect(); + $sso_account_id = $dbh->query("SELECT SSOAccountID FROM Users WHERE ID = " . $dbh->quote($uid)) + ->fetchColumn(); + if ($sso_account_id) + $redirect_uri = '/sso/logout'; + } } -header('Location: /'); +header("Location: $redirect_uri");