Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix allow-list handling with subresources
Problem ------- When Via HTML is using Checkmate's allow-list (`CHECKMATE_ALLOW_ALL` is disabled) website subresources (CSS, images, etc) are getting blocked because they're not on the allow-list. `AuthenticationView` allows the subresource requests because they have either a `Sec-Fetch-Site: same-origin` header or a `Referer` header that refers to Via itself: https://github.com/hypothesis/viahtml/blob/24a8d24c2188b4b30909d4df55efaea41740f8ef/viahtml/views/authentication.py#L70-L90 But `BlocklistView` then passes `allow_all=False` to Checkmate (because the `CHECKMATE_ALLOW_ALL` setting is disabled) and Checkmate blocks the URLs because they're not on the allow-list: https://github.com/hypothesis/viahtml/blob/24a8d24c2188b4b30909d4df55efaea41740f8ef/viahtml/views/blocklist.py#L40-L47 Solution -------- The `allow_all` parameter to Checkmate needs to vary depending on the request's origin: 1. If the request is a top-level document request that's being allowed because it has a `Referer` that's on the `VIA_ALLOWED_REFERRERS` list then `allow_all` should be either `True` or `False` depending on the `CHECKMATE_ALLOW_ALL` setting. This happens in the LMS context when the LMS app redirects the browser to Via HTML. In this context `CHECKMATE_ALLOW_ALL` is `True` - we don't use the allow-list in the LMS context. This also happens in the public context when Via 3 redirects the browser to Via HTML. In this context `CHECKMATE_ALLOW_ALL` is `False` - we _do_ use the allow-list in the public context. **Further work:** when the referrer is Via 3 it's technically unnecessary for Via HTML to call Checkmate at all since Via 3 will already have done so. But Via HTML doesn't currently have any way to distinguish Via 3 from other allowed referrers that won't have called Checkmate themselves (like LMS). Also if we're going to skip the blocklist we might want to verify that the referrer really was Via 3 in some more secure way than just looking at the `Referer` header. So there's no way to implement this optimization currently. 2. If the request is being allowed because Via HTML's `Referer` / `Sec-Fetch-Site`-based authentication is disabled (the `VIA_DISABLE_AUTHENTICATION` setting is on) then `allow_all` should come from the `CHECKMATE_ALLOW_ALL` setting. This can be used in dev (though it's not by default). 3. If the request is a subresource request that's being allowed because it has a `Sec-Fetch-Site: same-origin` header or because it has a `Referer` header that refers to Via itself then `allow_all` should always be `True` regardless of the `CHECKMATE_ALLOW_ALL` setting - we don't apply the allow-list to subresource requests. This third case is the change that actually fixes the bug. This needs to happen whether the `VIA_DISABLE_AUTHENTICATION` setting is on or off: when `VIA_DISABLE_AUTHENTICATION` is on we still need to look for same-origin `Sec-Fetch-Site` and `Referer` headers so we can identify subresource requests and set `allow_all` to `True`. Refactoring ----------- This means that the logic of `AuthenticationView` and `BlocklistView` is coupled: `AuthenticationView` decides whether a request is a subresource request or not, and based on this decision `BlocklistView` needs to alter the `allow_all` param to Checkmate. For this reason I've merged `AuthenticationView` and `BlocklistView` into a new `SecurityView` that contains everything that `AuthenticationView` and `BlocklistView` used to do before, plus the above change. This results in a `SecurityView` class that triggers PyLint's `too-many-arguments` warning, but I think the class is actually quite simple. It's less than 150 lines and it's good to have all the security code and tests together in one place. This class is much more thoroughly unit-tested than the previous two classes were. Further work ------------ I think the `VIA_DISABLE_AUTHENTICATION` setting can be deleted as it's not used by default (even in dev) and not needed. This'll simplify things. I'll send a follow-up PR to do that.
- Loading branch information