Manual:SessionManager と AuthManager

This page is a translated version of the page Manual:SessionManager and AuthManager and the translation is 17% complete.

認証関連のフレームワークとしてSessionManager および AuthManager の2件が MediaWiki 1.27 に導入されて(旧来の認証システムである)AuthPlugin につきものの「唯一しか認めない」という姿勢を置き換え、セッション管理はさまざまなフックを再利用せず Cookie 以外で実行できないようにしており、それらを使用し て MediaWiki が重点を置くパスワードベースの認証を回避させるフェデレーション・ログイン(例:「Google アカウントでログイン」)は実行不能であり、また MediaWiki の PHP Cookie に基づいたセッションへの依存を回避不可能にしてあります。

それぞれの役割は?

SessionManager はリクエストを受けた時にそれを特定の利用者セッションと結びかけるかどうかに関与し、例えば ログイン利用者がリクエストしている(またはしていない)かどうか、また PHP に対する $_SESSION のようにリクエスト全体で保持すべきデータかどうかが対象です。 Usually this means cookies holding the "session key" and the user's ID and token, but it could as easily be based on credentials in OAuth headers or a TLS client certificate.

AuthManager is concerned with logging in by supplying credentials to Special:UserLogin or the like, and with creating accounts with new credentials. This includes the usual username and password form, but also includes mechanisms such as logging in via Google, Facebook, or other third-party authentication service; multi-factor authentication; and other login-time checks such as password resets, CAPTCHAs, and so on.

How do I use them?

As a system administrator

The available session providers are configured via $wgSessionProviders . See documentation of that global and of the individual session providers for details.

The available authentication providers are configured via $wgAuthManagerConfig . See documentation of that global and of the individual authentication providers for details.

To handle operations where the user would traditionally be asked to enter their current password for confirmation, AuthManager instead requires that the user have actively logged in recently during the current session. To configure what exactly is meant by "recently", use $wgReauthenticateTime to set time limits for each operation. To determine what happens when the user is using something like OAuth where each request is individually authenticated and "log in" isn't possible, use $wgAllowSecuritySensitiveOperationIfCannotReauthenticate .

As a consumer

Sessions

To access the current session from your code, the most straightforward mechanism is to use the getSession() method on your WebRequest object. The resulting MediaWiki\Session\Session object has methods to access the data that, in the past, you'd have accessed using $webRequest->getSessionData() and ->setSessionData() or by directly accessing $_SESSION.

To test if a session is currently active where you would have previously used code like session_id() !== '', fetch the Session object and use its ->isPersistent() method. To ensure that the session is persistent, fetch it and use its ->persist() method instead of using wfSetupSession().

If you need to access session data in a context other than a client request, e.g. if you saved the session ID to run a background job and need to update status in the session data, use MediaWiki\Session\SessionManager::singleton()->getSessionById().

Authentication

If you're performing a security-sensitive action that would traditionally request the user's password for verification, use MediaWiki\Auth\AuthManager::singleton()->securitySensitiveOperationStatus() to check whether the user has authenticated recently enough, and if necessary direct them through Special:UserLogin to re-authenticate. SpecialPage can handle this for you if you return non-false from SpecialPage::getLoginSecurityLevel().

Other than that, most "consumer" code won't need to interact with AuthManager directly, since you really shouldn't be implementing your own authentication flow. To determine if a user is logged in, use the usual methods such as the getUser() on an IContextSource. To see that a user is authenticated, have them log in via the usual method.

But if you really insist: Authentication in AuthManager is a multi-step process that goes something like this:

  1. Call $authManager->canAuthenticateNow() to determine if authentication is even possible.
  2. Call $authManager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ) to determine which AuthenticationRequest subclasses are needed, convert them to form fields, and present them to the user.
  3. Once the user submits the form, use AuthenticationRequest::loadRequestsFromSubmission() to populate the requests with data and pass them to $authManager->beginAuthentication().
  4. Take action depending on the status of the AuthenticationResponse:
    • For status UI, convert the needed AuthenticationRequests to form fields, present to the user, and on submission use AuthenticationRequest::loadRequestsFromSubmission() to populate the new requests with data and pass them to $authManager->continueAuthentication() and handle the new response.
    • For status REDIRECT, redirect the user to the specified URL. Eventually the user should be redirected back, at which point the needed AuthenticationRequests should be populated with data and passed to $authManager->continueAuthentication().
    • For status PASS, authentication has succeeded.
    • For status RESTART, authentication with a third-party service has succeeded but those credentials aren't associated with a local account. Treat this as either UI or FAIL.
    • For status FAIL, authentication has failed. The response might contain an additional AuthenticationRequest that may be passed into $authManager->beginAuthentication() or $authManager->beginAccountCreation() to preserve state.

The processes for account creation and linking of third-party credentials are similar.

As a provider

If you're writing code that is going to provide new functionality for SessionManager or AuthManager, first you need to decide what kind of thing you're providing:

  • If you're implementing a new way for taking a WebRequest and determining the authenticated user and session data from it, you want to implement MediaWiki\Session\SessionProvider.
    • If you're doing something that seems like logging in, a SessionProvider is not what you want. You probably want a PrimaryAuthenticationProvider instead.
  • If you want to generically add additional checks to the process of getting a Session from a WebRequest, you'll likely want to look at the SessionMetadata and SessionCheckInfo hooks. The first allows adding additional metadata to be saved with the session, while the second allows you to look at the metadata when a Session is being loaded and if necessary veto its use.
  • If you're implementing a new way to log in, you want to implement MediaWiki\Auth\PrimaryAuthenticationProvider.
    • If your thing isn't so much a way to log in as a new way to just "be" logged in such as OAuth or TLS client certificates, you don't want this. You probably want a SessionProvider instead.
  • If you're implementing some new check that someone has to pass before being able to log in, such as a CAPTCHA, you want to implement MediaWiki\Auth\PreAuthenticationProvider.
  • If you're implementing something that should happen after logging in, including testing of a second factor, you want to implement MediaWiki\Auth\SecondaryAuthenticationProvider.

In all cases, providers are constructed using ObjectFactory from $wgSessionProviders or $wgAuthManagerAutoConfig and then have dependencies injected by setter methods.

SessionProvider

クラスの説明文書: MediaWiki\Session\SessionProvider

There are broadly three types of session providers, based on two abilities:

  • The ability to save any randomly-generated session ID, versus the ID being based on properties of the request that cannot be changed.
  • The ability to be associated with any arbitrary user who logs in, versus having a user that is intrinsically associated with the request.
    • This latter property is sometimes referred to as making the session "mutable" versus "immutable".

The resulting three types are:

  • Providers that can save any randomly-generated session ID, and can also be associated with any arbitrary user. A prime example of these are the traditional cookie-based sessions.
    • It's not necessary that the provider actually does anything to save the user's identity; as long as the session ID is provided, the user can be determined from the saved metadata.
  • Providers that have a user and session ID intrinsically associated with the request. Good examples here are OAuth and TLS client certificates: the OAuth headers or TLS client certificate are associated with a particular user and you can't just arbitrarily change them to be associated with a different user.
  • Providers that have a user intrinsically associated with the request, but can save any randomly-generated session ID. An example might be HTTP Digest authentication using the "opaque" field to hold the session ID.
    • You can often take a method with an intrinsic user and no ability to save randomly-generated session IDs and use a cookie to give it that ability; the MediaWiki\Session\ImmutableSessionProviderWithCookie base class implements the cookie portion of such a provider.

It's also possible to have a provider with the ability to be associated with any arbitrary user but lacking the ability to save a randomly-generated session ID. しかしながら意味はないように見えます。

A session provider "provides" sessions by returning a MediaWiki\Session\SessionInfo object from either provideSessionInfo() (for the session associated with a WebRequest) or newSessionInfo() (for a new session not yet associated with any WebRequest). The properties of the SessionInfo are:

  • The priority of the SessionInfo: if by some chance multiple providers find session data in the same request, the one with the highest priority is used. If there is a tie, SessionManager will throw an error. Generally a provider will either always use SessionInfo::MAX_PRIORITY (i.e. "you must use this SessionInfo") or will take the desired priority as a parameter to its constructor.
  • セッション ID。 It's ok for a provider to provide a SessionInfo without providing an ID if it does identify a user.
  • Whether the request identifies a user, and if that user is authenticated or just named. Using cookie-based sessions as an example,
    • "No user" results when the UserID or UserName cookie isn't present in the request. The user will be determined from the saved session metadata.
    • "Unauthenticated user" results when the UserID or UserName cookie is present, but the "Token" cookie is missing. Any user's ID or name is publicly available, so without the token we can't know that this isn't a spoofing attempt.
      • This is still worthwhile, since we can check that the saved session metadata identifies the same user to prevent someone from using a session ID that has expired and been reassigned to a different user.
    • "Authenticated user" results when the UserID or UserName cookie is present and the "Token" cookie is also present, and hash_equals( $user->getToken(), $cookieToken ) returns true. Since the token is supposed to be secret, we can assume that a correct token means this is the known user.
      • Tokens that come in from the WebRequest must always be checked using hash_equals to avoid timing attacks.
    • 利用者の UserID もしくは UserName のクッキーと「Token」クッキーも並存しているのに、hash_equals( $user->getToken(), $cookieToken ) が偽 false と返した事例は1件もありません。 If this happens, the provider must not provide any SessionInfo.
  • Whether various bits were actually found in the WebRequest: the session ID, the user's token, and the forceHTTPS flag.
  • Any additional metadata the provider wants to associate with the session. This is often useful if the provider does authorisation (e.g. OAuth grants) in addition to authentication.

The session provider is also responsible for "persisting" the session to a WebResponse, which is done on a call to persistSession(). If the provider has the ability to save randomly-generated session IDs, it does so here. If it has the ability to independently save the user identity, it should always save the user's ID or name but must only save the user's token if the session's ->shouldRememberUser() method returns true.

For proper caching behavior, the session provider needs to use getVaryHeaders() and getVaryCookies() to indicate which request headers and cookies it uses to determine the SessionInfo. It also needs to provide messages to identify its sessions in error messages, and to provide a hint as to why sessions aren't being persisted when they should be (e.g. that the browser is set to reject cookies).

PreAuthenticationProvider

クラスの説明文書: MediaWiki\Auth\PreAuthenticationProvider, MediaWiki\Auth\AbstractPreAuthenticationProvider

A "pre"-authentication provider can provide fields for the login or account creation form, and perform checks on a login or account creation attempt before any actual authentication happens. For example, it might throttle login attempts by IP address or present a CAPTCHA that must be solved in order to create the account.

PrimaryAuthenticationProvider

クラスの説明文書: MediaWiki\Auth\PrimaryAuthenticationProvider, MediaWiki\Auth\AbstractPrimaryAuthenticationProvider

A "primary" authentication provider is responsible for actual user authentication:

  • Taking input from the login form, determining which user is trying to log in, and actually authenticating that user.
  • 作成した利用者がのちほどログインできるかどうか、確かめること。
  • バックエンドの認証ストレージに利用者名が既存かどうか試験すること。
  • 既存の特定の利用者に関する認証データを変更する、もしくは第三者の認証提供アカウントとの連携を加除すること。

AuthManager may be configured to use multiple primary authentication providers. On the initial form submission each primary provider in turn is tried, and if it returns an ABSTAIN result the next in line is tried until either one returns a non-ABSTAIN response or it runs out of providers (in which case it generates a FAIL).

The authentication process for a provider is also multi-step: non-ABSTAIN responses include the usual PASS and FAIL, but also UI to present an additional input form for the user to fill out and REDIRECT to send the browser to some third party which should eventually redirect back to continue the authentication process.

SecondaryAuthenticationProvider

クラスの説明文書: MediaWiki\Auth\SecondaryAuthenticationProvider, MediaWiki\Auth\AbstractSecondaryAuthenticationProvider

利用者が「第1の」提供者から認証を受けると続けて「第2の」認証提供者に問い合わせる。 For example, it might request a second factor for multi-factor authentication, prompt the user to change their password, or check that the user isn't blocked. Secondary providers are also called on account creation so they can do things such as prompt to set up multi-factor authentication.

AuthManager may be configured with multiple secondary authentication providers, in which case all are run and must PASS or ABSTAIN for the authentication process to succeed. Like primary providers, they may respond with UI and REDIRECT to interact with the user.

認証プロバイダ同士の意思疎通

AuthManager provides support for communication between provider modules during the authentication process.

一例として、パスワードに依拠するプライマリな認証システムのプロバイダは、パスワードの有効期限という概念を採用するなら $this->getManager()->setAuthenticationSessionData( 'reset-pass', $data ) をコールし、それを契機に第2の認証プロバイダ MediaWiki\Auth\ResetPasswordSecondaryAuthenticationProvider から利用者にパスワードを変更するように催促します。 プロバイダの裁量により、どの認証データ「キー」を採用しているか、ジョブ実行に必要なデータは何か、文書化したりしなかったりしています。

関連項目

コードのスチュワード権限