Stack sampling profiler: add fire-and-forget interface
[chromium-blink-merge.git] / components / signin / core / browser / signin_header_helper.cc
blob43a2efce2bfb7f6bb97cb0cd615a999dbada3ef5
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
3 // found in the LICENSE file.
5 #include "components/signin/core/browser/signin_header_helper.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_split.h"
9 #include "base/strings/stringprintf.h"
10 #include "components/content_settings/core/browser/cookie_settings.h"
11 #include "components/google/core/browser/google_util.h"
12 #include "components/signin/core/common/profile_management_switches.h"
13 #include "google_apis/gaia/gaia_auth_util.h"
14 #include "google_apis/gaia/gaia_urls.h"
15 #include "net/base/escape.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request.h"
18 #include "url/gurl.h"
20 namespace {
22 // Dictionary of fields in a mirror response header.
23 typedef std::map<std::string, std::string> MirrorResponseHeaderDictionary;
25 const char kChromeConnectedHeader[] = "X-Chrome-Connected";
26 const char kChromeManageAccountsHeader[] = "X-Chrome-Manage-Accounts";
27 const char kContinueUrlAttrName[] = "continue_url";
28 const char kEmailAttrName[] = "email";
29 const char kEnableAccountConsistencyAttrName[] = "enable_account_consistency";
30 const char kGaiaIdAttrName[] = "id";
31 const char kProfileModeAttrName[] = "mode";
32 const char kIsSameTabAttrName[] = "is_same_tab";
33 const char kIsSamlAttrName[] = "is_saml";
34 const char kServiceTypeAttrName[] = "action";
36 bool IsDriveOrigin(const GURL& url) {
37 if (!url.SchemeIsCryptographic())
38 return false;
40 const GURL kGoogleDriveURL("https://drive.google.com");
41 const GURL kGoogleDocsURL("https://docs.google.com");
42 return url == kGoogleDriveURL || url == kGoogleDocsURL;
45 // Determines the service type that has been passed from GAIA in the header.
46 signin::GAIAServiceType GetGAIAServiceTypeFromHeader(
47 const std::string& header_value) {
48 if (header_value == "SIGNOUT")
49 return signin::GAIA_SERVICE_TYPE_SIGNOUT;
50 else if (header_value == "INCOGNITO")
51 return signin::GAIA_SERVICE_TYPE_INCOGNITO;
52 else if (header_value == "ADDSESSION")
53 return signin::GAIA_SERVICE_TYPE_ADDSESSION;
54 else if (header_value == "REAUTH")
55 return signin::GAIA_SERVICE_TYPE_REAUTH;
56 else if (header_value == "SIGNUP")
57 return signin::GAIA_SERVICE_TYPE_SIGNUP;
58 else if (header_value == "DEFAULT")
59 return signin::GAIA_SERVICE_TYPE_DEFAULT;
60 else
61 return signin::GAIA_SERVICE_TYPE_NONE;
64 // Parses the mirror response header. Its expected format is
65 // "key1=value1,key2=value2,...".
66 MirrorResponseHeaderDictionary ParseMirrorResponseHeader(
67 const std::string& header_value) {
68 MirrorResponseHeaderDictionary dictionary;
69 for (const base::StringPiece& field :
70 base::SplitStringPiece(header_value, ",", base::KEEP_WHITESPACE,
71 base::SPLIT_WANT_NONEMPTY)) {
72 size_t delim = field.find_first_of('=');
73 if (delim == std::string::npos) {
74 DLOG(WARNING) << "Unexpected GAIA header field '" << field << "'.";
75 continue;
77 dictionary[field.substr(0, delim).as_string()] =
78 net::UnescapeURLComponent(field.substr(delim + 1).as_string(),
79 net::UnescapeRule::URL_SPECIAL_CHARS);
81 return dictionary;
84 // Returns the parameters contained in the X-Chrome-Manage-Accounts response
85 // header.
86 signin::ManageAccountsParams BuildManageAccountsParams(
87 const std::string& header_value) {
88 signin::ManageAccountsParams params;
89 MirrorResponseHeaderDictionary header_dictionary =
90 ParseMirrorResponseHeader(header_value);
91 MirrorResponseHeaderDictionary::const_iterator it = header_dictionary.begin();
92 for (; it != header_dictionary.end(); ++it) {
93 const std::string key_name(it->first);
94 if (key_name == kServiceTypeAttrName) {
95 params.service_type =
96 GetGAIAServiceTypeFromHeader(header_dictionary[kServiceTypeAttrName]);
97 } else if (key_name == kEmailAttrName) {
98 params.email = header_dictionary[kEmailAttrName];
99 } else if (key_name == kIsSamlAttrName) {
100 params.is_saml = header_dictionary[kIsSamlAttrName] == "true";
101 } else if (key_name == kContinueUrlAttrName) {
102 params.continue_url = header_dictionary[kContinueUrlAttrName];
103 } else if (key_name == kIsSameTabAttrName) {
104 params.is_same_tab = header_dictionary[kIsSameTabAttrName] == "true";
105 } else {
106 DLOG(WARNING) << "Unexpected GAIA header attribute '" << key_name << "'.";
109 return params;
112 } // namespace
114 namespace signin {
116 ManageAccountsParams::ManageAccountsParams()
117 : service_type(GAIA_SERVICE_TYPE_NONE),
118 email(""),
119 is_saml(false),
120 continue_url(""),
121 is_same_tab(false) {
122 #if !defined(OS_IOS)
123 child_id = 0;
124 route_id = 0;
125 #endif // !defined(OS_IOS)
128 bool SettingsAllowSigninCookies(
129 content_settings::CookieSettings* cookie_settings) {
130 GURL gaia_url = GaiaUrls::GetInstance()->gaia_url();
131 GURL google_url = GaiaUrls::GetInstance()->google_url();
132 return cookie_settings &&
133 cookie_settings->IsSettingCookieAllowed(gaia_url, gaia_url) &&
134 cookie_settings->IsSettingCookieAllowed(google_url, google_url);
137 bool AppendMirrorRequestHeaderIfPossible(
138 net::URLRequest* request,
139 const GURL& redirect_url,
140 const std::string& account_id,
141 content_settings::CookieSettings* cookie_settings,
142 int profile_mode_mask) {
143 if (account_id.empty())
144 return false;
146 // If signin cookies are not allowed, don't add the header.
147 if (SettingsAllowSigninCookies(cookie_settings)) {
148 return false;
151 // Only set the header for Drive and Gaia always, and other Google properties
152 // if account consistency is enabled.
153 // Vasquette, which is integrated with most Google properties, needs the
154 // header to redirect certain user actions to Chrome native UI. Drive and Gaia
155 // need the header to tell if the current user is connected. The drive path is
156 // a temporary workaround until the more generic chrome.principals API is
157 // available.
158 const GURL& url = redirect_url.is_empty() ? request->url() : redirect_url;
159 GURL origin(url.GetOrigin());
160 bool is_enable_account_consistency = switches::IsEnableAccountConsistency();
161 bool is_google_url = is_enable_account_consistency &&
162 (google_util::IsGoogleDomainUrl(
163 url, google_util::ALLOW_SUBDOMAIN,
164 google_util::DISALLOW_NON_STANDARD_PORTS) ||
165 google_util::IsYoutubeDomainUrl(
166 url, google_util::ALLOW_SUBDOMAIN,
167 google_util::DISALLOW_NON_STANDARD_PORTS));
168 if (!is_google_url && !IsDriveOrigin(origin) &&
169 !gaia::IsGaiaSignonRealm(origin)) {
170 return false;
173 std::string header_value(base::StringPrintf(
174 "%s=%s,%s=%s,%s=%s", kGaiaIdAttrName, account_id.c_str(),
175 kProfileModeAttrName, base::IntToString(profile_mode_mask).c_str(),
176 kEnableAccountConsistencyAttrName,
177 is_enable_account_consistency ? "true" : "false"));
178 request->SetExtraRequestHeaderByName(kChromeConnectedHeader, header_value,
179 false);
180 return true;
183 ManageAccountsParams BuildManageAccountsParamsIfExists(net::URLRequest* request,
184 bool is_off_the_record) {
185 ManageAccountsParams empty_params;
186 empty_params.service_type = GAIA_SERVICE_TYPE_NONE;
187 if (!gaia::IsGaiaSignonRealm(request->url().GetOrigin()))
188 return empty_params;
190 std::string header_value;
191 if (!request->response_headers()->GetNormalizedHeader(
192 kChromeManageAccountsHeader, &header_value)) {
193 return empty_params;
196 DCHECK(switches::IsEnableAccountConsistency() && !is_off_the_record);
197 return BuildManageAccountsParams(header_value);
200 } // namespace signin