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

Side by Side Diff: chrome/browser/ui/login/login_prompt_browsertest.cc

Issue 5814005: Minimize login prompts (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fix race condition on Mac Created 10 years 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
OLDNEW
(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 #include <algorithm>
6 #include <list>
7 #include <map>
8
9 #include "chrome/browser/browser_thread.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/login/login_prompt.h"
12 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
13 #include "chrome/common/notification_service.h"
14 #include "chrome/test/in_process_browser_test.h"
15 #include "chrome/test/ui_test_utils.h"
16 #include "net/base/auth.h"
17
18 namespace {
19
20 class LoginPromptBrowserTest : public InProcessBrowserTest {
21 public:
22 LoginPromptBrowserTest()
23 : bad_password_(L"incorrect"), bad_username_(L"nouser") {
24 set_show_window(true);
25
26 auth_map_[L"foo"] = AuthInfo(L"testuser", L"foopassword");
27 auth_map_[L"bar"] = AuthInfo(L"testuser", L"barpassword");
28 }
29
30 protected:
31 void SetAuthFor(LoginHandler* handler);
32
33 struct AuthInfo {
34 std::wstring username_;
35 std::wstring password_;
36
37 AuthInfo() {}
38
39 AuthInfo(const std::wstring username,
40 const std::wstring password)
41 : username_(username), password_(password) {}
42 };
43
44 std::map<std::wstring, AuthInfo> auth_map_;
45 std::wstring bad_password_;
46 std::wstring bad_username_;
47 };
48
49 void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) {
50 net::AuthChallengeInfo* challenge = handler->auth_info();
51
52 ASSERT_TRUE(challenge);
53 std::map<std::wstring, AuthInfo>::iterator i =
54 auth_map_.find(challenge->realm);
55 EXPECT_TRUE(auth_map_.end() != i);
56 if (i != auth_map_.end()) {
57 const AuthInfo& info = i->second;
58 handler->SetAuth(info.username_, info.password_);
59 }
60 }
61
62 // Maintains a set of LoginHandlers that are currently active and
63 // keeps a count of the notifications that were observed.
64 class LoginPromptBrowserTestObserver : public NotificationObserver {
65 public:
66 LoginPromptBrowserTestObserver()
67 : auth_needed_count_(0),
68 auth_supplied_count_(0),
69 auth_cancelled_count_(0) {}
70
71 virtual void Observe(NotificationType type,
72 const NotificationSource& source,
73 const NotificationDetails& details);
74
75 void AddHandler(LoginHandler* handler);
76
77 void RemoveHandler(LoginHandler* handler);
78
79 void Register(const NotificationSource& source);
80
81 std::list<LoginHandler*> handlers_;
82
83 int auth_needed_count_;
84 int auth_supplied_count_;
85 int auth_cancelled_count_;
86
87 NotificationRegistrar registrar_;
88
89 DISALLOW_COPY_AND_ASSIGN(LoginPromptBrowserTestObserver);
90 };
91
92 void LoginPromptBrowserTestObserver::Observe(
93 NotificationType type,
94 const NotificationSource& source,
95 const NotificationDetails& details) {
96 if (type == NotificationType::AUTH_NEEDED) {
97 LoginNotificationDetails* login_details =
98 Details<LoginNotificationDetails>(details).ptr();
99 AddHandler(login_details->handler());
100 auth_needed_count_++;
101 } else if (type == NotificationType::AUTH_SUPPLIED) {
102 AuthSuppliedLoginNotificationDetails* login_details =
103 Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
104 RemoveHandler(login_details->handler());
105 auth_supplied_count_++;
106 } else if (type == NotificationType::AUTH_CANCELLED) {
107 LoginNotificationDetails* login_details =
108 Details<LoginNotificationDetails>(details).ptr();
109 RemoveHandler(login_details->handler());
110 auth_cancelled_count_++;
111 }
112 }
113
114 void LoginPromptBrowserTestObserver::AddHandler(LoginHandler* handler) {
115 std::list<LoginHandler*>::iterator i = std::find(handlers_.begin(),
116 handlers_.end(),
117 handler);
118 EXPECT_TRUE(i == handlers_.end());
119 if (i == handlers_.end())
120 handlers_.push_back(handler);
121 }
122
123 void LoginPromptBrowserTestObserver::RemoveHandler(LoginHandler* handler) {
124 std::list<LoginHandler*>::iterator i = std::find(handlers_.begin(),
125 handlers_.end(),
126 handler);
127 EXPECT_TRUE(i != handlers_.end());
128 if (i != handlers_.end())
129 handlers_.erase(i);
130 }
131
132 void LoginPromptBrowserTestObserver::Register(
133 const NotificationSource& source) {
134 registrar_.Add(this, NotificationType::AUTH_NEEDED, source);
135 registrar_.Add(this, NotificationType::AUTH_SUPPLIED, source);
136 registrar_.Add(this, NotificationType::AUTH_CANCELLED, source);
137 }
138
139 template <NotificationType::Type T>
140 class WindowedNavigationObserver
141 : public ui_test_utils::WindowedNotificationObserver {
142 public:
143 explicit WindowedNavigationObserver(NavigationController* controller)
144 : ui_test_utils::WindowedNotificationObserver(
145 T, Source<NavigationController>(controller)) {}
146 };
147
148 typedef WindowedNavigationObserver<NotificationType::LOAD_STOP>
149 WindowedLoadStopObserver;
150
151 typedef WindowedNavigationObserver<NotificationType::AUTH_NEEDED>
152 WindowedAuthNeededObserver;
153
154 typedef WindowedNavigationObserver<NotificationType::AUTH_CANCELLED>
155 WindowedAuthCancelledObserver;
156
157 typedef WindowedNavigationObserver<NotificationType::AUTH_SUPPLIED>
158 WindowedAuthSuppliedObserver;
159
160 const char* kMultiRealmTestPage = "files/login/multi_realm.html";
161 const int kMultiRealmTestRealmCount = 2;
162 const int kMultiRealmTestResourceCount = 4;
163
164 const char* kSingleRealmTestPage = "files/login/single_realm.html";
165 const int kSingleRealmTestResourceCount = 6;
166
167 // Test handling of resources that require authentication even though
168 // the page they are included on doesn't. In this case we should only
169 // present the minimal number of prompts necessary for successfully
170 // displaying the page. First we check whether cancelling works as
171 // expected.
172 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmCancellation) {
173 ASSERT_TRUE(test_server()->Start());
174 GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
175
176 TabContentsWrapper* contents =
177 browser()->GetSelectedTabContentsWrapper();
178 ASSERT_TRUE(contents);
179
180 NavigationController* controller = &contents->controller();
181 LoginPromptBrowserTestObserver observer;
182
183 observer.Register(Source<NavigationController>(controller));
184
185 WindowedLoadStopObserver load_stop_waiter(controller);
186
187 {
188 WindowedAuthNeededObserver auth_needed_waiter(controller);
189 browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED);
190 auth_needed_waiter.Wait();
191 }
192
193 int n_handlers = 0;
194
195 while (n_handlers < kMultiRealmTestRealmCount) {
196 WindowedAuthNeededObserver auth_needed_waiter(controller);
197
198 while (!observer.handlers_.empty()) {
199 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
200 LoginHandler* handler = *observer.handlers_.begin();
201
202 ASSERT_TRUE(handler);
203 n_handlers++;
204 handler->CancelAuth();
205 auth_cancelled_waiter.Wait();
206 }
207
208 if (n_handlers < kMultiRealmTestRealmCount)
209 auth_needed_waiter.Wait();
210 }
211
212 load_stop_waiter.Wait();
213
214 EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
215 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_needed_count_);
216 EXPECT_EQ(0, observer.auth_supplied_count_);
217 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_cancelled_count_);
218 }
219
220 // Similar to the MultipleRealmCancellation test above, but tests
221 // whether supplying credentials work as exepcted.
222 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmConfirmation) {
223 ASSERT_TRUE(test_server()->Start());
224 GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
225
226 TabContentsWrapper* contents =
227 browser()->GetSelectedTabContentsWrapper();
228 ASSERT_TRUE(contents);
229
230 NavigationController* controller = &contents->controller();
231 LoginPromptBrowserTestObserver observer;
232
233 observer.Register(Source<NavigationController>(controller));
234
235 WindowedLoadStopObserver load_stop_waiter(controller);
236 int n_handlers = 0;
237
238 {
239 WindowedAuthNeededObserver auth_needed_waiter(controller);
240
241 browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED);
242 auth_needed_waiter.Wait();
243 }
244
245 while (n_handlers < kMultiRealmTestRealmCount) {
246 WindowedAuthNeededObserver auth_needed_waiter(controller);
247
248 while (!observer.handlers_.empty()) {
249 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
250 LoginHandler* handler = *observer.handlers_.begin();
251
252 ASSERT_TRUE(handler);
253 n_handlers++;
254 SetAuthFor(handler);
255 auth_supplied_waiter.Wait();
256 }
257
258 if (n_handlers < kMultiRealmTestRealmCount)
259 auth_needed_waiter.Wait();
260 }
261
262 load_stop_waiter.Wait();
263
264 EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
265 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_needed_count_);
266 EXPECT_EQ(kMultiRealmTestResourceCount, observer.auth_supplied_count_);
267 EXPECT_EQ(0, observer.auth_cancelled_count_);
268 }
269
270 // Testing for recovery from an incorrect password for the case where
271 // there are multiple authenticated resources.
272 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, IncorrectConfirmation) {
273 ASSERT_TRUE(test_server()->Start());
274 GURL test_page = test_server()->GetURL(kSingleRealmTestPage);
275
276 TabContentsWrapper* contents =
277 browser()->GetSelectedTabContentsWrapper();
278 ASSERT_TRUE(contents);
279
280 NavigationController* controller = &contents->controller();
281 LoginPromptBrowserTestObserver observer;
282
283 observer.Register(Source<NavigationController>(controller));
284
285 WindowedLoadStopObserver load_stop_waiter(controller);
286
287 {
288 WindowedAuthNeededObserver auth_needed_waiter(controller);
289 browser()->OpenURL(test_page, GURL(), CURRENT_TAB, PageTransition::TYPED);
290 auth_needed_waiter.Wait();
291 }
292
293 EXPECT_FALSE(observer.handlers_.empty());
294
295 if (!observer.handlers_.empty()) {
296 WindowedAuthNeededObserver auth_needed_waiter(controller);
297 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
298 LoginHandler* handler = *observer.handlers_.begin();
299
300 ASSERT_TRUE(handler);
301 handler->SetAuth(bad_username_, bad_password_);
302 auth_supplied_waiter.Wait();
303
304 // The request should be retried after the incorrect password is
305 // supplied. This should result in a new AUTH_NEEDED notification
306 // for the same realm.
307 auth_needed_waiter.Wait();
308 }
309
310 int n_handlers = 0;
311
312 while (n_handlers < 1) {
313 WindowedAuthNeededObserver auth_needed_waiter(controller);
314
315 while (!observer.handlers_.empty()) {
316 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
317 LoginHandler* handler = *observer.handlers_.begin();
318
319 ASSERT_TRUE(handler);
320 n_handlers++;
321 SetAuthFor(handler);
322 auth_supplied_waiter.Wait();
323 }
324
325 if (n_handlers < 1)
326 auth_needed_waiter.Wait();
327 }
328
329 load_stop_waiter.Wait();
330
331 // auth_needed_count_ and auth_supplied_count_ are twice the number
332 // of resources since the incorrect password attempt should have
333 // resulted in a retry for the whole page. The single realm test
334 // has only one realm, and thus only one login prompt.
335 EXPECT_EQ(1, n_handlers);
336 EXPECT_EQ(kSingleRealmTestResourceCount * 2, observer.auth_needed_count_);
337 EXPECT_EQ(kSingleRealmTestResourceCount * 2, observer.auth_supplied_count_);
338 EXPECT_EQ(0, observer.auth_cancelled_count_);
339 }
340 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698