Requests for comment/MediaWiki HTTPS policy

This is a follow-up / extension of the login security request for comments.

Although this RFC is specific to https connections and cookie handling, the security policy framework can eventually apply to password, two-factor authentication, and captcha policies.

Background
The Wikimedia Foundation transitioned to use $wgSecureLogin for nearly all sites in August 2013. CentralAuth had several updates to ensure that the site and user preferences around HTTP versus HTTPS were respected throughout the central login as well.

The Wikimedia Foundation needs to handle a few special use-cases in our HTTPS policy:


 * Most users should enter their password into an HTTPS page, and submit the password via HTTPS
 * Some users want to opt out of using HTTPS after they have logged in, by setting a user preference
 * User from China and Iran should not be required to use HTTPS for login
 * For users of Wikipedia Zero, many ISPs will not zero-rate encrypted traffic, so users should not be redirected to HTTPS

Additionally, in the future:
 * Some projects only want to use HTTPS
 * We would like the option to force users with privileged accounts to use HTTPS for their logged in session

Problem
The http vs https handling code was added into MediaWiki at a time when using http to login was common, and using https was considered the exception. The code is fairly brittle (71716, etc.), and not always consistent between core and CentralAuth. It's also difficult to know what the expected behavior is in the interactions between:


 * The site enforcing $wgSecureLogin, and for CentralAuth, if the central login wiki is configured different from the local wiki
 * The user option opting into using a secure connection while logged in
 * The IP-based blacklist to prevent redirecting users to HTTPS
 * The hook to override redirecting to a secure connection when the 'forceHTTPS' cookie is set, used by Zero
 * Whether the user clicked the login link from an HTTP or HTTPS page

Additionally, MediaWiki has no way to specify that a privileged user (local administrator, CheckUser, etc.) must use a secure connection, and potentially login using an insecure session.

Proposal
Make the use of HTTP or HTTPS governed by a set of site, user, and ip-based policies, and allow the user to set their own preferences when allowed by the policy.

The policies should try to cover nearly every case that site administrators want to enforce, however the policy mechanism should be extensible by extensions that want to make different decisions or decisions based on other factors (e.g., the use of two-factor authentication for login).

The decisions to use HTTP versus HTTPS, setting cookies with the 'secure' flag, and setting the 'forceHTTPS' cookie would be governed by the following, in this order: These policies would specify whether https (or 'secure' flag for cookies) is required for the following situations: For example, when an anonymous user is rendering the login link on a page (determining HTTP versus HTTPS), MediaWiki will first check the site policy to see if using a secure login page is enforced. It will next check if there any IP-based policies based on the incoming IP address. Since the user is anonymous, no user-based policies will apply. If an anonymous user preference is implemented to adjust HTTP versus HTTPS login pages, then that preference would be consulted last. During this process, each policy is able to indicate that it's decision is final, and further policies will not be consulted about the decision.
 * 1) Site policy
 * 2) IP-based policy
 * 3) User policy
 * 4) User preference, if allowed by the other policies.
 * User login page
 * Logged in sessions
 * Session cookies (session, user, and optionally the token cookies)
 * Whether to send the forceHTTPS cookie

Defining the security policy will be done with arrays, to keep it simple and similar to other authn/z configurations. Something like

Code to make the decision when to use HTTPS, or set secure cookies, would do something like:

MediaWiki would setup the policies with something like:

Additional functionality
Eventually, the security policy model can be used for other security requirements (passwords, 2fa, etc), so the policy and config should be extensible both in core and extensions.

Extensions determine policy updates based on the requested page
Allow extensions to set policy based on the page title. For example, the OAuth extension needs to require that a user is using a secure connection when an app owner generates and is shown a shared secret with MediaWiki (this is required by the OAuth specification). It would be nice for OAuth to add this requirement via a small hook, instead of implementing the entire redirect when the user accesses the form.

Questions for the RFC

 * Is the policy config expressive enough, or should we use something else?
 * In the policy config, should we define a callback that enforces the policy? So then code can just call something like $policy->connection->enforce, and the connection policies have a callback that handles the redirect, if the user doesn't comply with the policy.