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

Side by Side Diff: components/password_manager/core/browser/affiliation_fetcher.cc

Issue 2953443002: Revert of Reland: Move the files related to Android <-> Web credentials to a separate folder. (Closed)
Patch Set: Created 3 years, 6 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
OLDNEW
(Empty)
1 // Copyright 2014 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 "components/password_manager/core/browser/affiliation_fetcher.h"
6
7 #include <stddef.h>
8 #include <utility>
9
10 #include "base/metrics/histogram_macros.h"
11 #include "base/metrics/sparse_histogram.h"
12 #include "components/password_manager/core/browser/affiliation_api.pb.h"
13 #include "components/password_manager/core/browser/affiliation_utils.h"
14 #include "components/password_manager/core/browser/test_affiliation_fetcher_fact ory.h"
15 #include "google_apis/google_api_keys.h"
16 #include "net/base/load_flags.h"
17 #include "net/base/url_util.h"
18 #include "net/http/http_status_code.h"
19 #include "net/traffic_annotation/network_traffic_annotation.h"
20 #include "net/url_request/url_fetcher.h"
21 #include "net/url_request/url_request_context_getter.h"
22 #include "url/gurl.h"
23
24 namespace password_manager {
25
26 namespace {
27
28 // Enumeration listing the possible outcomes of fetching affiliation information
29 // from the Affiliation API. This is used in UMA histograms, so do not change
30 // existing values, only add new values at the end.
31 enum AffiliationFetchResult {
32 AFFILIATION_FETCH_RESULT_SUCCESS,
33 AFFILIATION_FETCH_RESULT_FAILURE,
34 AFFILIATION_FETCH_RESULT_MALFORMED,
35 AFFILIATION_FETCH_RESULT_MAX
36 };
37
38 // Records the given fetch |result| into the respective UMA histogram, as well
39 // as the response and error codes of |fetcher| if it is non-null.
40 void ReportStatistics(AffiliationFetchResult result,
41 const net::URLFetcher* fetcher) {
42 UMA_HISTOGRAM_ENUMERATION("PasswordManager.AffiliationFetcher.FetchResult",
43 result, AFFILIATION_FETCH_RESULT_MAX);
44 if (fetcher) {
45 UMA_HISTOGRAM_SPARSE_SLOWLY(
46 "PasswordManager.AffiliationFetcher.FetchHttpResponseCode",
47 fetcher->GetResponseCode());
48 // Network error codes are negative. See: src/net/base/net_error_list.h.
49 UMA_HISTOGRAM_SPARSE_SLOWLY(
50 "PasswordManager.AffiliationFetcher.FetchErrorCode",
51 -fetcher->GetStatus().error());
52 }
53 }
54
55 } // namespace
56
57 static TestAffiliationFetcherFactory* g_testing_factory = nullptr;
58
59 AffiliationFetcher::AffiliationFetcher(
60 net::URLRequestContextGetter* request_context_getter,
61 const std::vector<FacetURI>& facet_uris,
62 AffiliationFetcherDelegate* delegate)
63 : request_context_getter_(request_context_getter),
64 requested_facet_uris_(facet_uris),
65 delegate_(delegate) {
66 for (const FacetURI& uri : requested_facet_uris_) {
67 DCHECK(uri.is_valid());
68 }
69 }
70
71 AffiliationFetcher::~AffiliationFetcher() {
72 }
73
74 // static
75 AffiliationFetcher* AffiliationFetcher::Create(
76 net::URLRequestContextGetter* context_getter,
77 const std::vector<FacetURI>& facet_uris,
78 AffiliationFetcherDelegate* delegate) {
79 if (g_testing_factory) {
80 return g_testing_factory->CreateInstance(context_getter, facet_uris,
81 delegate);
82 }
83 return new AffiliationFetcher(context_getter, facet_uris, delegate);
84 }
85
86 // static
87 void AffiliationFetcher::SetFactoryForTesting(
88 TestAffiliationFetcherFactory* factory) {
89 g_testing_factory = factory;
90 }
91
92 void AffiliationFetcher::StartRequest() {
93 DCHECK(!fetcher_);
94
95 net::NetworkTrafficAnnotationTag traffic_annotation =
96 net::DefineNetworkTrafficAnnotation("affiliation_lookup", R"(
97 semantics {
98 sender: "Android Credentials Affiliation Fetcher"
99 description:
100 "Users syncing their passwords may have credentials stored for "
101 "Android apps. Unless synced data is encrypted with a custom "
102 "passphrase, this service downloads the associations between "
103 "Android apps and the corresponding websites. Thus, the Android "
104 "credentials can be used while browsing the web. "
105 trigger: "Periodically in the background."
106 data:
107 "List of Android apps the user has credentials for. The passwords "
108 "and usernames aren't sent."
109 destination: GOOGLE_OWNED_SERVICE
110 }
111 policy {
112 cookies_allowed: false
113 setting:
114 "Users can enable or disable this feature either by stoping "
115 "syncing passwords to Google (via unchecking 'Passwords' in "
116 "Chromium's settings under 'Sign In', 'Advanced sync settings') or "
117 "by introducing a custom passphrase to disable this service. The "
118 "feature is enabled by default."
119 chrome_policy {
120 SyncDisabled {
121 policy_options {mode: MANDATORY}
122 SyncDisabled: true
123 }
124 }
125 })");
126 fetcher_ = net::URLFetcher::Create(BuildQueryURL(), net::URLFetcher::POST,
127 this, traffic_annotation);
128 fetcher_->SetRequestContext(request_context_getter_.get());
129 fetcher_->SetUploadData("application/x-protobuf", PreparePayload());
130 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
131 net::LOAD_DO_NOT_SEND_COOKIES |
132 net::LOAD_DO_NOT_SEND_AUTH_DATA |
133 net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE);
134 fetcher_->SetAutomaticallyRetryOn5xx(false);
135 fetcher_->SetAutomaticallyRetryOnNetworkChanges(0);
136 fetcher_->Start();
137 }
138
139 GURL AffiliationFetcher::BuildQueryURL() const {
140 return net::AppendQueryParameter(
141 GURL("https://www.googleapis.com/affiliation/v1/affiliation:lookup"),
142 "key", google_apis::GetAPIKey());
143 }
144
145 std::string AffiliationFetcher::PreparePayload() const {
146 affiliation_pb::LookupAffiliationRequest lookup_request;
147 for (const FacetURI& uri : requested_facet_uris_)
148 lookup_request.add_facet(uri.canonical_spec());
149
150 std::string serialized_request;
151 bool success = lookup_request.SerializeToString(&serialized_request);
152 DCHECK(success);
153 return serialized_request;
154 }
155
156 bool AffiliationFetcher::ParseResponse(
157 AffiliationFetcherDelegate::Result* result) const {
158 // This function parses the response protocol buffer message for a list of
159 // equivalence classes, and stores them into |results| after performing some
160 // validation and sanitization steps to make sure that the contract of
161 // AffiliationFetcherDelegate is fulfilled. Possible discrepancies are:
162 // * The server response will not have anything for facets that are not
163 // affiliated with any other facet, while |result| must have them.
164 // * The server response might contain future, unknown kinds of facet URIs,
165 // while |result| must contain only those that are FacetURI::is_valid().
166 // * The server response being ill-formed or self-inconsistent (in the sense
167 // that there are overlapping equivalence classes) is indicative of server
168 // side issues likely not remedied by re-fetching. Report failure in this
169 // case so the caller can be notified and it can act accordingly.
170 // * The |result| will be free of duplicate or empty equivalence classes.
171
172 std::string serialized_response;
173 if (!fetcher_->GetResponseAsString(&serialized_response)) {
174 NOTREACHED();
175 }
176
177 affiliation_pb::LookupAffiliationResponse response;
178 if (!response.ParseFromString(serialized_response))
179 return false;
180
181 result->reserve(requested_facet_uris_.size());
182
183 std::map<FacetURI, size_t> facet_uri_to_class_index;
184 for (int i = 0; i < response.affiliation_size(); ++i) {
185 const affiliation_pb::Affiliation& equivalence_class(
186 response.affiliation(i));
187
188 AffiliatedFacets affiliated_uris;
189 for (int j = 0; j < equivalence_class.facet_size(); ++j) {
190 const std::string& uri_spec(equivalence_class.facet(j).id());
191 FacetURI uri = FacetURI::FromPotentiallyInvalidSpec(uri_spec);
192 // Ignore potential future kinds of facet URIs (e.g. for new platforms).
193 if (!uri.is_valid())
194 continue;
195 affiliated_uris.push_back(uri);
196 }
197
198 // Be lenient and ignore empty (after filtering) equivalence classes.
199 if (affiliated_uris.empty())
200 continue;
201
202 // Ignore equivalence classes that are duplicates of earlier ones. However,
203 // fail in the case of a partial overlap, which violates the invariant that
204 // affiliations must form an equivalence relation.
205 for (const FacetURI& uri : affiliated_uris) {
206 if (!facet_uri_to_class_index.count(uri))
207 facet_uri_to_class_index[uri] = result->size();
208 if (facet_uri_to_class_index[uri] !=
209 facet_uri_to_class_index[affiliated_uris[0]]) {
210 return false;
211 }
212 }
213
214 // Filter out duplicate equivalence classes in the response.
215 if (facet_uri_to_class_index[affiliated_uris[0]] == result->size())
216 result->push_back(affiliated_uris);
217 }
218
219 // Synthesize an equivalence class (of size one) for each facet that did not
220 // appear in the server response due to not being affiliated with any others.
221 for (const FacetURI& uri : requested_facet_uris_) {
222 if (!facet_uri_to_class_index.count(uri))
223 result->push_back(AffiliatedFacets(1, uri));
224 }
225
226 return true;
227 }
228
229 void AffiliationFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
230 DCHECK_EQ(source, fetcher_.get());
231
232 // Note that invoking the |delegate_| may destroy |this| synchronously, so the
233 // invocation must happen last.
234 std::unique_ptr<AffiliationFetcherDelegate::Result> result_data(
235 new AffiliationFetcherDelegate::Result);
236 if (fetcher_->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
237 fetcher_->GetResponseCode() == net::HTTP_OK) {
238 if (ParseResponse(result_data.get())) {
239 ReportStatistics(AFFILIATION_FETCH_RESULT_SUCCESS, nullptr);
240 delegate_->OnFetchSucceeded(std::move(result_data));
241 } else {
242 ReportStatistics(AFFILIATION_FETCH_RESULT_MALFORMED, nullptr);
243 delegate_->OnMalformedResponse();
244 }
245 } else {
246 ReportStatistics(AFFILIATION_FETCH_RESULT_FAILURE, fetcher_.get());
247 delegate_->OnFetchFailed();
248 }
249 }
250
251 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698