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

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: Fixed commentary 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/sync/profile_sync_service.h"
15 #include "chrome/browser/sync/profile_sync_service_factory.h"
16 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
17 #include "chrome/browser/tab_contents/tab_util.h"
18 #include "chrome/browser/ui/one_click_signin_dialog.h"
19 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/common/url_constants.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/page_navigator.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/common/frame_navigate_params.h"
26 #include "grit/chromium_strings.h"
27 #include "grit/generated_resources.h"
28 #include "grit/theme_resources_standard.h"
29 #include "net/base/cookie_monster.h"
30 #include "net/http/http_response_headers.h"
31 #include "net/url_request/url_request.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/base/resource/resource_bundle.h"
34
35 namespace {
36 // Enum values used for UMA histograms.
37 enum {
38 // The infobar was shown to the user.
39 HISTOGRAM_SHOWN,
40
41 // The user pressed the accept button to perform the suggested action.
42 HISTOGRAM_ACCEPTED,
43
44 // The user pressed the reject to turn off the feature.
45 HISTOGRAM_REJECTED,
46
47 // The user pressed the X button to dismiss the infobar this time.
48 HISTOGRAM_DISMISSED,
49
50 // The user completely ignored the infoar. Either they navigated away, or
51 // they used the page as is.
52 HISTOGRAM_IGNORED,
53
54 // The user clicked on the learn more link in the infobar.
55 HISTOGRAM_LEARN_MORE,
56
57 HISTOGRAM_MAX
58 };
59
60 // The infobar asking the user if they want to use one-click sign in.
61 class OneClickLoginInfoBarDelegate : public ConfirmInfoBarDelegate {
62 public:
63 OneClickLoginInfoBarDelegate(InfoBarTabHelper* owner,
64 const std::string& email,
65 const std::string& password);
66 virtual ~OneClickLoginInfoBarDelegate();
67
68 private:
69 // ConfirmInfoBarDelegate overrides.
70 virtual void InfoBarDismissed() OVERRIDE;
71 virtual gfx::Image* GetIcon() const OVERRIDE;
72 virtual Type GetInfoBarType() const OVERRIDE;
73 virtual string16 GetMessageText() const OVERRIDE;
74 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
75 virtual bool Accept() OVERRIDE;
76 virtual bool Cancel() OVERRIDE;
77
78 void RecordHistogramAction(int action);
79
80 Profile* profile_;
81
82 // Email address and password of the account that has just logged in.
83 std::string email_;
84 std::string password_;
85
86 // Whether any UI controls in the infobar were pressed or not.
87 bool button_pressed_;
88
89 DISALLOW_COPY_AND_ASSIGN(OneClickLoginInfoBarDelegate);
90 };
91
92 OneClickLoginInfoBarDelegate::OneClickLoginInfoBarDelegate(
93 InfoBarTabHelper* owner,
94 const std::string& email,
95 const std::string& password)
96 : ConfirmInfoBarDelegate(owner),
97 profile_(Profile::FromBrowserContext(
98 owner->web_contents()->GetBrowserContext())),
99 email_(email),
100 password_(password),
101 button_pressed_(false) {
102 DCHECK(profile_);
103 RecordHistogramAction(HISTOGRAM_SHOWN);
104 }
105
106 OneClickLoginInfoBarDelegate::~OneClickLoginInfoBarDelegate() {
107 if (!button_pressed_)
108 RecordHistogramAction(HISTOGRAM_IGNORED);
109 }
110
111 void OneClickLoginInfoBarDelegate::InfoBarDismissed() {
112 RecordHistogramAction(HISTOGRAM_DISMISSED);
113 button_pressed_ = true;
114 }
115
116 gfx::Image* OneClickLoginInfoBarDelegate::GetIcon() const {
117 return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
118 IDR_INFOBAR_AUTOLOGIN);
119 }
120
121 InfoBarDelegate::Type OneClickLoginInfoBarDelegate::GetInfoBarType() const {
122 return PAGE_ACTION_TYPE;
123 }
124
125 string16 OneClickLoginInfoBarDelegate::GetMessageText() const {
126 return l10n_util::GetStringFUTF16(
127 IDS_ONE_CLICK_SIGNIN_INFOBAR_MESSAGE,
128 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
129 }
130
131 string16 OneClickLoginInfoBarDelegate::GetButtonLabel(
132 InfoBarButton button) const {
133 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
134 IDS_OK : IDS_ONE_CLICK_SIGNIN_INFOBAR_CANCEL_BUTTON);
135 }
136
137 bool OneClickLoginInfoBarDelegate::Accept() {
138 RecordHistogramAction(HISTOGRAM_ACCEPTED);
139 ShowOneClickSigninDialog(profile_, email_, password_);
140 button_pressed_ = true;
141 return true;
142 }
143
144 bool OneClickLoginInfoBarDelegate::Cancel() {
145 PrefService* pref_service =
146 TabContentsWrapper::GetCurrentWrapperForContents(
147 owner()->web_contents())->profile()->GetPrefs();
148 pref_service->SetBoolean(prefs::kReverseAutologinEnabled, false);
149 RecordHistogramAction(HISTOGRAM_REJECTED);
150 button_pressed_ = true;
151 return true;
152 }
153
154 void OneClickLoginInfoBarDelegate::RecordHistogramAction(int action) {
155 UMA_HISTOGRAM_ENUMERATION("AutoLogin.Reverse", action, HISTOGRAM_MAX);
156 }
157
158 } // namespace
159
160 // static
161 bool OneClickSigninManager::CanOffer(content::WebContents* web_contents) {
162 return !web_contents->GetBrowserContext()->IsOffTheRecord();
163 }
164
165 // static
166 void OneClickSigninManager::ShowInfoBarIfPossible(net::URLRequest* request,
167 int child_id,
168 int route_id) {
169 // See if the response contains the X-Google-Accounts-SignIn header.
170 std::string value;
171 request->GetResponseHeaderByName("X-Google-Accounts-SignIn", &value);
172 if (value.empty())
173 return;
174
175 std::vector<std::pair<std::string, std::string> > pairs;
176 if (!base::SplitStringIntoKeyValuePairs(value, '=', ',', &pairs))
177 return;
178
179 // Parse the information from the value string.
180 std::string email;
181 for (size_t i = 0; i < pairs.size(); ++i) {
182 const std::pair<std::string, std::string>& pair = pairs[i];
183 if (pair.first == "email")
184 TrimString(pair.second, "\"", &email);
185 }
186
187 if (email.empty())
188 return;
189
190 content::BrowserThread::PostTask(
191 content::BrowserThread::UI, FROM_HERE,
192 base::Bind(&OneClickSigninManager::ShowInfoBarUIThread, email,
193 child_id, route_id));
194 }
195
196 OneClickSigninManager::OneClickSigninManager(content::WebContents* web_contents)
197 : content::WebContentsObserver(web_contents) {
198 }
199
200 OneClickSigninManager::~OneClickSigninManager() {
201 }
202
203 // static
204 void OneClickSigninManager::ShowInfoBarUIThread(
205 const std::string& email,
206 int child_id,
207 int route_id) {
208 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
209
210 content::WebContents* web_contents = tab_util::GetWebContentsByID(child_id,
211 route_id);
212 if (!web_contents)
213 return;
214
215 Profile* profile =
216 Profile::FromBrowserContext(web_contents->GetBrowserContext());
217
218 if (!ProfileSyncServiceFactory::HasProfileSyncService(profile))
Andrew T Wilson (Slow) 2012/02/24 22:51:35 I'm not certain this is the right check, btw - if
Roger Tawa OOO till Jul 10th 2012/03/01 04:55:17 Done.
219 return;
220
221 ProfileSyncService* service =
222 ProfileSyncServiceFactory::GetForProfile(profile);
223
224 if (!profile->GetPrefs()->GetBoolean(prefs::kReverseAutologinEnabled) ||
225 service->AreCredentialsAvailable(true))
Andrew T Wilson (Slow) 2012/02/24 22:51:35 I'd get rid of the |true| param here, as I don't t
Roger Tawa OOO till Jul 10th 2012/03/01 04:55:17 Done.
226 return;
227
228 TabContentsWrapper* wrapper =
229 TabContentsWrapper::GetCurrentWrapperForContents(web_contents);
230 if (!wrapper)
231 return;
232
233 // Save the email in the one-click signin manager. The manager may
234 // not exist if the contents is incognito or if the profile is already
235 // connected to a Google account.
236 OneClickSigninManager* manager = wrapper->one_click_signin_manager();
237 if (manager)
238 manager->SaveEmail(email);
239 }
240
241 void OneClickSigninManager::DidNavigateAnyFrame(
242 const content::LoadCommittedDetails& details,
243 const content::FrameNavigateParams& params) {
244 if (params.password_form.origin.is_valid())
245 SavePassword(params.password_form);
246 }
247
248 void OneClickSigninManager::DidStopLoading() {
249 if (email_.empty() || password_.empty())
250 return;
251
252 TabContentsWrapper* wrapper =
253 TabContentsWrapper::GetCurrentWrapperForContents(web_contents());
254
255 wrapper->infobar_tab_helper()->AddInfoBar(
256 new OneClickLoginInfoBarDelegate(wrapper->infobar_tab_helper(),
257 email_, password_));
258
259 email_.clear();
260 password_.clear();
261 }
262
263 void OneClickSigninManager::SaveEmail(const std::string& email) {
264 // TODO(rogerta): validate that the email address is the same as set in
265 // the form?
266 email_ = email;
267 }
268
269 void OneClickSigninManager::SavePassword(
270 const webkit::forms::PasswordForm& form) {
271 // TODO(rogerta): validate that the email address in the form is the same
272 // as set by SaveEmail?
273
274 // TODO(rogerta): in the case of a 2-factor or captcha or some other type of
275 // challenge, its possible for the user to never complete the signin.
276 // Should have a way to detect this and clear the password member.
277
278 // TODO(rogerta): need to make sure this works with multi-login enabled
279 // accounts. In particular, of the user is already longged into one
280 // account, adds a second account to the session and decides to connect
281 // his profile with that one, make sure we use the right account.
282 password_ = UTF16ToUTF8(form.password_value);
283 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698