Chromium Code Reviews| 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 const signin::GAIAServiceType& gaia_service_type) { | |
|
Roger Tawa OOO till Jul 10th
2014/06/04 00:20:49
Why a reference?
msarda
2014/06/04 00:43:28
Done.
| |
| 59 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 87 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 88 DCHECK_NE(signin::GAIA_SERVICE_TYPE_NONE, gaia_service_type); | |
| 60 | 89 |
| 61 content::WebContents* web_contents = | 90 content::WebContents* web_contents = |
| 62 tab_util::GetWebContentsByID(child_id, route_id); | 91 tab_util::GetWebContentsByID(child_id, route_id); |
| 63 if (!web_contents) | 92 if (!web_contents) |
| 64 return; | 93 return; |
| 65 | 94 |
| 66 signin::GAIAServiceType service_type = | |
| 67 GetGAIAServiceTypeFromHeader(header_value); | |
| 68 | |
| 69 #if !defined(OS_ANDROID) | 95 #if !defined(OS_ANDROID) |
| 70 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); | 96 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); |
| 71 if (browser) { | 97 if (browser) { |
| 72 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { | 98 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { |
| 73 chrome::NewIncognitoWindow(browser); | 99 chrome::NewIncognitoWindow(browser); |
| 74 } else { | 100 } else { |
| 75 browser->window()->ShowAvatarBubbleFromAvatarButton( | 101 browser->window()->ShowAvatarBubbleFromAvatarButton( |
| 76 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT, | 102 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT, |
| 77 service_type); | 103 service_type); |
| 78 } | 104 } |
| 79 } | 105 } |
| 80 #else // defined(OS_ANDROID) | 106 #else // defined(OS_ANDROID) |
| 81 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { | 107 if (service_type == signin::GAIA_SERVICE_TYPE_INCOGNITO) { |
| 82 web_contents->OpenURL(content::OpenURLParams( | 108 web_contents->OpenURL(content::OpenURLParams( |
| 83 GURL(chrome::kChromeUINativeNewTabURL), content::Referrer(), | 109 GURL(chrome::kChromeUINativeNewTabURL), content::Referrer(), |
| 84 OFF_THE_RECORD, content::PAGE_TRANSITION_AUTO_TOPLEVEL, false)); | 110 OFF_THE_RECORD, content::PAGE_TRANSITION_AUTO_TOPLEVEL, false)); |
| 85 } else { | 111 } else { |
| 112 // TODO(mlerman): pass service_type to android logic for UMA metrics | |
| 113 // that will eventually be installed there. | |
| 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 = ParseMirrorResponseHeader( | |
| 205 header_value); | |
|
Roger Tawa OOO till Jul 10th
2014/06/04 00:20:49
nit: better to wrap like this?
MirrorResponseHead
msarda
2014/06/04 00:43:28
Done.
| |
| 206 if (!header_dictionary.count("action")) | |
| 207 return params; | |
| 208 params.service_type = | |
| 209 GetGAIAServiceTypeFromHeader(header_dictionary["action"]); | |
|
Roger Tawa OOO till Jul 10th
2014/06/04 00:20:49
Better to reverse condition?
if (header_dictionar
msarda
2014/06/04 00:43:28
Done.
| |
| 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, |
| 168 kChromeManageAccountsHeader, &header_value)) { | 229 params.service_type)); |
| 169 DCHECK(switches::IsNewProfileManagement() && | 230 #endif // defined(OS_IOS) |
| 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 } | 231 } |
| 177 | 232 |
| 178 } // namespace signin | 233 } // namespace signin |
| OLD | NEW |