C++程序  |  298行  |  12.28 KB

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// The signin manager encapsulates some functionality tracking
// which user is signed in. See SigninManagerBase for full description of
// responsibilities. The class defined in this file provides functionality
// required by all platforms except Chrome OS.
//
// When a user is signed in, a ClientLogin request is run on their behalf.
// Auth tokens are fetched from Google and the results are stored in the
// TokenService.
// TODO(tim): Bug 92948, 226464. ClientLogin is all but gone from use.

#ifndef CHROME_BROWSER_SIGNIN_SIGNIN_MANAGER_H_
#define CHROME_BROWSER_SIGNIN_SIGNIN_MANAGER_H_

#if defined(OS_CHROMEOS)
// On Chrome OS, SigninManagerBase is all that exists.
#include "chrome/browser/signin/signin_manager_base.h"

#else

#include <string>

#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/prefs/pref_change_registrar.h"
#include "base/prefs/pref_member.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_internals_util.h"
#include "chrome/browser/signin/signin_manager_base.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "net/cookies/canonical_cookie.h"

class CookieSettings;
class GaiaAuthFetcher;
class ProfileIOData;
class PrefService;
class SigninAccountIdHelper;
class SigninGlobalError;
class SigninManagerDelegate;

class SigninManager : public SigninManagerBase,
                      public GaiaAuthConsumer,
                      public content::NotificationObserver {
 public:
  // The callback invoked once the OAuth token has been fetched during signin,
  // but before the profile transitions to the "signed-in" state. This allows
  // callers to load policy and prompt the user appropriately before completing
  // signin. The callback is passed the just-fetched OAuth login refresh token.
  typedef base::Callback<void(const std::string&)> OAuthTokenFetchedCallback;

  // Returns true if |url| is a web signin URL and should be hosted in an
  // isolated, privileged signin process.
  static bool IsWebBasedSigninFlowURL(const GURL& url);

  // This is used to distinguish URLs belonging to the special web signin flow
  // running in the special signin process from other URLs on the same domain.
  // We do not grant WebUI privilieges / bindings to this process or to URLs of
  // this scheme; enforcement of privileges is handled separately by
  // OneClickSigninHelper.
  static const char* kChromeSigninEffectiveSite;

  explicit SigninManager(scoped_ptr<SigninManagerDelegate> delegate);
  virtual ~SigninManager();

  // Returns true if the username is allowed based on the policy string.
  static bool IsUsernameAllowedByPolicy(const std::string& username,
                                        const std::string& policy);

  // Attempt to sign in this user with existing credentials from the cookie jar.
  // |session_index| indicates which user account to use if the cookie jar
  // contains a multi-login session. Otherwise the end result of this call is
  // the same as StartSignIn().
  // If non-null, the passed |signin_complete| callback is invoked once signin
  // has been completed and the oauth login token has been generated - the
  // callback will not be invoked if no token is generated (either because of
  // a failed signin or because web-based signin is not enabled).
  // The callback should invoke SignOut() or CompletePendingSignin() to either
  // continue or cancel the in-process signin.
  virtual void StartSignInWithCredentials(
      const std::string& session_index,
      const std::string& username,
      const std::string& password,
      const OAuthTokenFetchedCallback& oauth_fetched_callback);

  // Attempt to sign in this user with the given oauth code. The cookie jar
  // may not be set up properly for the same user, thus will call the
  // mergeSession endpoint to populate the cookie jar.
  virtual void StartSignInWithOAuthCode(
      const std::string& username,
      const std::string& password,
      const std::string& oauth_code,
      const OAuthTokenFetchedCallback& callback);

  // Copies auth credentials from one SigninManager to this one. This is used
  // when creating a new profile during the signin process to transfer the
  // in-progress credentials to the new profile.
  virtual void CopyCredentialsFrom(const SigninManager& source);

  // Sign a user out, removing the preference, erasing all keys
  // associated with the user, and canceling all auth in progress.
  virtual void SignOut();

  // On platforms where SigninManager is responsible for dealing with
  // invalid username policy updates, we need to check this during
  // initialization and sign the user out.
  virtual void Initialize(Profile* profile, PrefService* local_state) OVERRIDE;
  virtual void Shutdown() OVERRIDE;

  // Invoked from an OAuthTokenFetchedCallback to complete user signin.
  virtual void CompletePendingSignin();

  // Invoked from SigninManagerAndroid to indicate that the sign-in process
  // has completed for |username|.
  void OnExternalSigninCompleted(const std::string& username);

  // Returns true if there's a signin in progress.
  virtual bool AuthInProgress() const OVERRIDE;

  virtual bool IsSigninAllowed() const OVERRIDE;

  // Returns true if the passed username is allowed by policy. Virtual for
  // mocking in tests.
  virtual bool IsAllowedUsername(const std::string& username) const;

  // If an authentication is in progress, return the username being
  // authenticated. Returns an empty string if no auth is in progress.
  const std::string& GetUsernameForAuthInProgress() const;

  // Handles errors if a required user info key is not returned from the
  // GetUserInfo call.
  void OnGetUserInfoKeyNotFound(const std::string& key);

  // Set the profile preference to turn off one-click sign-in so that it won't
  // ever show it again in this profile (even if the user tries a new account).
  static void DisableOneClickSignIn(Profile* profile);

  // GaiaAuthConsumer
  virtual void OnClientLoginSuccess(const ClientLoginResult& result) OVERRIDE;
  virtual void OnClientLoginFailure(
      const GoogleServiceAuthError& error) OVERRIDE;
  virtual void OnClientOAuthSuccess(const ClientOAuthResult& result) OVERRIDE;
  virtual void OnClientOAuthFailure(
      const GoogleServiceAuthError& error) OVERRIDE;
  virtual void OnGetUserInfoSuccess(const UserInfoMap& data) OVERRIDE;
  virtual void OnGetUserInfoFailure(
      const GoogleServiceAuthError& error) OVERRIDE;

  // content::NotificationObserver
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

  // Tells the SigninManager whether to prohibit signout for this profile.
  // If |prohibit_signout| is true, then signout will be prohibited.
  void ProhibitSignout(bool prohibit_signout);

  // If true, signout is prohibited for this profile (calls to SignOut() are
  // ignored).
  bool IsSignoutProhibited() const;

  // Checks if signin is allowed for the profile that owns |io_data|. This must
  // be invoked on the IO thread, and can be used to check if signin is enabled
  // on that thread.
  static bool IsSigninAllowedOnIOThread(ProfileIOData* io_data);

  // Allows the SigninManager to track the privileged signin process
  // identified by |process_id| so that we can later ask (via IsSigninProcess)
  // if it is safe to sign the user in from the current context (see
  // OneClickSigninHelper).  All of this tracking state is reset once the
  // renderer process terminates.
  void SetSigninProcess(int process_id);
  void ClearSigninProcess();
  bool IsSigninProcess(int process_id) const;
  bool HasSigninProcess() const;

 protected:
  // Flag saying whether signing out is allowed.
  bool prohibit_signout_;

 private:
  enum SigninType {
    SIGNIN_TYPE_NONE,
    SIGNIN_TYPE_WITH_CREDENTIALS,
    SIGNIN_TYPE_WITH_OAUTH_CODE
  };

  std::string SigninTypeToString(SigninType type);
  friend class FakeSigninManager;
  FRIEND_TEST_ALL_PREFIXES(SigninManagerTest, ClearTransientSigninData);
  FRIEND_TEST_ALL_PREFIXES(SigninManagerTest, ProvideSecondFactorSuccess);
  FRIEND_TEST_ALL_PREFIXES(SigninManagerTest, ProvideSecondFactorFailure);

  // If user was signed in, load tokens from DB if available.
  void InitTokenService();

  // Called to setup the transient signin data during one of the
  // StartSigninXXX methods.  |type| indicates which of the methods is being
  // used to perform the signin while |username| and |password| identify the
  // account to be signed in. Returns false and generates an auth error if the
  // passed |username| is not allowed by policy.
  bool PrepareForSignin(SigninType type,
                        const std::string& username,
                        const std::string& password);

  // Called to verify GAIA cookies asynchronously before starting auto sign-in
  // without password.
  void VerifyGaiaCookiesBeforeSignIn(const std::string& session_index);

  // Called when GAIA cookies are fetched. If LSID cookie is valid, then start
  // auto sign-in by exchanging cookies for an oauth code.
  void OnGaiaCookiesFetched(
      const std::string session_index, const net::CookieList& cookie_list);

  // Persists |username| as the currently signed-in account, and triggers
  // a sign-in success notification.
  void OnSignedIn(const std::string& username);

  // Called when a new request to re-authenticate a user is in progress.
  // Will clear in memory data but leaves the db as such so when the browser
  // restarts we can use the old token(which might throw a password error).
  void ClearTransientSigninData();

  // Called to handle an error from a GAIA auth fetch.  Sets the last error
  // to |error|, sends out a notification of login failure, and clears the
  // transient signin data if |clear_transient_data| is true.
  void HandleAuthError(const GoogleServiceAuthError& error,
                       bool clear_transient_data);

  void OnSigninAllowedPrefChanged();
  void OnGoogleServicesUsernamePatternChanged();

  // ClientLogin identity.
  std::string possibly_invalid_username_;
  std::string password_;  // This is kept empty whenever possible.
  bool had_two_factor_error_;

  // Result of the last client login, kept pending the lookup of the
  // canonical email.
  ClientLoginResult last_result_;

  // Actual client login handler.
  scoped_ptr<GaiaAuthFetcher> client_login_;

  // Registrar for notifications from the TokenService.
  content::NotificationRegistrar registrar_;

  // OAuth revocation fetcher for sign outs.
  scoped_ptr<GaiaAuthFetcher> revoke_token_fetcher_;

  // Fetcher for the obfuscated user id.
  scoped_ptr<SigninAccountIdHelper> account_id_helper_;

  // The type of sign being performed.  This value is valid only between a call
  // to one of the StartSigninXXX methods and when the sign in is either
  // successful or not.
  SigninType type_;

  // Temporarily saves the oauth2 refresh and access tokens when signing in
  // with credentials.  These will be passed to TokenService so that it does
  // not need to mint new ones.
  ClientOAuthResult temp_oauth_login_tokens_;

  base::WeakPtrFactory<SigninManager> weak_pointer_factory_;

  // See SetSigninProcess.  Tracks the currently active signin process
  // by ID, if there is one.
  int signin_process_id_;

  // Callback invoked during signin after an OAuth token has been fetched
  // but before signin is complete.
  OAuthTokenFetchedCallback oauth_token_fetched_callback_;

  scoped_ptr<SigninManagerDelegate> delegate_;

  // Helper object to listen for changes to signin preferences stored in non-
  // profile-specific local prefs (like kGoogleServicesUsernamePattern).
  PrefChangeRegistrar local_state_pref_registrar_;

  // Helper object to listen for changes to the signin allowed preference.
  BooleanPrefMember signin_allowed_;

  DISALLOW_COPY_AND_ASSIGN(SigninManager);
};

#endif  // !defined(OS_CHROMEOS)

#endif  // CHROME_BROWSER_SIGNIN_SIGNIN_MANAGER_H_