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 |