Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: chrome/browser/signin/one_click_signin.cc

Issue 9453035: Implement one click login. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Added support for starting sync process, both automatically and with manual settings Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 #include "chrome/browser/signin/one_click_signin.h"
6
7 #include "base/metrics/histogram.h"
8 #include "base/string_split.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/google/google_util.h"
11 #include "chrome/browser/infobars/infobar_tab_helper.h"
12 #include "chrome/browser/prefs/pref_service.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/signin/signin_manager.h"
15 #include "chrome/browser/signin/signin_manager_factory.h"
16 #include "chrome/browser/sync/profile_sync_service.h"
17 #include "chrome/browser/sync/profile_sync_service_factory.h"
18 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
19 #include "chrome/browser/tab_contents/tab_util.h"
20 #include "chrome/browser/ui/one_click_signin_dialog.h"
21 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
22 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
23 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
24 #include "chrome/common/chrome_notification_types.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/url_constants.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/notification_source.h"
29 #include "content/public/browser/page_navigator.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/common/frame_navigate_params.h"
32 #include "grit/chromium_strings.h"
33 #include "grit/generated_resources.h"
34 #include "grit/theme_resources_standard.h"
35 #include "net/base/cookie_monster.h"
36 #include "net/http/http_response_headers.h"
37 #include "net/url_request/url_request.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/base/resource/resource_bundle.h"
40
41 namespace {
42 // Enum values used for UMA histograms.
43 enum {
44 // The infobar was shown to the user.
45 HISTOGRAM_SHOWN,
46
47 // The user pressed the accept button to perform the suggested action.
48 HISTOGRAM_ACCEPTED,
49
50 // The user pressed the reject to turn off the feature.
51 HISTOGRAM_REJECTED,
52
53 // The user pressed the X button to dismiss the infobar this time.
54 HISTOGRAM_DISMISSED,
55
56 // The user completely ignored the infoar. Either they navigated away, or
57 // they used the page as is.
58 HISTOGRAM_IGNORED,
59
60 // The user clicked on the learn more link in the infobar.
61 HISTOGRAM_LEARN_MORE,
62
63 HISTOGRAM_MAX
64 };
65
66 // The infobar asking the user if they want to use one-click sign in.
67 class OneClickLoginInfoBarDelegate : public ConfirmInfoBarDelegate {
68 public:
69 OneClickLoginInfoBarDelegate(InfoBarTabHelper* owner,
70 const std::string& email,
71 const std::string& password);
72 virtual ~OneClickLoginInfoBarDelegate();
73
74 private:
75 // ConfirmInfoBarDelegate overrides.
76 virtual void InfoBarDismissed() OVERRIDE;
77 virtual gfx::Image* GetIcon() const OVERRIDE;
78 virtual Type GetInfoBarType() const OVERRIDE;
79 virtual string16 GetMessageText() const OVERRIDE;
80 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
81 virtual bool Accept() OVERRIDE;
82 virtual bool Cancel() OVERRIDE;
83
84 void RecordHistogramAction(int action);
85
86 Profile* profile_;
87
88 // Email address and password of the account that has just logged in.
89 std::string email_;
90 std::string password_;
91
92 // Whether any UI controls in the infobar were pressed or not.
93 bool button_pressed_;
94
95 DISALLOW_COPY_AND_ASSIGN(OneClickLoginInfoBarDelegate);
96 };
97
98 OneClickLoginInfoBarDelegate::OneClickLoginInfoBarDelegate(
99 InfoBarTabHelper* owner,
100 const std::string& email,
101 const std::string& password)
102 : ConfirmInfoBarDelegate(owner),
103 profile_(Profile::FromBrowserContext(
104 owner->web_contents()->GetBrowserContext())),
105 email_(email),
106 password_(password),
107 button_pressed_(false) {
108 DCHECK(profile_);
109 RecordHistogramAction(HISTOGRAM_SHOWN);
110 }
111
112 OneClickLoginInfoBarDelegate::~OneClickLoginInfoBarDelegate() {
113 if (!button_pressed_)
114 RecordHistogramAction(HISTOGRAM_IGNORED);
115 }
116
117 void OneClickLoginInfoBarDelegate::InfoBarDismissed() {
118 RecordHistogramAction(HISTOGRAM_DISMISSED);
119 button_pressed_ = true;
120 }
121
122 gfx::Image* OneClickLoginInfoBarDelegate::GetIcon() const {
123 return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
124 IDR_INFOBAR_AUTOLOGIN);
125 }
126
127 InfoBarDelegate::Type OneClickLoginInfoBarDelegate::GetInfoBarType() const {
128 return PAGE_ACTION_TYPE;
129 }
130
131 string16 OneClickLoginInfoBarDelegate::GetMessageText() const {
132 return l10n_util::GetStringFUTF16(
133 IDS_ONE_CLICK_SIGNIN_INFOBAR_MESSAGE,
134 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
135 }
136
137 string16 OneClickLoginInfoBarDelegate::GetButtonLabel(
138 InfoBarButton button) const {
139 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
140 IDS_OK : IDS_ONE_CLICK_SIGNIN_INFOBAR_CANCEL_BUTTON);
141 }
142
143 bool OneClickLoginInfoBarDelegate::Accept() {
144 RecordHistogramAction(HISTOGRAM_ACCEPTED);
145 ShowOneClickSigninDialog(profile_, email_, password_);
146 button_pressed_ = true;
147 return true;
148 }
149
150 bool OneClickLoginInfoBarDelegate::Cancel() {
151 PrefService* pref_service =
152 TabContentsWrapper::GetCurrentWrapperForContents(
153 owner()->web_contents())->profile()->GetPrefs();
154 pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false);
155 RecordHistogramAction(HISTOGRAM_REJECTED);
156 button_pressed_ = true;
157 return true;
158 }
159
160 void OneClickLoginInfoBarDelegate::RecordHistogramAction(int action) {
161 UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action, HISTOGRAM_MAX);
162 }
163
164 } // namespace
165
166 // static
167 bool OneClickSigninManager::CanOffer(content::WebContents* web_contents) {
168 return !web_contents->GetBrowserContext()->IsOffTheRecord();
169 }
170
171 // static
172 void OneClickSigninManager::ShowInfoBarIfPossible(net::URLRequest* request,
173 int child_id,
174 int route_id) {
175 // See if the response contains the X-Google-Accounts-SignIn header.
176 std::string value;
177 request->GetResponseHeaderByName("X-Google-Accounts-SignIn", &value);
178 if (value.empty())
179 return;
180
181 std::vector<std::pair<std::string, std::string> > pairs;
182 if (!base::SplitStringIntoKeyValuePairs(value, '=', ',', &pairs))
183 return;
184
185 // Parse the information from the value string.
186 std::string email;
187 for (size_t i = 0; i < pairs.size(); ++i) {
188 const std::pair<std::string, std::string>& pair = pairs[i];
189 if (pair.first == "email")
190 TrimString(pair.second, "\"", &email);
191 }
192
193 if (email.empty())
194 return;
195
196 content::BrowserThread::PostTask(
197 content::BrowserThread::UI, FROM_HERE,
198 base::Bind(&OneClickSigninManager::ShowInfoBarUIThread, email,
199 child_id, route_id));
200 }
201
202 OneClickSigninManager::OneClickSigninManager(content::WebContents* web_contents)
203 : content::WebContentsObserver(web_contents) {
204 }
205
206 OneClickSigninManager::~OneClickSigninManager() {
207 }
208
209 // static
210 void OneClickSigninManager::ShowInfoBarUIThread(
211 const std::string& email,
212 int child_id,
213 int route_id) {
214 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
215
216 content::WebContents* web_contents = tab_util::GetWebContentsByID(child_id,
217 route_id);
218 if (!web_contents)
219 return;
220
221 Profile* profile =
222 Profile::FromBrowserContext(web_contents->GetBrowserContext());
223
224 if (!ProfileSyncServiceFactory::HasProfileSyncService(profile))
225 return;
226
227 ProfileSyncService* service =
228 ProfileSyncServiceFactory::GetForProfile(profile);
229
230 if (!profile->GetPrefs()->GetBoolean(prefs::kReverseAutologinEnabled) ||
231 service->AreCredentialsAvailable(true))
232 return;
233
234 TabContentsWrapper* wrapper =
235 TabContentsWrapper::GetCurrentWrapperForContents(web_contents);
236 if (!wrapper)
237 return;
238
239 // Save the email in the one-click signin manager. The manager may
240 // not exist if the contents is incognito or if the profile is already
241 // connected to a Google account.
242 OneClickSigninManager* manager = wrapper->one_click_signin_manager();
243 if (manager)
244 manager->SaveEmail(email);
245 }
246
247 void OneClickSigninManager::DidNavigateAnyFrame(
248 const content::LoadCommittedDetails& details,
249 const content::FrameNavigateParams& params) {
250 if (params.password_form.origin.is_valid())
251 SavePassword(params.password_form);
252 }
253
254 void OneClickSigninManager::DidStopLoading() {
255 if (email_.empty() || password_.empty())
256 return;
257
258 TabContentsWrapper* wrapper =
259 TabContentsWrapper::GetCurrentWrapperForContents(web_contents());
260
261 wrapper->infobar_tab_helper()->AddInfoBar(
262 new OneClickLoginInfoBarDelegate(wrapper->infobar_tab_helper(),
263 email_, password_));
264
265 email_.clear();
266 password_.clear();
267 }
268
269 void OneClickSigninManager::SaveEmail(const std::string& email) {
270 // TODO(rogerta): validate that the email address is the same as set in
271 // the form?
272 email_ = email;
273 }
274
275 void OneClickSigninManager::SavePassword(
276 const webkit::forms::PasswordForm& form) {
277 // TODO(rogerta): validate that the email address in the form is the same
278 // as set by SaveEmail?
279
280 // TODO(rogerta): in the case of a 2-factor or captcha or some other type of
281 // challenge, its possible for the user to never complete the signin.
282 // Should have a way to detect this and clear the password member.
283
284 // TODO(rogerta): need to make sure this works with multi-login enabled
285 // accounts. In particular, of the user is already longged into one
286 // account, adds a second account to the session and decides to connect
287 // his profile with that one, make sure we use the right account.
288 password_ = UTF16ToUTF8(form.password_value);
289 }
290
291
292 OneClickSigninSyncStarter::OneClickSigninSyncStarter(
293 const std::string& email,
294 const std::string& password,
295 Profile* profile,
296 bool use_default_settings)
297 : profile_(profile), use_default_settings_(use_default_settings) {
298 DCHECK(profile_);
299
300 // Register for signin manager notifications before starting the process.
301 registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
302 content::Source<Profile>(profile_));
303 registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
304 content::Source<Profile>(profile_));
Andrew T Wilson (Slow) 2012/02/25 00:12:30 Did you want to do something with FAILED?
Roger Tawa OOO till Jul 10th 2012/03/01 04:55:17 The object needs to delete itself in the failed ca
305
306 SigninManager* manager = SigninManagerFactory::GetForProfile(profile_);
307 manager->StartSignInWithCredentials(email, password);
308 }
309
310 OneClickSigninSyncStarter::~OneClickSigninSyncStarter() {
311 }
312
313 void OneClickSigninSyncStarter::Observe(
314 int type,
315 const content::NotificationSource& source,
316 const content::NotificationDetails& details) {
317 if (type == chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL) {
318 ProfileSyncService* service =
319 ProfileSyncServiceFactory::GetForProfile(profile_);
320 service->SetSyncSetupCompleted();
Andrew T Wilson (Slow) 2012/02/25 00:12:30 I think you only want to set this flag if the user
Roger Tawa OOO till Jul 10th 2012/03/01 04:55:17 Doing so means that the user does not go to the se
321
322 if (use_default_settings_) {
323 // Just kick off the sync machine, no need to configure it first.
324 service->UnsuppressAndStart();
325 } else {
326 // Give the user a chance to configure things.
327 LoginUIService* service =
Andrew T Wilson (Slow) 2012/02/25 00:12:30 This declaration is shadowing the declaration of |
Roger Tawa OOO till Jul 10th 2012/03/01 04:55:17 Done.
328 LoginUIServiceFactory::GetForProfile(profile_);
329 service->ShowLoginUI();
Andrew T Wilson (Slow) 2012/02/25 00:12:30 Despite what I said previously, in retrospect I'm
Roger Tawa OOO till Jul 10th 2012/03/01 04:55:17 Done.
330 }
331 }
332
333 delete this;
334 }
OLDNEW
« no previous file with comments | « chrome/browser/signin/one_click_signin.h ('k') | chrome/browser/ui/cocoa/one_click_signin_dialog_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698