diff --git a/docs/configuration.md b/docs/configuration.md index 63836a61..d5dea892 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -11,7 +11,7 @@ The following flags are available: | Flag | Type | Description | Default Value | |:----------------------------------|:---------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------| -| `auto-login` | boolean | Automatically redirect all HTTP GET requests to login if the user does not have a valid session for all matching upstream paths. | | +| `auto-login` | boolean | Enforce authentication if the user does not have a valid session for all matching upstream paths. Automatically redirects HTTP navigation requests to login, otherwise responds with 401 with the Location header set. | | | `auto-login-ignore-paths` | strings | Comma separated list of absolute paths to ignore when `auto-login` is enabled. Supports basic wildcard matching with glob-style asterisks. Invalid patterns are ignored. | | | `bind-address` | string | Listen address for public connections. | `127.0.0.1:3000` | | `cookie-prefix` | string | Prefix for cookie names. | `io.nais.wonderwall` | diff --git a/docs/sessions.md b/docs/sessions.md index f6e9ba5c..39491175 100644 --- a/docs/sessions.md +++ b/docs/sessions.md @@ -1,6 +1,14 @@ # Session Management -Sessions are stored server-side; we only store a session identifier at the end-user's user agent. +When a user authenticates themselves, they receive a session. Sessions are stored server-side; we only store a session identifier at the end-user's user agent. + +A session has three states: + +- _active_ - the session is valid +- _inactive_ - the session has reached the _inactivity timeout_ and is considered invalid +- _expired_ - the session has reached its _maximum lifetime_ and is considered invalid + +Requests with an _invalid_ session are considered _unauthenticated_. ## Session Metadata @@ -11,7 +19,7 @@ User agents can access their own session metadata by using [the `/oauth2/session Every session has a maximum lifetime. The lifetime is indicated by the `session.ends_at` and `session.ends_in_seconds` fields in the session metadata. -When the session reaches the maximum lifetime, it is considered to be _expired_ or _ended_, after which the user is essentially unauthenticated. +When the session reaches the maximum lifetime, it is considered to be _expired_, after which the user is essentially unauthenticated. A new session must be acquired by redirecting the user to [the `/oauth2/login` endpoint](endpoints.md#oauth2login) again. The maximum lifetime can be configured with the `session.max-lifetime` flag. @@ -42,7 +50,7 @@ In SSO mode, tokens can not be automatically refreshed. They must be refreshed b A session can be marked as _inactive_ before it _expires_ (reaches the maximum lifetime). This happens if the time since the last _refresh_ exceeds the given _inactivity timeout_. -An inactive session _cannot_ be refreshed; a new session must be acquired by redirecting the user to the `/oauth2/login` endpoint. +An _inactive_ session _cannot_ be refreshed; a new session must be acquired by redirecting the user to the `/oauth2/login` endpoint. This is useful if you want to ensure that an end-user can re-authenticate with the identity provider if they've been gone from an authenticated session for some time. Inactivity support is enabled with the `session.inactivity` option, which also requires `session.refresh`. diff --git a/docs/usage.md b/docs/usage.md index ade86266..40d53c7c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -21,15 +21,36 @@ When you must authenticate a user, redirect to the user to [the `/oauth2/login` #### 1.1. Autologin -The `auto-login` option (disabled by default) will configure Wonderwall to automatically redirect any HTTP `GET` requests to the login endpoint if the user does not have a valid session. -It will automatically set the `redirect` parameter for logins to the URL for the original request so that the user is redirected back to their intended location after login. +The `auto-login` option will configure Wonderwall to enforce authentication for **all** requests, except for the paths that are explicitly [excluded](configuration.md#auto-login-ignore-paths). -You should still check the `Authorization` header for a token and validate the token. -This is especially important as auto-login will **NOT** trigger for HTTP requests that are not `GET` requests, such as `POST` or `PUT`. +If the user is _unauthenticated_ or has an [_inactive_ or _expired_ session](sessions.md), all requests will be short-circuited (i.e. return early and **not** proxied to your application). +The short-circuited response depends on whether the request is a _top-level navigation_ request or not. +A _top-level navigation_ request has the following properties: -To ensure smooth end-user experiences whenever their session expires, your application must thus actively validate and -properly handle such requests. For example, your application might respond with an HTTP 401 to allow frontends to -cache or store payloads before redirecting them back to the login endpoint. +1. Is a `GET` request +2. Has the Fetch metadata headers `Sec-Fetch-Dest=document` and `Sec-Fetch-Mode=navigate` + +If the user agent does not support the Fetch metadata headers, we look for an `Accept` header that includes `text/html`. + +A _top-level navigation_ request results in a HTTP 302 Found response with the `Location` header pointing to [the `/oauth2/login` endpoint](endpoints.md#oauth2login). +The `redirect` parameter in the login URL is automatically set to the URL for the original request, so that the user is redirected back to their intended location after login. + +Other requests are considered non-navigational requests, and they will result in a HTTP 401 Unauthorized response. +The `Location` header is set as before, and a JSON response is included for convenience: + +```json +{ + "correlation_id": "388d19c6-d439-4ff3-a77f-0ac3421418b2", + "error": "unauthenticated", + "error_description": "request is not authenticated, please log in", + "login_url": "/oauth2/login?redirect=http%3A%2F%2Flocalhost%3A3000%2Fasdf" +} +``` + +The `redirect` parameter in the login URL is set to the value found in the `Referer` header, so that the user is redirected back to their intended location after login. +If the `Referer` header is empty, the `redirect` parameter is set to the matching ingress path for the original request. + +For defence in depth, you should still check the `Authorization` header for a token and validate the token even when using auto-login. ### 2. Logout diff --git a/pkg/config/config.go b/pkg/config/config.go index b16dec42..301c345f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -106,7 +106,7 @@ func Initialize() (*Config, error) { flag.Duration(ShutdownGracefulPeriod, 30*time.Second, "Graceful shutdown period when receiving a shutdown signal after which the server is forcibly exited.") flag.Duration(ShutdownWaitBeforePeriod, 0*time.Second, "Wait period when receiving a shutdown signal before actually starting a graceful shutdown. Useful for allowing propagation of Endpoint updates in Kubernetes.") - flag.Bool(AutoLogin, false, "Automatically redirect all HTTP GET requests to login if the user does not have a valid session for all matching upstream paths.") + flag.Bool(AutoLogin, false, "Enforce authentication if the user does not have a valid session for all matching upstream paths. Automatically redirects HTTP navigation requests to login, otherwise responds with 401 with the Location header set.") flag.StringSlice(AutoLoginIgnorePaths, []string{}, "Comma separated list of absolute paths to ignore when 'auto-login' is enabled. Supports basic wildcard matching with glob-style asterisks. Invalid patterns are ignored.") flag.String(CookiePrefix, "io.nais.wonderwall", "Prefix for cookie names.") flag.String(EncryptionKey, "", "Base64 encoded 256-bit cookie encryption key; must be identical in instances that share session store.")