-
Notifications
You must be signed in to change notification settings - Fork 66
Description
Followup to #9773 — logout is currently the only API operation that needs audit logging but doesn't have it. This sounds more urgent than it is because sessions are a lot more likely to be deleted due to expiry (an event that is not currently logged because it is not a discrete API operation) than they are to be deleted by a call to logout — any request that comes in with an expired session causes that session to be hard deleted:
omicron/nexus/auth/src/authn/external/session_cookie.rs
Lines 134 to 138 in 10f6883
| // if the session has gone unused for longer than idle_timeout, it is | |
| // expired | |
| let now = Utc::now(); | |
| if session.time_last_used() + ctx.session_idle_timeout() < now { | |
| let expired_session = ctx.session_expire(token).await; |
Lines 529 to 532 in 10f6883
| async fn session_expire(&self, token: String) -> Option<()> { | |
| let opctx = self.nexus.opctx_external_authn(); | |
| self.nexus.session_hard_delete_by_token(opctx, token).await.ok() | |
| } |
Audit logging logout requires a tiny bit of work because the endpoint does auth in a funny way: we just try to delete a session matching the provided token. If the token doesn't match anything, it's a noop, and the request goes through fine. In order to make logging work we'd probably have to separate the lookup of the session from the delete in order to have a session ID to write down:
- Look up session by token
- Log logout call with session ID
- Delete token
- Complete log
omicron/nexus/src/external_api/http_entrypoints.rs
Lines 8125 to 8144 in 10f6883
| async fn logout( | |
| rqctx: RequestContext<Self::Context>, | |
| cookies: Cookies, | |
| ) -> Result<HttpResponseHeaders<HttpResponseUpdatedNoContent>, HttpError> | |
| { | |
| let apictx = rqctx.context(); | |
| let handler = async { | |
| let nexus = &apictx.context.nexus; | |
| // this is kind of a weird one, but we're only doing things here | |
| // that are authorized directly by the possession of the token, | |
| // which makes it somewhat like a login | |
| let opctx = nexus.opctx_external_authn(); | |
| let session_cookie = | |
| cookies.get(session_cookie::SESSION_COOKIE_COOKIE_NAME); | |
| // Look up session and delete it if present | |
| if let Some(cookie) = session_cookie { | |
| let token = cookie.value().to_string(); | |
| nexus.session_hard_delete_by_token(&opctx, token).await?; | |
| } |