OLD | NEW |
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 "chrome/browser/signin/signin_header_helper.h" | 5 #include "chrome/browser/signin/signin_header_helper.h" |
6 | 6 |
7 #include "base/strings/string_number_conversions.h" | 7 #include "base/strings/string_number_conversions.h" |
| 8 #include "base/strings/string_util.h" |
8 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
9 #include "chrome/browser/google/google_util.h" | 10 #include "chrome/browser/google/google_util.h" |
10 #include "chrome/browser/prefs/incognito_mode_prefs.h" | 11 #include "chrome/browser/prefs/incognito_mode_prefs.h" |
11 #include "chrome/browser/profiles/profile_io_data.h" | 12 #include "chrome/browser/profiles/profile_io_data.h" |
12 #include "chrome/browser/tab_contents/tab_util.h" | 13 #include "chrome/browser/tab_contents/tab_util.h" |
13 #include "chrome/browser/ui/browser_window.h" | 14 #include "chrome/browser/ui/browser_window.h" |
14 #include "chrome/common/url_constants.h" | 15 #include "chrome/common/url_constants.h" |
15 #include "components/signin/core/common/profile_management_switches.h" | 16 #include "components/signin/core/common/profile_management_switches.h" |
16 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/web_contents.h" | 18 #include "content/public/browser/web_contents.h" |
18 #include "google_apis/gaia/gaia_auth_util.h" | 19 #include "google_apis/gaia/gaia_auth_util.h" |
19 #include "net/http/http_response_headers.h" | 20 #include "net/http/http_response_headers.h" |
20 #include "net/url_request/url_request.h" | 21 #include "net/url_request/url_request.h" |
21 | 22 |
22 #if defined(OS_ANDROID) | 23 #if defined(OS_ANDROID) |
23 #include "chrome/browser/android/signin/account_management_screen_helper.h" | 24 #include "chrome/browser/android/signin/account_management_screen_helper.h" |
24 #else | 25 #else |
25 #include "chrome/browser/ui/browser_commands.h" | 26 #include "chrome/browser/ui/browser_commands.h" |
26 #include "chrome/browser/ui/browser_finder.h" | 27 #include "chrome/browser/ui/browser_finder.h" |
27 #endif // defined(OS_ANDROID) | 28 #endif // defined(OS_ANDROID) |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
| 32 // Dictionary of fields in a mirror response header. |
| 33 typedef std::map<std::string, std::string> MirrorResponseHeaderDictionary; |
| 34 |
31 const char kChromeConnectedHeader[] = "X-Chrome-Connected"; | 35 const char kChromeConnectedHeader[] = "X-Chrome-Connected"; |
32 const char kChromeManageAccountsHeader[] = "X-Chrome-Manage-Accounts"; | 36 const char kChromeManageAccountsHeader[] = "X-Chrome-Manage-Accounts"; |
33 const char kGaiaIdAttrName[] = "id"; | 37 const char kGaiaIdAttrName[] = "id"; |
34 const char kProfileModeAttrName[] = "mode"; | 38 const char kProfileModeAttrName[] = "mode"; |
35 const char kEnableAccountConsistencyAttrName[] = "enable_account_consistency"; | 39 const char kEnableAccountConsistencyAttrName[] = "enable_account_consistency"; |
36 | 40 |
37 // Determine the service type that has been passed from GAIA in the header. | 41 // Determines the service type that has been passed from GAIA in the header. |
38 signin::GAIAServiceType GetGAIAServiceTypeFromHeader( | 42 signin::GAIAServiceType GetGAIAServiceTypeFromHeader( |
39 const std::string& header_value) { | 43 const std::string& header_value) { |
40 if (header_value == "SIGNOUT") | 44 if (header_value == "SIGNOUT") |
41 return signin::GAIA_SERVICE_TYPE_SIGNOUT; | 45 return signin::GAIA_SERVICE_TYPE_SIGNOUT; |
42 else if (header_value == "INCOGNITO") | 46 else if (header_value == "INCOGNITO") |
43 return signin::GAIA_SERVICE_TYPE_INCOGNITO; | 47 return signin::GAIA_SERVICE_TYPE_INCOGNITO; |
44 else if (header_value == "ADDSESSION") | 48 else if (header_value == "ADDSESSION") |
45 return signin::GAIA_SERVICE_TYPE_ADDSESSION; | 49 return signin::GAIA_SERVICE_TYPE_ADDSESSION; |
46 else if (header_value == "REAUTH") | 50 else if (header_value == "REAUTH") |
47 return signin::GAIA_SERVICE_TYPE_REAUTH; | 51 return signin::GAIA_SERVICE_TYPE_REAUTH; |
48 else if (header_value == "DEFAULT") | 52 else if (header_value == "DEFAULT") |
49 return signin::GAIA_SERVICE_TYPE_DEFAULT; | 53 return signin::GAIA_SERVICE_TYPE_DEFAULT; |
50 else | 54 else |
51 return signin::GAIA_SERVICE_TYPE_NONE; | 55 return signin::GAIA_SERVICE_TYPE_NONE; |
52 } | 56 } |
53 | 57 |
| 58 // Parses the mirror response header. Its expected format is |
| 59 // "key1=value1,key2=value2,...". |
| 60 MirrorResponseHeaderDictionary ParseMirrorResponseHeader( |
| 61 const std::string& header_value) { |
| 62 std::vector<std::string> fields; |
| 63 if (!Tokenize(header_value, std::string(","), &fields)) |
| 64 return MirrorResponseHeaderDictionary(); |
| 65 |
| 66 MirrorResponseHeaderDictionary dictionary; |
| 67 for (std::vector<std::string>::iterator i = fields.begin(); |
| 68 i != fields.end(); ++i) { |
| 69 std::string field(*i); |
| 70 std::vector<std::string> tokens; |
| 71 if (Tokenize(field, "=", &tokens) != 2) { |
| 72 DLOG(WARNING) << "Unexpected GAIA header filed '" << field << "'."; |
| 73 continue; |
| 74 } |
| 75 dictionary[tokens[0]] = tokens[1]; |
| 76 } |
| 77 return dictionary; |
| 78 } |
| 79 |
| 80 #if !defined(OS_IOS) |
54 // Processes the mirror response header on the UI thread. Currently depending | 81 // Processes the mirror response header on the UI thread. Currently depending |
55 // on the value of |header_value|, it either shows the profile avatar menu, or | 82 // on the value of |header_value|, it either shows the profile avatar menu, or |
56 // opens an incognito window/tab. | 83 // opens an incognito window/tab. |
57 void ProcessMirrorHeaderUIThread( | 84 void ProcessMirrorHeaderUIThread( |
58 int child_id, int route_id, const std::string& header_value) { | 85 int child_id, int route_id, |
| 86 signin::ManageAccountsParams manage_accounts_params) { |
59 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 87 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
60 | 88 |
| 89 signin::GAIAServiceType service_type = manage_accounts_params.service_type; |
| 90 DCHECK_NE(signin::GAIA_SERVICE_TYPE_NONE, service_type); |
| 91 |
61 content::WebContents* web_contents = | 92 content::WebContents* web_contents = |
62 tab_util::GetWebContentsByID(child_id, route_id); | 93 tab_util::GetWebContentsByID(child_id, route_id); |
63 if (!web_contents) | 94 if (!web_contents) |
64 return; | 95 return; |
65 | 96 |
66 signin::GAIAServiceType service_type = | |
67 GetGAIAServiceTypeFromHeader(header_value); | |
68 | |
69 #if !defined(OS_ANDROID) | 97 #if !defined(OS_ANDROID) |
70 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); | 98 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); |
71 if (browser) { | 99 if (browser) { |
72 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { | 100 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { |
73 chrome::NewIncognitoWindow(browser); | 101 chrome::NewIncognitoWindow(browser); |
74 } else { | 102 } else { |
75 browser->window()->ShowAvatarBubbleFromAvatarButton( | 103 browser->window()->ShowAvatarBubbleFromAvatarButton( |
76 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT, | 104 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT, |
77 service_type); | 105 service_type); |
78 } | 106 } |
79 } | 107 } |
80 #else // defined(OS_ANDROID) | 108 #else // defined(OS_ANDROID) |
81 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { | 109 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { |
82 web_contents->OpenURL(content::OpenURLParams( | 110 web_contents->OpenURL(content::OpenURLParams( |
83 GURL(chrome::kChromeUINativeNewTabURL), content::Referrer(), | 111 GURL(chrome::kChromeUINativeNewTabURL), content::Referrer(), |
84 OFF_THE_RECORD, content::PAGE_TRANSITION_AUTO_TOPLEVEL, false)); | 112 OFF_THE_RECORD, content::PAGE_TRANSITION_AUTO_TOPLEVEL, false)); |
85 } else { | 113 } else { |
86 AccountManagementScreenHelper::OpenAccountManagementScreen( | 114 AccountManagementScreenHelper::OpenAccountManagementScreen( |
87 Profile::FromBrowserContext(web_contents->GetBrowserContext()), | 115 Profile::FromBrowserContext(web_contents->GetBrowserContext()), |
88 service_type); | 116 service_type); |
89 } | 117 } |
90 #endif // OS_ANDROID | 118 #endif // OS_ANDROID |
91 } | 119 } |
| 120 #endif // !defined(OS_IOS) |
92 | 121 |
93 bool IsDriveOrigin(const GURL& url) { | 122 bool IsDriveOrigin(const GURL& url) { |
94 if (!url.SchemeIsSecure()) | 123 if (!url.SchemeIsSecure()) |
95 return false; | 124 return false; |
96 | 125 |
97 const GURL kGoogleDriveURL("https://drive.google.com"); | 126 const GURL kGoogleDriveURL("https://drive.google.com"); |
98 const GURL kGoogleDocsURL("https://docs.google.com"); | 127 const GURL kGoogleDocsURL("https://docs.google.com"); |
99 return url == kGoogleDriveURL || url == kGoogleDocsURL; | 128 return url == kGoogleDriveURL || url == kGoogleDocsURL; |
100 } | 129 } |
101 | 130 |
102 } // empty namespace | 131 } // empty namespace |
103 | 132 |
104 namespace signin { | 133 namespace signin { |
105 | 134 |
106 void AppendMirrorRequestHeaderIfPossible( | 135 bool AppendMirrorRequestHeaderIfPossible( |
107 net::URLRequest* request, | 136 net::URLRequest* request, |
108 const GURL& redirect_url, | 137 const GURL& redirect_url, |
109 ProfileIOData* io_data, | 138 ProfileIOData* io_data, |
110 int child_id, | 139 int child_id, |
111 int route_id) { | 140 int route_id) { |
112 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 141 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
113 | 142 |
114 if (io_data->IsOffTheRecord() || | 143 if (io_data->IsOffTheRecord() || |
115 io_data->google_services_username()->GetValue().empty()) { | 144 io_data->google_services_username()->GetValue().empty()) { |
116 return; | 145 return false; |
117 } | 146 } |
118 | 147 |
119 // Only set the header for Drive always, and other Google properties if | 148 // Only set the header for Drive always, and other Google properties if |
120 // new-profile-management is enabled. | 149 // new-profile-management is enabled. |
121 // Vasquette, which is integrated with most Google properties, needs the | 150 // Vasquette, which is integrated with most Google properties, needs the |
122 // header to redirect certain user actions to Chrome native UI. Drive needs | 151 // header to redirect certain user actions to Chrome native UI. Drive needs |
123 // the header to tell if the current user is connected. The drive path is a | 152 // the header to tell if the current user is connected. The drive path is a |
124 // temporary workaround until the more generic chrome.principals API is | 153 // temporary workaround until the more generic chrome.principals API is |
125 // available. | 154 // available. |
126 const GURL& url = redirect_url.is_empty() ? request->url() : redirect_url; | 155 const GURL& url = redirect_url.is_empty() ? request->url() : redirect_url; |
127 GURL origin(url.GetOrigin()); | 156 GURL origin(url.GetOrigin()); |
128 bool is_new_profile_management = switches::IsNewProfileManagement(); | 157 bool is_new_profile_management = switches::IsNewProfileManagement(); |
129 bool is_google_url = | 158 bool is_google_url = |
130 !switches::IsEnableWebBasedSignin() && | 159 !switches::IsEnableWebBasedSignin() && |
131 is_new_profile_management && | 160 is_new_profile_management && |
132 google_util::IsGoogleDomainUrl( | 161 google_util::IsGoogleDomainUrl( |
133 url, | 162 url, |
134 google_util::ALLOW_SUBDOMAIN, | 163 google_util::ALLOW_SUBDOMAIN, |
135 google_util::DISALLOW_NON_STANDARD_PORTS); | 164 google_util::DISALLOW_NON_STANDARD_PORTS); |
136 if (!is_google_url && !IsDriveOrigin(origin)) | 165 if (!is_google_url && !IsDriveOrigin(origin)) |
137 return; | 166 return false; |
138 | 167 |
139 std::string account_id(io_data->google_services_account_id()->GetValue()); | 168 std::string account_id(io_data->google_services_account_id()->GetValue()); |
140 | 169 |
141 int profile_mode_mask = PROFILE_MODE_DEFAULT; | 170 int profile_mode_mask = PROFILE_MODE_DEFAULT; |
142 // TODO(guohui): Needs to check for parent control as well. | 171 // TODO(guohui): Needs to check for parent control as well. |
143 if (io_data->incognito_availibility()->GetValue() == | 172 if (io_data->incognito_availibility()->GetValue() == |
144 IncognitoModePrefs::DISABLED) { | 173 IncognitoModePrefs::DISABLED) { |
145 profile_mode_mask |= PROFILE_MODE_INCOGNITO_DISABLED; | 174 profile_mode_mask |= PROFILE_MODE_INCOGNITO_DISABLED; |
146 } | 175 } |
147 | 176 |
148 // TODO(guohui): needs to make a new flag for enabling account consistency. | 177 // TODO(guohui): needs to make a new flag for enabling account consistency. |
149 std::string header_value(base::StringPrintf("%s=%s,%s=%s,%s=%s", | 178 std::string header_value(base::StringPrintf("%s=%s,%s=%s,%s=%s", |
150 kGaiaIdAttrName, account_id.c_str(), | 179 kGaiaIdAttrName, account_id.c_str(), |
151 kProfileModeAttrName, base::IntToString(profile_mode_mask).c_str(), | 180 kProfileModeAttrName, base::IntToString(profile_mode_mask).c_str(), |
152 kEnableAccountConsistencyAttrName, | 181 kEnableAccountConsistencyAttrName, |
153 is_new_profile_management ? "true" : "false")); | 182 is_new_profile_management ? "true" : "false")); |
154 request->SetExtraRequestHeaderByName( | 183 request->SetExtraRequestHeaderByName( |
155 kChromeConnectedHeader, header_value, false); | 184 kChromeConnectedHeader, header_value, false); |
| 185 return true; |
| 186 } |
| 187 |
| 188 ManageAccountsParams GetManageAccountsParams(net::URLRequest* request, |
| 189 ProfileIOData* io_data) { |
| 190 ManageAccountsParams params; |
| 191 params.service_type = GAIA_SERVICE_TYPE_NONE; |
| 192 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| 193 if (!gaia::IsGaiaSignonRealm(request->url().GetOrigin())) |
| 194 return params; |
| 195 |
| 196 std::string header_value; |
| 197 if (!request->response_headers()->GetNormalizedHeader( |
| 198 kChromeManageAccountsHeader, &header_value)) { |
| 199 return params; |
| 200 } |
| 201 |
| 202 DCHECK(switches::IsNewProfileManagement() && !io_data->IsOffTheRecord()); |
| 203 |
| 204 MirrorResponseHeaderDictionary header_dictionary = |
| 205 ParseMirrorResponseHeader(header_value); |
| 206 if (header_dictionary.count("action")) { |
| 207 params.service_type = |
| 208 GetGAIAServiceTypeFromHeader(header_dictionary["action"]); |
| 209 } |
| 210 return params; |
156 } | 211 } |
157 | 212 |
158 void ProcessMirrorResponseHeaderIfExists( | 213 void ProcessMirrorResponseHeaderIfExists( |
159 net::URLRequest* request, | 214 net::URLRequest* request, |
160 ProfileIOData* io_data, | 215 ProfileIOData* io_data, |
161 int child_id, | 216 int child_id, |
162 int route_id) { | 217 int route_id) { |
| 218 #if defined(OS_IOS) |
| 219 NOTREACHED(); |
| 220 #else |
163 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | 221 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| 222 ManageAccountsParams params = GetManageAccountsParams(request, io_data); |
| 223 if (params.service_type == GAIA_SERVICE_TYPE_NONE) |
| 224 return; |
164 | 225 |
165 std::string header_value; | 226 content::BrowserThread::PostTask( |
166 if (gaia::IsGaiaSignonRealm(request->url().GetOrigin()) && | 227 content::BrowserThread::UI, FROM_HERE, |
167 request->response_headers()->GetNormalizedHeader( | 228 base::Bind(ProcessMirrorHeaderUIThread, child_id, route_id, params)); |
168 kChromeManageAccountsHeader, &header_value)) { | 229 #endif // defined(OS_IOS) |
169 DCHECK(switches::IsNewProfileManagement() && | |
170 !io_data->IsOffTheRecord()); | |
171 content::BrowserThread::PostTask( | |
172 content::BrowserThread::UI, FROM_HERE, | |
173 base::Bind(ProcessMirrorHeaderUIThread, child_id, route_id, | |
174 header_value)); | |
175 } | |
176 } | 230 } |
177 | 231 |
178 } // namespace signin | 232 } // namespace signin |
OLD | NEW |