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

Side by Side Diff: components/signin/core/browser/signin_header_helper.cc

Issue 2923733003: [signin] Add DICe flow for account consistency requests. (Closed)
Patch Set: Add test for Dice disabled 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/signin/core/browser/signin_header_helper.h" 5 #include "components/signin/core/browser/signin_header_helper.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <map>
8 9
10 #include "base/logging.h"
9 #include "base/macros.h" 11 #include "base/macros.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h" 12 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "build/build_config.h" 13 #include "build/build_config.h"
15 #include "components/content_settings/core/browser/cookie_settings.h" 14 #include "components/content_settings/core/browser/cookie_settings.h"
16 #include "components/google/core/browser/google_util.h" 15 #include "components/google/core/browser/google_util.h"
16 #include "components/signin/core/browser/chrome_connected_header_helper.h"
17 #include "components/signin/core/common/profile_management_switches.h" 17 #include "components/signin/core/common/profile_management_switches.h"
18 #include "google_apis/gaia/gaia_auth_util.h" 18 #include "google_apis/gaia/gaia_auth_util.h"
19 #include "google_apis/gaia/gaia_urls.h" 19 #include "google_apis/gaia/gaia_urls.h"
20 #include "net/base/escape.h" 20 #include "net/base/escape.h"
21 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
22 #include "net/http/http_response_headers.h" 21 #include "net/http/http_response_headers.h"
23 #include "net/url_request/url_request.h" 22 #include "net/url_request/url_request.h"
24 #include "url/gurl.h" 23 #include "url/gurl.h"
25 24
25 #if !defined(OS_IOS) && !defined(OS_ANDROID)
26 #include "components/signin/core/browser/dice_header_helper.h"
27 #endif
28
26 namespace signin { 29 namespace signin {
27 30
28 namespace { 31 namespace {
29 32
30 // Dictionary of fields in a mirror response header. 33 // Dictionary of fields in a mirror response header.
31 typedef std::map<std::string, std::string> MirrorResponseHeaderDictionary; 34 typedef std::map<std::string, std::string> MirrorResponseHeaderDictionary;
32 35
33 const char kChromeManageAccountsHeader[] = "X-Chrome-Manage-Accounts"; 36 const char kChromeManageAccountsHeader[] = "X-Chrome-Manage-Accounts";
34 const char kContinueUrlAttrName[] = "continue_url"; 37 const char kContinueUrlAttrName[] = "continue_url";
35 const char kEmailAttrName[] = "email"; 38 const char kEmailAttrName[] = "email";
36 const char kEnableAccountConsistencyAttrName[] = "enable_account_consistency";
37 const char kGaiaIdAttrName[] = "id";
38 const char kProfileModeAttrName[] = "mode";
39 const char kIsSameTabAttrName[] = "is_same_tab"; 39 const char kIsSameTabAttrName[] = "is_same_tab";
40 const char kIsSamlAttrName[] = "is_saml"; 40 const char kIsSamlAttrName[] = "is_saml";
41 const char kServiceTypeAttrName[] = "action"; 41 const char kServiceTypeAttrName[] = "action";
42 42
43 bool IsDriveOrigin(const GURL& url) {
44 if (!url.SchemeIsCryptographic())
45 return false;
46
47 const GURL kGoogleDriveURL("https://drive.google.com");
48 const GURL kGoogleDocsURL("https://docs.google.com");
49 return url == kGoogleDriveURL || url == kGoogleDocsURL;
50 }
51
52 bool IsUrlEligibleToIncludeGaiaId(const GURL& url, bool is_header_request) {
53 if (is_header_request) {
54 // GAIA Id is only necessary for Drive. Don't set it otherwise.
55 return IsDriveOrigin(url.GetOrigin());
56 }
57
58 // Cookie requests don't have the granularity to only include the GAIA Id for
59 // Drive origin. Set it on all google.com instead.
60 if (!url.SchemeIsCryptographic())
61 return false;
62
63 const std::string kGoogleDomain = "google.com";
64 std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
65 url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
66 return domain == kGoogleDomain;
67 }
68
69 // Determines the service type that has been passed from GAIA in the header. 43 // Determines the service type that has been passed from GAIA in the header.
70 GAIAServiceType GetGAIAServiceTypeFromHeader(const std::string& header_value) { 44 GAIAServiceType GetGAIAServiceTypeFromHeader(const std::string& header_value) {
71 if (header_value == "SIGNOUT") 45 if (header_value == "SIGNOUT")
72 return GAIA_SERVICE_TYPE_SIGNOUT; 46 return GAIA_SERVICE_TYPE_SIGNOUT;
73 else if (header_value == "INCOGNITO") 47 else if (header_value == "INCOGNITO")
74 return GAIA_SERVICE_TYPE_INCOGNITO; 48 return GAIA_SERVICE_TYPE_INCOGNITO;
75 else if (header_value == "ADDSESSION") 49 else if (header_value == "ADDSESSION")
76 return GAIA_SERVICE_TYPE_ADDSESSION; 50 return GAIA_SERVICE_TYPE_ADDSESSION;
77 else if (header_value == "REAUTH") 51 else if (header_value == "REAUTH")
78 return GAIA_SERVICE_TYPE_REAUTH; 52 return GAIA_SERVICE_TYPE_REAUTH;
(...skipping 19 matching lines...) Expand all
98 continue; 72 continue;
99 } 73 }
100 dictionary[field.substr(0, delim).as_string()] = net::UnescapeURLComponent( 74 dictionary[field.substr(0, delim).as_string()] = net::UnescapeURLComponent(
101 field.substr(delim + 1).as_string(), 75 field.substr(delim + 1).as_string(),
102 net::UnescapeRule::PATH_SEPARATORS | 76 net::UnescapeRule::PATH_SEPARATORS |
103 net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS); 77 net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
104 } 78 }
105 return dictionary; 79 return dictionary;
106 } 80 }
107 81
108 // Checks if the url has the required properties to have a X-Chrome-Connected
109 // header.
110 bool IsUrlEligibleForXChromeConnectedHeader(const GURL& url) {
111 // Only set the header for Drive and Gaia always, and other Google properties
112 // if account consistency is enabled.
113 // Vasquette, which is integrated with most Google properties, needs the
114 // header to redirect certain user actions to Chrome native UI. Drive and Gaia
115 // need the header to tell if the current user is connected. The drive path is
116 // a temporary workaround until the more generic chrome.principals API is
117 // available.
118
119 // Consider the account id sensitive and limit it to secure domains.
120 if (!url.SchemeIsCryptographic())
121 return false;
122
123 GURL origin(url.GetOrigin());
124 bool is_enable_account_consistency =
125 switches::IsAccountConsistencyMirrorEnabled();
126 bool is_google_url = is_enable_account_consistency &&
127 (google_util::IsGoogleDomainUrl(
128 url, google_util::ALLOW_SUBDOMAIN,
129 google_util::DISALLOW_NON_STANDARD_PORTS) ||
130 google_util::IsYoutubeDomainUrl(
131 url, google_util::ALLOW_SUBDOMAIN,
132 google_util::DISALLOW_NON_STANDARD_PORTS));
133 return is_google_url || IsDriveOrigin(origin) ||
134 gaia::IsGaiaSignonRealm(origin);
135 }
136
137 // Checks if the url has the required properties to have an account consistency
138 // header.
139 bool IsUrlEligibleForAccountConsistencyRequestHeader(const GURL& url) {
140 // TODO(droger): Support X-Chrome-ID-Consistency-Request.
141 return IsUrlEligibleForXChromeConnectedHeader(url);
142 }
143
144 std::string BuildMirrorRequestIfPossible(
145 bool is_header_request,
146 const GURL& url,
147 const std::string& account_id,
148 const content_settings::CookieSettings* cookie_settings,
149 int profile_mode_mask) {
150 if (account_id.empty())
151 return std::string();
152
153 // If signin cookies are not allowed, don't add the header.
154 if (!SettingsAllowSigninCookies(cookie_settings)) {
155 return std::string();
156 }
157
158 // Check if url is elligible for the header.
159 if (!IsUrlEligibleForXChromeConnectedHeader(url))
160 return std::string();
161
162 std::vector<std::string> parts;
163 if (IsUrlEligibleToIncludeGaiaId(url, is_header_request)) {
164 // Only set the GAIA Id on domains that actually requires it.
165 parts.push_back(
166 base::StringPrintf("%s=%s", kGaiaIdAttrName, account_id.c_str()));
167 }
168 parts.push_back(
169 base::StringPrintf("%s=%s", kProfileModeAttrName,
170 base::IntToString(profile_mode_mask).c_str()));
171 parts.push_back(base::StringPrintf(
172 "%s=%s", kEnableAccountConsistencyAttrName,
173 switches::IsAccountConsistencyMirrorEnabled() ? "true" : "false"));
174
175 return base::JoinString(parts, is_header_request ? "," : ":");
176 }
177
178 } // namespace 82 } // namespace
179 83
180 extern const char kChromeConnectedHeader[] = "X-Chrome-Connected";
181
182 ManageAccountsParams::ManageAccountsParams() 84 ManageAccountsParams::ManageAccountsParams()
183 : service_type(GAIA_SERVICE_TYPE_NONE), 85 : service_type(GAIA_SERVICE_TYPE_NONE),
184 email(""), 86 email(""),
185 is_saml(false), 87 is_saml(false),
186 continue_url(""), 88 continue_url(""),
187 is_same_tab(false) { 89 is_same_tab(false) {
188 #if !defined(OS_IOS) 90 #if !defined(OS_IOS)
189 child_id = 0; 91 child_id = 0;
190 route_id = 0; 92 route_id = 0;
191 #endif // !defined(OS_IOS) 93 #endif // !defined(OS_IOS)
192 } 94 }
193 95
194 ManageAccountsParams::ManageAccountsParams(const ManageAccountsParams& other) = 96 ManageAccountsParams::ManageAccountsParams(const ManageAccountsParams& other) =
195 default; 97 default;
196 98
197 bool SettingsAllowSigninCookies( 99 bool SettingsAllowSigninCookies(
198 const content_settings::CookieSettings* cookie_settings) { 100 const content_settings::CookieSettings* cookie_settings) {
199 GURL gaia_url = GaiaUrls::GetInstance()->gaia_url(); 101 GURL gaia_url = GaiaUrls::GetInstance()->gaia_url();
200 GURL google_url = GaiaUrls::GetInstance()->google_url(); 102 GURL google_url = GaiaUrls::GetInstance()->google_url();
201 return cookie_settings && 103 return cookie_settings &&
202 cookie_settings->IsCookieAccessAllowed(gaia_url, gaia_url) && 104 cookie_settings->IsCookieAccessAllowed(gaia_url, gaia_url) &&
203 cookie_settings->IsCookieAccessAllowed(google_url, google_url); 105 cookie_settings->IsCookieAccessAllowed(google_url, google_url);
204 } 106 }
205 107
206 std::string BuildMirrorRequestCookieIfPossible( 108 bool SigninHeaderHelper::AppendOrRemoveRequestHeader(
207 const GURL& url,
208 const std::string& account_id,
209 const content_settings::CookieSettings* cookie_settings,
210 int profile_mode_mask) {
211 return BuildMirrorRequestIfPossible(false /* is_header_request */, url,
212 account_id, cookie_settings,
213 profile_mode_mask);
214 }
215
216 bool AppendOrRemoveAccountConsistentyRequestHeader(
217 net::URLRequest* request, 109 net::URLRequest* request,
110 const char* header_name,
218 const GURL& redirect_url, 111 const GURL& redirect_url,
219 const std::string& account_id, 112 const std::string& account_id,
220 const content_settings::CookieSettings* cookie_settings, 113 const content_settings::CookieSettings* cookie_settings,
221 int profile_mode_mask) { 114 int profile_mode_mask) {
222 const GURL& url = redirect_url.is_empty() ? request->url() : redirect_url; 115 const GURL& url = redirect_url.is_empty() ? request->url() : redirect_url;
223 116 std::string header_value = BuildRequestHeaderIfPossible(
224 // TODO(droger): Support X-Chrome-ID-Consistency-Request.
225 std::string header_name = kChromeConnectedHeader;
226 std::string header_value = BuildMirrorRequestIfPossible(
227 true /* is_header_request */, url, account_id, cookie_settings, 117 true /* is_header_request */, url, account_id, cookie_settings,
228 profile_mode_mask); 118 profile_mode_mask);
229 119
230 if (!header_name.empty() && header_value.empty()) { 120 if (header_value.empty()) {
231 // If the request is being redirected, and it has the account consistency 121 // If the request is being redirected, and it has the account consistency
232 // header, and current url is a Google URL, and the redirected one is not, 122 // header, and current url is a Google URL, and the redirected one is not,
233 // remove the header. 123 // remove the header.
234 if (!redirect_url.is_empty() && 124 if (!redirect_url.is_empty() &&
235 request->extra_request_headers().HasHeader(header_name) && 125 request->extra_request_headers().HasHeader(header_name) &&
236 IsUrlEligibleForAccountConsistencyRequestHeader(request->url()) && 126 IsUrlEligibleForRequestHeader(request->url()) &&
237 !IsUrlEligibleForAccountConsistencyRequestHeader(redirect_url)) { 127 !IsUrlEligibleForRequestHeader(redirect_url)) {
238 request->RemoveRequestHeaderByName(header_name); 128 request->RemoveRequestHeaderByName(header_name);
239 } 129 }
240 return false; 130 return false;
241 } 131 }
242 request->SetExtraRequestHeaderByName(header_name, header_value, false); 132 request->SetExtraRequestHeaderByName(header_name, header_value, false);
243 return true; 133 return true;
244 } 134 }
245 135
136 std::string SigninHeaderHelper::BuildRequestHeaderIfPossible(
137 bool is_header_request,
138 const GURL& url,
139 const std::string& account_id,
140 const content_settings::CookieSettings* cookie_settings,
141 int profile_mode_mask) {
142 // If signin cookies are not allowed, don't add the header.
143 if (!SettingsAllowSigninCookies(cookie_settings))
144 return std::string();
145
146 // Check if url is eligible for the header.
147 if (!IsUrlEligibleForRequestHeader(url))
148 return std::string();
149
150 return BuildRequestHeader(is_header_request, url, account_id,
151 profile_mode_mask);
152 }
153
154 void AppendOrRemoveAccountConsistentyRequestHeader(
155 net::URLRequest* request,
156 const GURL& redirect_url,
157 const std::string& account_id,
158 const content_settings::CookieSettings* cookie_settings,
159 int profile_mode_mask) {
160 // Dice is not enabled on mobile.
msarda 2017/06/08 23:43:05 Indent
droger 2017/06/09 09:52:24 Not done. Indentation is correct.
161 #if !defined(OS_IOS) && !defined(OS_ANDROID)
162 DiceHeaderHelper dice_helper;
163 dice_helper.AppendOrRemoveRequestHeader(request, kDiceRequestHeader,
164 redirect_url, account_id,
165 cookie_settings, profile_mode_mask);
166 #endif
167
168 ChromeConnectedHeaderHelper chrome_connected_helper;
169 chrome_connected_helper.AppendOrRemoveRequestHeader(
170 request, kChromeConnectedHeader, redirect_url, account_id,
171 cookie_settings, profile_mode_mask);
172 }
173
246 ManageAccountsParams BuildManageAccountsParams( 174 ManageAccountsParams BuildManageAccountsParams(
247 const std::string& header_value) { 175 const std::string& header_value) {
248 ManageAccountsParams params; 176 ManageAccountsParams params;
249 MirrorResponseHeaderDictionary header_dictionary = 177 MirrorResponseHeaderDictionary header_dictionary =
250 ParseMirrorResponseHeader(header_value); 178 ParseMirrorResponseHeader(header_value);
251 MirrorResponseHeaderDictionary::const_iterator it = header_dictionary.begin(); 179 MirrorResponseHeaderDictionary::const_iterator it = header_dictionary.begin();
252 for (; it != header_dictionary.end(); ++it) { 180 for (; it != header_dictionary.end(); ++it) {
253 const std::string key_name(it->first); 181 const std::string key_name(it->first);
254 if (key_name == kServiceTypeAttrName) { 182 if (key_name == kServiceTypeAttrName) {
255 params.service_type = 183 params.service_type =
(...skipping 26 matching lines...) Expand all
282 !response_headers->GetNormalizedHeader( 210 !response_headers->GetNormalizedHeader(
283 kChromeManageAccountsHeader, &header_value)) { 211 kChromeManageAccountsHeader, &header_value)) {
284 return empty_params; 212 return empty_params;
285 } 213 }
286 214
287 DCHECK(switches::IsAccountConsistencyMirrorEnabled() && !is_off_the_record); 215 DCHECK(switches::IsAccountConsistencyMirrorEnabled() && !is_off_the_record);
288 return BuildManageAccountsParams(header_value); 216 return BuildManageAccountsParams(header_value);
289 } 217 }
290 218
291 } // namespace signin 219 } // namespace signin
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698