| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 // | |
| 5 // AuthWatcher watches authentication events and user open and close | |
| 6 // events and accordingly opens and closes shares. | |
| 7 | |
| 8 #ifndef CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_ | |
| 9 #define CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_ | |
| 10 #pragma once | |
| 11 | |
| 12 #include <string> | |
| 13 | |
| 14 #include "base/gtest_prod_util.h" | |
| 15 #include "base/message_loop_proxy.h" | |
| 16 #include "base/ref_counted.h" | |
| 17 #include "base/scoped_ptr.h" | |
| 18 #include "base/thread.h" | |
| 19 #include "chrome/browser/sync/protocol/service_constants.h" | |
| 20 #include "chrome/common/deprecated/event_sys.h" | |
| 21 #include "chrome/common/net/gaia/gaia_authenticator.h" | |
| 22 | |
| 23 namespace syncable { | |
| 24 struct DirectoryManagerEvent; | |
| 25 class DirectoryManager; | |
| 26 } | |
| 27 | |
| 28 namespace browser_sync { | |
| 29 | |
| 30 class AuthWatcher; | |
| 31 class ServerConnectionManager; | |
| 32 class URLFactory; | |
| 33 class UserSettings; | |
| 34 struct ServerConnectionEvent; | |
| 35 | |
| 36 struct AuthWatcherEvent { | |
| 37 enum WhatHappened { | |
| 38 AUTHENTICATION_ATTEMPT_START, | |
| 39 AUTHWATCHER_DESTROYED, | |
| 40 AUTH_RENEWED, // Currently only used in testing. | |
| 41 AUTH_SUCCEEDED, | |
| 42 GAIA_AUTH_FAILED, | |
| 43 SERVICE_USER_NOT_SIGNED_UP, | |
| 44 SERVICE_AUTH_FAILED, | |
| 45 SERVICE_CONNECTION_FAILED, | |
| 46 // Used in a safety check in AuthWatcher::AuthenticateWithToken() | |
| 47 ILLEGAL_VALUE, | |
| 48 }; | |
| 49 WhatHappened what_happened; | |
| 50 const gaia::GaiaAuthenticator::AuthResults* auth_results; | |
| 51 // use AuthWatcherEvent as its own traits type in hookups. | |
| 52 typedef AuthWatcherEvent EventType; | |
| 53 static inline bool IsChannelShutdownEvent(const AuthWatcherEvent& event) { | |
| 54 return event.what_happened == AUTHWATCHER_DESTROYED; | |
| 55 } | |
| 56 | |
| 57 // Used for AUTH_SUCCEEDED/AUTH_RENEWED notification. | |
| 58 std::string user_email; | |
| 59 // May be empty if we're only locally authenticated. | |
| 60 std::string auth_token; | |
| 61 | |
| 62 // How was this auth attempt initiated? | |
| 63 enum AuthenticationTrigger { | |
| 64 USER_INITIATED = 0, // default value. | |
| 65 EXPIRED_CREDENTIALS, | |
| 66 }; | |
| 67 | |
| 68 AuthenticationTrigger trigger; | |
| 69 }; | |
| 70 | |
| 71 // The mother-class of Authentication for the sync backend. Handles both gaia | |
| 72 // and sync service authentication via asynchronous Authenticate* methods, | |
| 73 // raising AuthWatcherEvents on success/failure. The implementation currently | |
| 74 // runs its own backend thread for the actual auth processing, which means | |
| 75 // the AuthWatcherEvents can be raised on a different thread than the one that | |
| 76 // invoked authentication. | |
| 77 class AuthWatcher : public base::RefCountedThreadSafe<AuthWatcher> { | |
| 78 friend class AuthWatcherTest; | |
| 79 FRIEND_TEST_ALL_PREFIXES(AuthWatcherTest, Construction); | |
| 80 public: | |
| 81 // Normal progression is local -> gaia -> token. | |
| 82 enum Status { LOCALLY_AUTHENTICATED, GAIA_AUTHENTICATED, NOT_AUTHENTICATED }; | |
| 83 typedef syncable::DirectoryManagerEvent DirectoryManagerEvent; | |
| 84 typedef syncable::DirectoryManager DirectoryManager; | |
| 85 | |
| 86 AuthWatcher(DirectoryManager* dirman, | |
| 87 ServerConnectionManager* scm, | |
| 88 const std::string& user_agent, | |
| 89 const std::string& service_id, | |
| 90 const std::string& gaia_url, | |
| 91 UserSettings* user_settings, | |
| 92 gaia::GaiaAuthenticator* gaia_auth); | |
| 93 ~AuthWatcher(); | |
| 94 | |
| 95 typedef EventChannel<AuthWatcherEvent, Lock> Channel; | |
| 96 | |
| 97 inline Channel* channel() const { | |
| 98 return channel_.get(); | |
| 99 } | |
| 100 | |
| 101 // The following 3 flavors of authentication routines are asynchronous and can | |
| 102 // be called from any thread. | |
| 103 // If |captcha_value| is specified but |captcha_token| is not, this will | |
| 104 // attempt authentication using the last observed captcha token out of | |
| 105 // convenience in the common case so the token doesn't have to be plumbed | |
| 106 // everywhere. | |
| 107 void Authenticate(const std::string& email, const std::string& password, | |
| 108 const std::string& captcha_token, const std::string& captcha_value); | |
| 109 | |
| 110 void Authenticate(const std::string& email, const std::string& password, | |
| 111 bool persist_creds_to_disk) { | |
| 112 Authenticate(email, password, "", ""); | |
| 113 } | |
| 114 | |
| 115 // Use this to update only the token of the current email address. | |
| 116 void RenewAuthToken(const std::string& updated_token); | |
| 117 | |
| 118 // Use this version when you don't need the gaia authentication step because | |
| 119 // you already have a valid LSID cookie for |gaia_email|. | |
| 120 void AuthenticateWithLsid(const std::string& lsid); | |
| 121 | |
| 122 // Use this version when you don't need the gaia authentication step because | |
| 123 // you already have a valid token for |gaia_email|. | |
| 124 void AuthenticateWithToken(const std::string& gaia_email, | |
| 125 const std::string& auth_token); | |
| 126 | |
| 127 // Joins on the backend thread. The AuthWatcher is useless after this and | |
| 128 // should be destroyed. | |
| 129 void Shutdown() { auth_backend_thread_.Stop(); } | |
| 130 | |
| 131 std::string email() const; | |
| 132 syncable::DirectoryManager* dirman() const { return dirman_; } | |
| 133 ServerConnectionManager* scm() const { return scm_; } | |
| 134 UserSettings* settings() const { return user_settings_; } | |
| 135 Status status() const { return (Status)status_; } | |
| 136 | |
| 137 private: | |
| 138 void ClearAuthenticationData(); | |
| 139 | |
| 140 void NotifyAuthChanged(const std::string& email, | |
| 141 const std::string& auth_token, | |
| 142 bool renewed); | |
| 143 void HandleServerConnectionEvent(const ServerConnectionEvent& event); | |
| 144 | |
| 145 void SaveUserSettings(const std::string& username, | |
| 146 const std::string& auth_token); | |
| 147 | |
| 148 MessageLoop* message_loop() { return auth_backend_thread_.message_loop(); } | |
| 149 | |
| 150 base::MessageLoopProxy* message_loop_proxy() { | |
| 151 return loop_proxy_; | |
| 152 } | |
| 153 | |
| 154 void DoRenewAuthToken(const std::string& updated_token); | |
| 155 | |
| 156 // These two helpers should only be called from the auth function. | |
| 157 // Called when authentication with gaia succeeds, to save credential info. | |
| 158 void PersistCredentials(); | |
| 159 // Called when authentication with gaia fails. | |
| 160 void ProcessGaiaAuthFailure(); | |
| 161 | |
| 162 // Just checks that the user has at least one local share cache. | |
| 163 bool AuthenticateLocally(std::string email); | |
| 164 // Also checks the user's password against stored password hash. | |
| 165 bool AuthenticateLocally(std::string email, const std::string& password); | |
| 166 | |
| 167 // Sets the trigger member of the event and sends the event on channel_. | |
| 168 void NotifyListeners(AuthWatcherEvent* event); | |
| 169 | |
| 170 inline std::string FormatAsEmailAddress(const std::string& email) const { | |
| 171 std::string mail(email); | |
| 172 if (email.find('@') == std::string::npos) { | |
| 173 mail.push_back('@'); | |
| 174 // TODO(chron): Should this be done only at the UI level? | |
| 175 mail.append(DEFAULT_SIGNIN_DOMAIN); | |
| 176 } | |
| 177 return mail; | |
| 178 } | |
| 179 | |
| 180 // A struct to marshal various data across to the auth_backend_thread_ on | |
| 181 // Authenticate() and AuthenticateWithToken calls. | |
| 182 struct AuthRequest { | |
| 183 std::string email; | |
| 184 std::string password; | |
| 185 std::string auth_token; | |
| 186 std::string captcha_token; | |
| 187 std::string captcha_value; | |
| 188 bool persist_creds_to_disk; | |
| 189 AuthWatcherEvent::AuthenticationTrigger trigger; | |
| 190 }; | |
| 191 | |
| 192 // The public interface Authenticate methods are proxies to these, which | |
| 193 // can only be called from |auth_backend_thread_|. | |
| 194 void DoAuthenticate(const AuthRequest& request); | |
| 195 void DoAuthenticateWithLsid(const std::string& lsid); | |
| 196 void DoAuthenticateWithToken(const std::string& email, | |
| 197 const std::string& auth_token); | |
| 198 | |
| 199 // The public HandleServerConnectionEvent method proxies to this method, which | |
| 200 // can only be called on |auth_backend_thread_|. | |
| 201 void DoHandleServerConnectionEvent( | |
| 202 const ServerConnectionEvent& event, | |
| 203 const std::string& auth_token_snapshot); | |
| 204 | |
| 205 scoped_ptr<gaia::GaiaAuthenticator> const gaia_; | |
| 206 syncable::DirectoryManager* const dirman_; | |
| 207 ServerConnectionManager* const scm_; | |
| 208 scoped_ptr<EventListenerHookup> connmgr_hookup_; | |
| 209 Status status_; | |
| 210 UserSettings* const user_settings_; | |
| 211 scoped_ptr<Channel> channel_; | |
| 212 | |
| 213 base::Thread auth_backend_thread_; | |
| 214 scoped_refptr<base::MessageLoopProxy> loop_proxy_; | |
| 215 | |
| 216 AuthWatcherEvent::AuthenticationTrigger current_attempt_trigger_; | |
| 217 DISALLOW_COPY_AND_ASSIGN(AuthWatcher); | |
| 218 }; | |
| 219 | |
| 220 } // namespace browser_sync | |
| 221 | |
| 222 #endif // CHROME_BROWSER_SYNC_ENGINE_AUTH_WATCHER_H_ | |
| OLD | NEW |