sbp commented on code in PR #874:
URL: 
https://github.com/apache/tooling-trusted-releases/pull/874#discussion_r2927142903


##########
atr/docs/asfquart-usage.md:
##########
@@ -0,0 +1,157 @@
+# 3.16. ASFQuart usage
+
+**Up**: `3.` [Developer guide](developer-guide)
+
+**Prev**: `3.15.` [TLS security configuration](tls-security-configuration)
+
+**Next**: (none)
+
+**Sections**:
+
+* [Overview](#overview)
+* [Application construction](#application-construction)
+* [Session management](#session-management)
+* [OAuth authentication](#oauth-authentication)
+* [Authentication decorators](#authentication-decorators)
+* [Exception handling](#exception-handling)
+* [Application secret and session 
encryption](#application-secret-and-session-encryption)
+* [JWT signing key storage](#jwt-signing-key-storage)
+* [Application extensions](#application-extensions)
+* [What ATR does not use from ASFQuart](#what-atr-does-not-use-from-asfquart)
+* [Security considerations for auditors](#security-considerations-for-auditors)
+
+## Overview
+
+[ASFQuart](https://github.com/apache/infrastructure-asfquart) is a shared 
framework library maintained by ASF Infrastructure that provides common 
functionality for ASF web applications built on 
[Quart](https://quart.palletsprojects.com/) (an async Python web framework). 
ATR uses ASFQuart as the foundation of its web application, relying on it for 
application construction, session management, OAuth integration with the ASF 
identity provider, and authentication enforcement.
+
+ASFQuart is not an ATR dependency in the usual sense — it is 
infrastructure-level code shared across multiple ASF services. ATR does not 
modify or vendor ASFQuart; it uses the library as published. This document 
describes what ATR uses from ASFQuart and what security-relevant behaviour is 
inherited from it.
+
+## Application construction
+
+ATR creates its application instance via `asfquart.construct()` in 
[`server.py`](/ref/atr/server.py). This call produces a `QuartApp` instance (a 
subclass of `quart.Quart`) with ASF-standard defaults applied:
+
+```python
+app = asfquart.construct(__name__, token_file="secrets/generated/apptoken.txt")
+```
+
+The `construct()` function performs the following setup that ATR inherits:
+
+* Creates the Quart application with a persistent secret key (see [Application 
secret and session encryption](#application-secret-and-session-encryption))
+* Sets secure cookie defaults: `SameSite=Strict`, `Secure=True`, 
`HttpOnly=True`
+* Registers a URL converter for filenames (`FilenameConverter`)
+* Sets up the ASF OAuth endpoint at the default `/auth` URI
+* Registers an error handler that redirects unauthenticated users to the OAuth 
login flow
+
+ATR then overrides the OAuth URLs to use the non-OIDC ASF OAuth endpoints and 
applies its own configuration via `app.config.from_object()`, taking care to 
preserve the ASFQuart-generated secret key.
+
+## Session management
+
+ATR uses ASFQuart's session module (`asfquart.session`) for all cookie-based 
user sessions. ASFQuart sessions are server-side Quart sessions keyed by the 
application ID, which means multiple ASFQuart applications on the same host do 
not share sessions.

Review Comment:
   I think I know what you mean, but "server-side" is a bit confusing because 
we don't at all store session state in ATR. We are planning to, but it's not 
done yet!



##########
atr/docs/asfquart-usage.md:
##########
@@ -0,0 +1,157 @@
+# 3.16. ASFQuart usage
+
+**Up**: `3.` [Developer guide](developer-guide)
+
+**Prev**: `3.15.` [TLS security configuration](tls-security-configuration)
+
+**Next**: (none)
+
+**Sections**:
+
+* [Overview](#overview)
+* [Application construction](#application-construction)
+* [Session management](#session-management)
+* [OAuth authentication](#oauth-authentication)
+* [Authentication decorators](#authentication-decorators)
+* [Exception handling](#exception-handling)
+* [Application secret and session 
encryption](#application-secret-and-session-encryption)
+* [JWT signing key storage](#jwt-signing-key-storage)
+* [Application extensions](#application-extensions)
+* [What ATR does not use from ASFQuart](#what-atr-does-not-use-from-asfquart)
+* [Security considerations for auditors](#security-considerations-for-auditors)
+
+## Overview
+
+[ASFQuart](https://github.com/apache/infrastructure-asfquart) is a shared 
framework library maintained by ASF Infrastructure that provides common 
functionality for ASF web applications built on 
[Quart](https://quart.palletsprojects.com/) (an async Python web framework). 
ATR uses ASFQuart as the foundation of its web application, relying on it for 
application construction, session management, OAuth integration with the ASF 
identity provider, and authentication enforcement.
+
+ASFQuart is not an ATR dependency in the usual sense — it is 
infrastructure-level code shared across multiple ASF services. ATR does not 
modify or vendor ASFQuart; it uses the library as published. This document 
describes what ATR uses from ASFQuart and what security-relevant behaviour is 
inherited from it.
+
+## Application construction
+
+ATR creates its application instance via `asfquart.construct()` in 
[`server.py`](/ref/atr/server.py). This call produces a `QuartApp` instance (a 
subclass of `quart.Quart`) with ASF-standard defaults applied:
+
+```python
+app = asfquart.construct(__name__, token_file="secrets/generated/apptoken.txt")
+```
+
+The `construct()` function performs the following setup that ATR inherits:
+
+* Creates the Quart application with a persistent secret key (see [Application 
secret and session encryption](#application-secret-and-session-encryption))
+* Sets secure cookie defaults: `SameSite=Strict`, `Secure=True`, 
`HttpOnly=True`
+* Registers a URL converter for filenames (`FilenameConverter`)
+* Sets up the ASF OAuth endpoint at the default `/auth` URI
+* Registers an error handler that redirects unauthenticated users to the OAuth 
login flow
+
+ATR then overrides the OAuth URLs to use the non-OIDC ASF OAuth endpoints and 
applies its own configuration via `app.config.from_object()`, taking care to 
preserve the ASFQuart-generated secret key.
+
+## Session management
+
+ATR uses ASFQuart's session module (`asfquart.session`) for all cookie-based 
user sessions. ASFQuart sessions are server-side Quart sessions keyed by the 
application ID, which means multiple ASFQuart applications on the same host do 
not share sessions.
+
+### Reading sessions
+
+ATR calls `asfquart.session.read()` throughout the codebase to obtain the 
current user's session. This function:
+
+1. Looks up the session cookie by application ID
+2. Checks whether the session has expired (default: 7 days of inactivity)
+3. Checks whether the session exceeds the maximum lifetime if 
`MAX_SESSION_AGE` is configured
+4. If valid, updates the last-access timestamp and returns a `ClientSession` 
object
+5. If expired or absent, returns `None`
+
+The returned `ClientSession` object provides: `uid` (ASF user ID), `fullname`, 
`email`, `committees` (PMC memberships), `projects` (committer memberships), 
`isMember`, `isChair`, `isRoot`, `mfa`, and a `metadata` dict for 
application-specific data.

Review Comment:
   Missing a couple here, `self.dn = raw_data.get("dn")` and `self.isRole = 
raw_data.get("roleaccount", False)`.



##########
atr/docs/asfquart-usage.md:
##########
@@ -0,0 +1,157 @@
+# 3.16. ASFQuart usage
+
+**Up**: `3.` [Developer guide](developer-guide)
+
+**Prev**: `3.15.` [TLS security configuration](tls-security-configuration)
+
+**Next**: (none)
+
+**Sections**:
+
+* [Overview](#overview)
+* [Application construction](#application-construction)
+* [Session management](#session-management)
+* [OAuth authentication](#oauth-authentication)
+* [Authentication decorators](#authentication-decorators)
+* [Exception handling](#exception-handling)
+* [Application secret and session 
encryption](#application-secret-and-session-encryption)
+* [JWT signing key storage](#jwt-signing-key-storage)
+* [Application extensions](#application-extensions)
+* [What ATR does not use from ASFQuart](#what-atr-does-not-use-from-asfquart)
+* [Security considerations for auditors](#security-considerations-for-auditors)
+
+## Overview
+
+[ASFQuart](https://github.com/apache/infrastructure-asfquart) is a shared 
framework library maintained by ASF Infrastructure that provides common 
functionality for ASF web applications built on 
[Quart](https://quart.palletsprojects.com/) (an async Python web framework). 
ATR uses ASFQuart as the foundation of its web application, relying on it for 
application construction, session management, OAuth integration with the ASF 
identity provider, and authentication enforcement.
+
+ASFQuart is not an ATR dependency in the usual sense — it is 
infrastructure-level code shared across multiple ASF services. ATR does not 
modify or vendor ASFQuart; it uses the library as published. This document 
describes what ATR uses from ASFQuart and what security-relevant behaviour is 
inherited from it.
+
+## Application construction
+
+ATR creates its application instance via `asfquart.construct()` in 
[`server.py`](/ref/atr/server.py). This call produces a `QuartApp` instance (a 
subclass of `quart.Quart`) with ASF-standard defaults applied:
+
+```python
+app = asfquart.construct(__name__, token_file="secrets/generated/apptoken.txt")
+```
+
+The `construct()` function performs the following setup that ATR inherits:
+
+* Creates the Quart application with a persistent secret key (see [Application 
secret and session encryption](#application-secret-and-session-encryption))
+* Sets secure cookie defaults: `SameSite=Strict`, `Secure=True`, 
`HttpOnly=True`
+* Registers a URL converter for filenames (`FilenameConverter`)
+* Sets up the ASF OAuth endpoint at the default `/auth` URI
+* Registers an error handler that redirects unauthenticated users to the OAuth 
login flow
+
+ATR then overrides the OAuth URLs to use the non-OIDC ASF OAuth endpoints and 
applies its own configuration via `app.config.from_object()`, taking care to 
preserve the ASFQuart-generated secret key.
+
+## Session management
+
+ATR uses ASFQuart's session module (`asfquart.session`) for all cookie-based 
user sessions. ASFQuart sessions are server-side Quart sessions keyed by the 
application ID, which means multiple ASFQuart applications on the same host do 
not share sessions.
+
+### Reading sessions
+
+ATR calls `asfquart.session.read()` throughout the codebase to obtain the 
current user's session. This function:
+
+1. Looks up the session cookie by application ID
+2. Checks whether the session has expired (default: 7 days of inactivity)
+3. Checks whether the session exceeds the maximum lifetime if 
`MAX_SESSION_AGE` is configured
+4. If valid, updates the last-access timestamp and returns a `ClientSession` 
object
+5. If expired or absent, returns `None`
+
+The returned `ClientSession` object provides: `uid` (ASF user ID), `fullname`, 
`email`, `committees` (PMC memberships), `projects` (committer memberships), 
`isMember`, `isChair`, `isRoot`, `mfa`, and a `metadata` dict for 
application-specific data.
+
+ATR uses the `metadata` dict to track admin impersonation state (the `admin` 
key stores the original admin's UID when browsing as another user).
+
+### Writing and clearing sessions
+
+ATR calls `asfquart.session.write()` to create sessions after OAuth login and 
during admin impersonation. The write function stores the session data with 
creation (`cts`) and last-update (`uts`) timestamps. ATR calls 
`asfquart.session.clear()` to destroy sessions on logout, session expiry, and 
when ending admin impersonation.
+
+### Session expiry
+
+ASFQuart enforces two expiry checks within `session.read()`:
+
+* **Inactivity expiry**: sessions unused for longer than `expiry_time` 
(default 7 days) are deleted
+* **Maximum lifetime**: if `MAX_SESSION_AGE` is set in the application config, 
sessions older than this value are deleted regardless of activity
+
+ATR additionally enforces its own absolute session maximum via 
`ABSOLUTE_SESSION_MAX_SECONDS` in a `before_request` hook in 
[`server.py`](/ref/atr/server.py), which is independent of ASFQuart's expiry.
+
+## OAuth authentication
+
+ATR uses ASFQuart's generic OAuth endpoint (`asfquart.generics.setup_oauth`) 
to handle the ASF OAuth login flow. The endpoint is registered at `/auth` and 
handles:
+
+* `/auth?login` — initiates the OAuth flow by generating a cryptographic state 
token (`secrets.token_hex(16)`) and redirecting to the ASF OAuth service
+* `/auth?login=/path` — same as above, but redirects the user to `/path` after 
successful login
+* `/auth?logout` — clears the user's session
+* `/auth?state=...&code=...` — callback from the ASF OAuth service that 
exchanges the authorization code for user data
+
+ATR overrides the default OAuth URLs to use the non-OIDC endpoints:
+
+```python
+asfquart.generics.OAUTH_URL_INIT = 
"https://oauth.apache.org/auth?state=%s&redirect_uri=%s";
+asfquart.generics.OAUTH_URL_CALLBACK = "https://oauth.apache.org/token?code=%s";
+```
+
+The OAuth flow has a configurable workflow timeout (default 15 minutes) after 
which pending state tokens expire. State tokens are consumed immediately on use 
to prevent replay. The callback enforces HTTPS on the redirect URI and uses a 
`Refresh` header (instead of a 302 redirect) when `SameSite=Strict` cookies are 
in use, because a cross-site redirect would cause the browser to discard the 
session cookie.

Review Comment:
   ```
                   if redirect_uri:  # if called with /auth=login=/foo, 
redirect to /foo
                       # If SameSite is set, we cannot redirect with a 30x 
response, as that may invalidate the set-cookie
                       # instead, we issue a 200 Okay with a Refresh header, 
instructing the browser to immediately go
                       # someplace else. This counts as a samesite request.
                       return quart.Response(
                           status=200,
                           response=f"Successfully logged in! Welcome, 
{oauth_data['uid']}\n",
                           headers={"Refresh": f"0; url={redirect_uri}"}
                       )
   ```
   
   Doesn't seem to check the value of `SameSite`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to