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 "chrome/browser/signin/signin_header_helper.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "chrome/browser/google/google_util.h"
9 #include "chrome/browser/prefs/incognito_mode_prefs.h"
10 #include "chrome/browser/profiles/profile_io_data.h"
11 #include "chrome/browser/tab_contents/tab_util.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #include "chrome/common/url_constants.h"
14 #include "components/signin/core/common/profile_management_switches.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/web_contents.h"
17 #include "google_apis/gaia/gaia_auth_util.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/url_request/url_request.h"
21 #if defined(OS_ANDROID)
22 #include "chrome/browser/android/signin/account_management_screen_helper.h"
24 #include "chrome/browser/ui/browser_commands.h"
25 #include "chrome/browser/ui/browser_finder.h"
26 #endif // defined(OS_ANDROID)
30 const char kChromeConnectedHeader
[] = "X-Chrome-Connected";
31 const char kChromeManageAccountsHeader
[] = "X-Chrome-Manage-Accounts";
32 const char kGaiaSignoutOptionsIncognito
[] = "SIGNOUTOPTIONS_INCOGNITO";
34 // Processes the mirror response header on the UI thread. Currently depending
35 // on the value of |header_value|, it either shows the profile avatar menu, or
36 // opens an incognito window/tab.
37 void ProcessMirrorHeaderUIThread(
38 int child_id
, int route_id
, const std::string
& header_value
) {
39 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
41 content::WebContents
* web_contents
=
42 tab_util::GetWebContentsByID(child_id
, route_id
);
46 #if !defined(OS_ANDROID)
47 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents
);
49 if (header_value
== kGaiaSignoutOptionsIncognito
) {
50 chrome::NewIncognitoWindow(browser
);
52 browser
->window()->ShowAvatarBubbleFromAvatarButton(
53 BrowserWindow::AVATAR_BUBBLE_MODE_ACCOUNT_MANAGEMENT
);
56 #else // defined(OS_ANDROID)
57 if (header_value
== kGaiaSignoutOptionsIncognito
) {
58 web_contents
->OpenURL(content::OpenURLParams(
59 GURL(chrome::kChromeUINativeNewTabURL
), content::Referrer(),
60 OFF_THE_RECORD
, content::PAGE_TRANSITION_AUTO_TOPLEVEL
, false));
62 AccountManagementScreenHelper::OpenAccountManagementScreen(
63 Profile::FromBrowserContext(web_contents
->GetBrowserContext()));
68 bool IsDriveOrigin(const GURL
& url
) {
69 if (!url
.SchemeIsSecure())
72 const GURL
kGoogleDriveURL("https://drive.google.com");
73 const GURL
kGoogleDocsURL("https://docs.google.com");
74 return url
== kGoogleDriveURL
|| url
== kGoogleDocsURL
;
81 void AppendMirrorRequestHeaderIfPossible(
82 net::URLRequest
* request
,
83 const GURL
& redirect_url
,
84 ProfileIOData
* io_data
,
87 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO
));
89 if (io_data
->IsOffTheRecord() ||
90 io_data
->google_services_username()->GetValue().empty()) {
94 // Only set the header for Drive always, and other Google properties if
95 // new-profile-management is enabled.
96 // Vasquette, which is integrated with most Google properties, needs the
97 // header to redirect certain user actions to Chrome native UI. Drive needs
98 // the header to tell if the current user is connected. The drive path is a
99 // temporary workaround until the more generic chrome.principals API is
101 const GURL
& url
= redirect_url
.is_empty() ? request
->url() : redirect_url
;
102 GURL
origin(url
.GetOrigin());
104 !switches::IsEnableWebBasedSignin() &&
105 switches::IsNewProfileManagement() &&
106 google_util::IsGoogleDomainUrl(
108 google_util::ALLOW_SUBDOMAIN
,
109 google_util::DISALLOW_NON_STANDARD_PORTS
);
110 if (!is_google_url
&& !IsDriveOrigin(origin
))
113 std::string
account_id(io_data
->google_services_account_id()->GetValue());
115 int profile_mode_mask
= PROFILE_MODE_DEFAULT
;
116 // TODO(guohui): Needs to check for parent control as well.
117 if (io_data
->incognito_availibility()->GetValue() ==
118 IncognitoModePrefs::DISABLED
) {
119 profile_mode_mask
|= PROFILE_MODE_INCOGNITO_DISABLED
;
122 std::string header_value
=
123 account_id
+ ":" + base::IntToString(profile_mode_mask
);
124 request
->SetExtraRequestHeaderByName(
125 kChromeConnectedHeader
, header_value
, false);
128 void ProcessMirrorResponseHeaderIfExists(
129 net::URLRequest
* request
,
130 ProfileIOData
* io_data
,
133 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO
));
135 std::string header_value
;
136 if (gaia::IsGaiaSignonRealm(request
->url().GetOrigin()) &&
137 request
->response_headers()->GetNormalizedHeader(
138 kChromeManageAccountsHeader
, &header_value
)) {
139 DCHECK(switches::IsNewProfileManagement() &&
140 !io_data
->IsOffTheRecord());
141 content::BrowserThread::PostTask(
142 content::BrowserThread::UI
, FROM_HERE
,
143 base::Bind(ProcessMirrorHeaderUIThread
, child_id
, route_id
,
148 } // namespace signin