1 // Copyright 2020 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/login_detection/login_detection_tab_helper.h"
6
7 #include "base/test/metrics/histogram_tester.h"
8 #include "chrome/browser/login_detection/login_detection_util.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
11 #include "components/ukm/test_ukm_recorder.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/test/navigation_simulator.h"
15 #include "services/metrics/public/cpp/ukm_builders.h"
16
17 namespace login_detection {
18
19 class LoginDetectionTabHelperTest : public ChromeRenderViewHostTestHarness {
20 public:
SetUp()21 void SetUp() override {
22 scoped_feature_list_.InitAndEnableFeature(kLoginDetection);
23 ChromeRenderViewHostTestHarness::SetUp();
24 ResetMetricsTesters();
25 LoginDetectionTabHelper::MaybeCreateForWebContents(web_contents());
26 }
27
ResetMetricsTesters()28 void ResetMetricsTesters() {
29 histogram_tester_ = std::make_unique<base::HistogramTester>();
30 ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
31 }
32
33 // Verifies the UMA and UKM metrics for the given login detection type to be
34 // recorded.
VerifyLoginDetectionTypeMetrics(LoginDetectionTabHelper::LoginDetectionType type)35 void VerifyLoginDetectionTypeMetrics(
36 LoginDetectionTabHelper::LoginDetectionType type) {
37 histogram_tester_->ExpectUniqueSample("Login.PageLoad.DetectionType", type,
38 1);
39
40 const auto& entries = ukm_recorder_->GetEntriesByName(
41 ukm::builders::LoginDetection::kEntryName);
42 ASSERT_EQ(1U, entries.size());
43 ukm::TestUkmRecorder::ExpectEntryMetric(
44 entries[0], ukm::builders::LoginDetection::kPage_LoginTypeName,
45 static_cast<int64_t>(type));
46 }
47
48 protected:
49 base::test::ScopedFeatureList scoped_feature_list_;
50 std::unique_ptr<base::HistogramTester> histogram_tester_;
51 std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
52 };
53
TEST_F(LoginDetectionTabHelperTest,NoLogin)54 TEST_F(LoginDetectionTabHelperTest, NoLogin) {
55 NavigateAndCommit(GURL("https://foo.com/page.html"));
56 VerifyLoginDetectionTypeMetrics(
57 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
58 }
59
TEST_F(LoginDetectionTabHelperTest,SimpleOAuthLogin)60 TEST_F(LoginDetectionTabHelperTest, SimpleOAuthLogin) {
61 NavigateAndCommit(GURL("https://foo.com/page.html"));
62 VerifyLoginDetectionTypeMetrics(
63 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
64 ResetMetricsTesters();
65
66 // OAuth login start
67 NavigateAndCommit(GURL("https://oauth.com/authenticate?client_id=123"));
68 VerifyLoginDetectionTypeMetrics(
69 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
70
71 // OAuth login complete
72 ResetMetricsTesters();
73 NavigateAndCommit(GURL("https://foo.com/redirect?code=secret"));
74 VerifyLoginDetectionTypeMetrics(
75 LoginDetectionTabHelper::LoginDetectionType::kOauthFirstTimeLoginFlow);
76
77 // Subsequent navigations to OAuth signed-in site.
78 ResetMetricsTesters();
79 NavigateAndCommit(GURL("https://images.foo.com/page.html"));
80 VerifyLoginDetectionTypeMetrics(
81 LoginDetectionTabHelper::LoginDetectionType::kOauthLogin);
82 }
83
TEST_F(LoginDetectionTabHelperTest,NavigationToOAuthLoggedInSite)84 TEST_F(LoginDetectionTabHelperTest, NavigationToOAuthLoggedInSite) {
85 NavigateAndCommit(GURL("https://foo.com/page.html"));
86 VerifyLoginDetectionTypeMetrics(
87 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
88 ResetMetricsTesters();
89
90 // Trigger OAuth login so that the site is saved in prefs.
91 NavigateAndCommit(GURL("https://oauth.com/authenticate?client_id=123"));
92 NavigateAndCommit(GURL("https://foo.com/redirect?code=secret"));
93
94 // Subsequent navigations to OAuth signed-in site.
95 ResetMetricsTesters();
96 NavigateAndCommit(GURL("https://images.foo.com/page.html"));
97 VerifyLoginDetectionTypeMetrics(
98 LoginDetectionTabHelper::LoginDetectionType::kOauthLogin);
99
100 // Navigation to a non logged-in site.
101 ResetMetricsTesters();
102 NavigateAndCommit(GURL("https://bar.com/page.html"));
103 VerifyLoginDetectionTypeMetrics(
104 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
105 }
106
TEST_F(LoginDetectionTabHelperTest,OAuthLoginViaRedirect)107 TEST_F(LoginDetectionTabHelperTest, OAuthLoginViaRedirect) {
108 NavigateAndCommit(GURL("https://foo.com/page.html"));
109 VerifyLoginDetectionTypeMetrics(
110 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
111 ResetMetricsTesters();
112
113 // OAuth login start and complete via redirects.
114 auto simulator = content::NavigationSimulator::CreateBrowserInitiated(
115 GURL("https://foo.com/oauth_signin"), web_contents());
116 simulator->SetTransition(ui::PAGE_TRANSITION_LINK);
117 simulator->Start();
118 simulator->Redirect(GURL("https://oauth.com/authenticate?client_id=123"));
119 simulator->Redirect(GURL("https://oauth.com/user_login"));
120 simulator->Redirect(GURL("https://oauth.com/?username=user&password=123"));
121 simulator->Redirect(GURL("https://foo.com/redirect?code=secret"));
122 simulator->Commit();
123
124 VerifyLoginDetectionTypeMetrics(
125 LoginDetectionTabHelper::LoginDetectionType::kOauthFirstTimeLoginFlow);
126
127 // Subsequent navigations to OAuth signed-in site.
128 ResetMetricsTesters();
129 NavigateAndCommit(GURL("https://images.foo.com/page.html"));
130 VerifyLoginDetectionTypeMetrics(
131 LoginDetectionTabHelper::LoginDetectionType::kOauthLogin);
132 }
133
134 // Test that OAuth login is still detected when there are intermediate
135 // navigations to other sites.
TEST_F(LoginDetectionTabHelperTest,InvalidOAuthLogins)136 TEST_F(LoginDetectionTabHelperTest, InvalidOAuthLogins) {
137 NavigateAndCommit(GURL("https://foo.com/page.html"));
138 VerifyLoginDetectionTypeMetrics(
139 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
140 ResetMetricsTesters();
141
142 // OAuth login start
143 NavigateAndCommit(GURL("https://oauth.com/authenticate?client_id=123"));
144 VerifyLoginDetectionTypeMetrics(
145 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
146
147 // Intermediate navigation just ignored
148 ResetMetricsTesters();
149 NavigateAndCommit(GURL("https://bar.com/page.html"));
150 VerifyLoginDetectionTypeMetrics(
151 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
152
153 // OAuth login complete will be detected
154 ResetMetricsTesters();
155 NavigateAndCommit(GURL("https://foo.com/redirect?code=secret"));
156 VerifyLoginDetectionTypeMetrics(
157 LoginDetectionTabHelper::LoginDetectionType::kOauthFirstTimeLoginFlow);
158
159 ResetMetricsTesters();
160 NavigateAndCommit(GURL("https://images.foo.com/page.html"));
161 VerifyLoginDetectionTypeMetrics(
162 LoginDetectionTabHelper::LoginDetectionType::kOauthLogin);
163 }
164
165 // Test that OAuth login is still detected when there are intermediate redirect
166 // navigations to other sites.
TEST_F(LoginDetectionTabHelperTest,InvalidOAuthLoginsWithRedirect)167 TEST_F(LoginDetectionTabHelperTest, InvalidOAuthLoginsWithRedirect) {
168 NavigateAndCommit(GURL("https://foo.com/page.html"));
169 VerifyLoginDetectionTypeMetrics(
170 LoginDetectionTabHelper::LoginDetectionType::kNoLogin);
171 ResetMetricsTesters();
172
173 // OAuth login start and complete via redirects.
174 auto simulator = content::NavigationSimulator::CreateBrowserInitiated(
175 GURL("https://foo.com/oauth_signin"), web_contents());
176 simulator->SetTransition(ui::PAGE_TRANSITION_LINK);
177 simulator->Start();
178 simulator->Redirect(GURL("https://oauth.com/authenticate?client_id=123"));
179 simulator->Redirect(GURL("https://oauth.com/user_login"));
180 simulator->Redirect(GURL("https://oauth.com/?username=user&password=123"));
181 simulator->Redirect(GURL("https://bar.com/page.html"));
182 simulator->Redirect(GURL("https://foo.com/redirect?code=secret"));
183 simulator->Commit();
184
185 VerifyLoginDetectionTypeMetrics(
186 LoginDetectionTabHelper::LoginDetectionType::kOauthFirstTimeLoginFlow);
187 }
188
189 } // namespace login_detection
190