diff --git a/chrome/browser/chromeos/login/oobe_base_test.cc b/chrome/browser/chromeos/login/oobe_base_test.cc index 7f6b75d599198a..26d53b55b7ad79 100644 --- a/chrome/browser/chromeos/login/oobe_base_test.cc +++ b/chrome/browser/chromeos/login/oobe_base_test.cc @@ -107,6 +107,15 @@ void OobeBaseTest::SetUpCommandLine(CommandLine* command_line) { command_line->AppendSwitchASCII(::switches::kGoogleApisUrl, gaia_url.spec()); fake_gaia_->Initialize(); + + // Allow GAIA to be served over http. + base::FilePath test_data_dir; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir)); + command_line->AppendSwitchASCII( + chromeos::switches::kGAIAAuthExtensionManifest, + test_data_dir.Append("login") + .Append("gaia_auth_http_manifest.json") + .value()); } void OobeBaseTest::SimulateNetworkOffline() { diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc index 886e61352ff1bd..3941fbbb280d8d 100644 --- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc +++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc @@ -14,6 +14,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/existing_user_controller.h" #include "chrome/browser/chromeos/login/login_display_host_impl.h" +#include "chrome/browser/chromeos/login/test/https_forwarder.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/user.h" #include "chrome/browser/chromeos/login/user_manager.h" @@ -42,6 +43,7 @@ #include "policy/policy_constants.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" using net::test_server::BasicHttpResponse; using net::test_server::HttpRequest; @@ -64,7 +66,8 @@ const char kTestSessionLSIDCookie[] = "fake-session-LSID-cookie"; const char kFirstSAMLUserEmail[] = "bob@example.com"; const char kSecondSAMLUserEmail[] = "alice@example.com"; -const char kNonSAMLUserEmail[] = "carol@example.com"; +const char kHTTPSAMLUserEmail[] = "carol@example.com"; +const char kNonSAMLUserEmail[] = "dan@example.com"; const char kRelayState[] = "RelayState"; @@ -194,10 +197,20 @@ class SamlTest : public InProcessBrowserTest { virtual ~SamlTest() {} virtual void SetUp() OVERRIDE { - // Start embedded test server here so that we can get server base url - // and override Gaia urls in SetupCommandLine. ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + // Start the GAIA https wrapper here so that the GAIA URLs can be pointed at + // it in SetUpCommandLine(). + gaia_https_forwarder_.reset( + new HTTPSForwarder(embedded_test_server()->base_url())); + ASSERT_TRUE(gaia_https_forwarder_->Start()); + + // Start the SAML IdP https wrapper here so that GAIA can be pointed at it + // in SetUpCommandLine(). + saml_https_forwarder_.reset( + new HTTPSForwarder(embedded_test_server()->base_url())); + ASSERT_TRUE(saml_https_forwarder_->Start()); + // Stop IO thread here because no threads are allowed while // spawning sandbox host process. See crbug.com/322732. embedded_test_server()->StopThread(); @@ -215,28 +228,21 @@ class SamlTest : public InProcessBrowserTest { command_line->AppendSwitch(::switches::kDisableBackgroundNetworking); command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); - const GURL& server_url = embedded_test_server()->base_url(); - - std::string gaia_host("gaia"); - GURL::Replacements replace_gaia_host; - replace_gaia_host.SetHostStr(gaia_host); - gaia_url_ = server_url.ReplaceComponents(replace_gaia_host); - - command_line->AppendSwitchASCII(::switches::kGaiaUrl, gaia_url_.spec()); - command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url_.spec()); + const GURL gaia_url = gaia_https_forwarder_->GetURL(""); + command_line->AppendSwitchASCII(::switches::kGaiaUrl, gaia_url.spec()); + command_line->AppendSwitchASCII(::switches::kLsoUrl, gaia_url.spec()); command_line->AppendSwitchASCII(::switches::kGoogleApisUrl, - gaia_url_.spec()); - fake_gaia_.Initialize(); - - std::string saml_idp_host("saml.idp"); - GURL::Replacements replace_saml_idp_host; - replace_saml_idp_host.SetHostStr(saml_idp_host); - GURL saml_idp_url = server_url.ReplaceComponents(replace_saml_idp_host); - saml_idp_url = saml_idp_url.Resolve("/SAML/SSO"); + gaia_url.spec()); - fake_saml_idp_.SetUp(saml_idp_url.path(), gaia_url_); + const GURL saml_idp_url = saml_https_forwarder_->GetURL("SAML"); + fake_saml_idp_.SetUp(saml_idp_url.path(), gaia_url); fake_gaia_.RegisterSamlUser(kFirstSAMLUserEmail, saml_idp_url); fake_gaia_.RegisterSamlUser(kSecondSAMLUserEmail, saml_idp_url); + fake_gaia_.RegisterSamlUser( + kHTTPSAMLUserEmail, + embedded_test_server()->base_url().Resolve("/SAML")); + + fake_gaia_.Initialize(); } virtual void SetUpOnMainThread() OVERRIDE { @@ -364,9 +370,10 @@ class SamlTest : public InProcessBrowserTest { scoped_ptr login_screen_load_observer_; private: - GURL gaia_url_; FakeGaia fake_gaia_; FakeSamlIdp fake_saml_idp_; + scoped_ptr gaia_https_forwarder_; + scoped_ptr saml_https_forwarder_; bool saml_load_injected_; @@ -526,6 +533,17 @@ IN_PROC_BROWSER_TEST_F(SamlTest, PasswordConfirmFlow) { OobeScreenWaiter(OobeDisplay::SCREEN_FATAL_ERROR).Wait(); } +// Verifies that when GAIA attempts to redirect to a SAML IdP served over http, +// not https, the redirect is blocked by CSP and an error message is shown. +IN_PROC_BROWSER_TEST_F(SamlTest, HTTPRedirectDisallowed) { + fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html"); + + WaitForSigninScreen(); + GetLoginDisplay()->ShowSigninScreenForCreds(kHTTPSAMLUserEmail, ""); + + OobeScreenWaiter(OobeDisplay::SCREEN_FATAL_ERROR).Wait(); +} + class SAMLPolicyTest : public SamlTest { public: SAMLPolicyTest(); diff --git a/chrome/browser/chromeos/login/test/https_forwarder.cc b/chrome/browser/chromeos/login/test/https_forwarder.cc new file mode 100644 index 00000000000000..118488ab9d8110 --- /dev/null +++ b/chrome/browser/chromeos/login/test/https_forwarder.cc @@ -0,0 +1,62 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/login/test/https_forwarder.h" + +#include "base/base_paths.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/values.h" +#include "net/test/python_utils.h" + +namespace chromeos { + +HTTPSForwarder::HTTPSForwarder(const GURL& forward_target) + : net::LocalTestServer(net::LocalTestServer::TYPE_HTTPS, + net::LocalTestServer::kLocalhost, + base::FilePath()), + forward_target_(forward_target) { +} + +HTTPSForwarder::~HTTPSForwarder() { +} + +bool HTTPSForwarder::SetPythonPath() const { + if (!net::LocalTestServer::SetPythonPath()) + return false; + + base::FilePath net_testserver_path; + if (!LocalTestServer::GetTestServerPath(&net_testserver_path)) + return false; + AppendToPythonPath(net_testserver_path.DirName()); + + return true; +} + +bool HTTPSForwarder::GetTestServerPath(base::FilePath* testserver_path) const { + base::FilePath source_root_dir; + if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir)) + return false; + + *testserver_path = source_root_dir.Append("chrome") + .Append("browser") + .Append("chromeos") + .Append("login") + .Append("test") + .Append("https_forwarder.py"); + return true; +} + +bool HTTPSForwarder::GenerateAdditionalArguments( + base::DictionaryValue* arguments) const { + base::FilePath source_root_dir; + if (!net::LocalTestServer::GenerateAdditionalArguments(arguments) || + !PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir)) + return false; + + arguments->SetString("forward-target", forward_target_.spec()); + return true; +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/test/https_forwarder.h b/chrome/browser/chromeos/login/test/https_forwarder.h new file mode 100644 index 00000000000000..eaad6fd4a82880 --- /dev/null +++ b/chrome/browser/chromeos/login/test/https_forwarder.h @@ -0,0 +1,37 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_TEST_HTTPS_FORWARDER_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_TEST_HTTPS_FORWARDER_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "net/test/spawned_test_server/local_test_server.h" +#include "url/gurl.h" + +namespace chromeos { + +// An https test server that forwards all requests to another server. This +// allows a server that supports http only to be accessed over https. +class HTTPSForwarder : public net::LocalTestServer { + public: + explicit HTTPSForwarder(const GURL& forward_target); + virtual ~HTTPSForwarder(); + + // net::LocalTestServer: + virtual bool SetPythonPath() const OVERRIDE; + virtual bool GetTestServerPath( + base::FilePath* testserver_path) const OVERRIDE; + virtual bool GenerateAdditionalArguments( + base::DictionaryValue* arguments) const OVERRIDE; + + private: + GURL forward_target_; + + DISALLOW_COPY_AND_ASSIGN(HTTPSForwarder); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_TEST_HTTPS_FORWARDER_H_ diff --git a/chrome/browser/chromeos/login/test/https_forwarder.py b/chrome/browser/chromeos/login/test/https_forwarder.py new file mode 100644 index 00000000000000..eaa0db22b11e7f --- /dev/null +++ b/chrome/browser/chromeos/login/test/https_forwarder.py @@ -0,0 +1,169 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""An https server that forwards requests to another server. This allows a +server that supports http only to be accessed over https. +""" + +import BaseHTTPServer +import os +import SocketServer +import sys +import urllib2 +import urlparse +import testserver_base +import tlslite.api + + +class RedirectSuppressor(urllib2.HTTPErrorProcessor): + """Prevents urllib2 from following http redirects. + + If this class is placed in an urllib2.OpenerDirector's handler chain before + the default urllib2.HTTPRedirectHandler, it will terminate the processing of + responses containing redirect codes (301, 302, 303, 307) before they reach the + default redirect handler. + """ + + def http_response(self, req, response): + return response + + def https_response(self, req, response): + return response + + +class RequestForwarder(BaseHTTPServer.BaseHTTPRequestHandler): + """Handles requests received by forwarding them to the another server.""" + + def do_GET(self): + """Forwards GET requests.""" + self._forward(None) + + def do_POST(self): + """Forwards POST requests.""" + self._forward(self.rfile.read(int(self.headers['Content-Length']))) + + def _forward(self, body): + """Forwards a GET or POST request to another server. + + Args: + body: The request body. This should be |None| for GET requests. + """ + request_url = urlparse.urlparse(self.path) + url = urlparse.urlunparse((self.server.forward_scheme, + self.server.forward_netloc, + self.server.forward_path + request_url[2], + request_url[3], + request_url[4], + request_url[5])) + + headers = dict((key, value) for key, value in dict(self.headers).iteritems() + if key.lower() != 'host') + opener = urllib2.build_opener(RedirectSuppressor) + forward = opener.open(urllib2.Request(url, body, headers)) + + self.send_response(forward.getcode()) + for key, value in dict(forward.info()).iteritems(): + self.send_header(key, value) + self.end_headers() + self.wfile.write(forward.read()) + + +class MultiThreadedHTTPSServer(SocketServer.ThreadingMixIn, + tlslite.api.TLSSocketServerMixIn, + testserver_base.ClientRestrictingServerMixIn, + testserver_base.BrokenPipeHandlerMixIn, + testserver_base.StoppableHTTPServer): + """A multi-threaded version of testserver.HTTPSServer.""" + + def __init__(self, server_address, request_hander_class, pem_cert_and_key): + """Initializes the server. + + Args: + server_address: Server host and port. + request_hander_class: The class that will handle requests to the server. + pem_cert_and_key: Path to file containing the https cert and private key. + """ + self.cert_chain = tlslite.api.X509CertChain().parseChain(pem_cert_and_key) + # Force using only python implementation - otherwise behavior is different + # depending on whether m2crypto Python module is present (error is thrown + # when it is). m2crypto uses a C (based on OpenSSL) implementation under + # the hood. + self.private_key = tlslite.api.parsePEMKey(pem_cert_and_key, + private=True, + implementations=['python']) + + testserver_base.StoppableHTTPServer.__init__(self, + server_address, + request_hander_class) + + def handshake(self, tlsConnection): + """Performs the SSL handshake for an https connection. + + Args: + tlsConnection: The https connection. + Returns: + Whether the SSL handshake succeeded. + """ + try: + self.tlsConnection = tlsConnection + tlsConnection.handshakeServer(certChain=self.cert_chain, + privateKey=self.private_key) + tlsConnection.ignoreAbruptClose = True + return True + except: + return False + + +class ServerRunner(testserver_base.TestServerRunner): + """Runner that starts an https server which forwards requests to another + server. + """ + + def create_server(self, server_data): + """Performs the SSL handshake for an https connection. + + Args: + server_data: Dictionary that holds information about the server. + Returns: + The started server. + """ + port = self.options.port + host = self.options.host + + if not os.path.isfile(self.options.cert_and_key_file): + raise testserver_base.OptionError( + 'Specified server cert file not found: ' + + self.options.cert_and_key_file) + pem_cert_and_key = open(self.options.cert_and_key_file).read() + + server = MultiThreadedHTTPSServer((host, port), + RequestForwarder, + pem_cert_and_key) + print 'HTTPS server started on %s:%d...' % (host, server.server_port) + + forward_target = urlparse.urlparse(self.options.forward_target) + server.forward_scheme = forward_target[0] + server.forward_netloc = forward_target[1] + server.forward_path = forward_target[2].rstrip('/') + server.forward_host = forward_target.hostname + if forward_target.port: + server.forward_host += ':' + str(forward_target.port) + server_data['port'] = server.server_port + return server + + def add_options(self): + """Specifies the command-line options understood by the server.""" + testserver_base.TestServerRunner.add_options(self) + self.option_parser.add_option('--https', action='store_true', + help='Ignored (provided for compatibility ' + 'only).') + self.option_parser.add_option('--cert-and-key-file', help='The path to the ' + 'file containing the certificate and private ' + 'key for the server in PEM format.') + self.option_parser.add_option('--forward-target', help='The URL prefix to ' + 'which requests will be forwarded.') + + +if __name__ == '__main__': + sys.exit(ServerRunner().main()) diff --git a/chrome/browser/chromeos/login/webui_login_view.cc b/chrome/browser/chromeos/login/webui_login_view.cc index 23dac9eaeddfae..1aeb6b52f99e3d 100644 --- a/chrome/browser/chromeos/login/webui_login_view.cc +++ b/chrome/browser/chromeos/login/webui_login_view.cc @@ -420,9 +420,9 @@ void WebUILoginView::DidFailProvisionalLoad( if (frame_unique_name != base::UTF8ToUTF16("gaia-frame")) return; - base::FundamentalValue error_value(-error_code); GetWebUI()->CallJavascriptFunction("login.GaiaSigninScreen.onFrameError", - error_value); + base::FundamentalValue(-error_code), + base::StringValue(validated_url.spec())); } void WebUILoginView::OnLoginPromptVisible() { diff --git a/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc b/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc index 2c52405b98c749..3618484bd7ee02 100644 --- a/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc +++ b/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc @@ -4,7 +4,11 @@ #include "chrome/browser/extensions/signin/gaia_auth_extension_loader.h" +#include + #include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/logging.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" @@ -15,6 +19,7 @@ #include "grit/browser_resources.h" #if defined(OS_CHROMEOS) +#include "base/file_util.h" #include "chrome/browser/chromeos/system/input_device_settings.h" #include "chromeos/chromeos_constants.h" #include "chromeos/chromeos_switches.h" @@ -43,15 +48,25 @@ void LoadGaiaAuthExtension(Profile* profile) { return; } - int manifest_resource_id = IDR_GAIA_AUTH_MANIFEST; - #if defined(OS_CHROMEOS) + if (command_line->HasSwitch(chromeos::switches::kGAIAAuthExtensionManifest)) { + const base::FilePath manifest_path = command_line->GetSwitchValuePath( + chromeos::switches::kGAIAAuthExtensionManifest); + std::string manifest; + if (!base::ReadFileToString(manifest_path, &manifest)) + NOTREACHED(); + component_loader->Add(manifest, + base::FilePath(FILE_PATH_LITERAL("gaia_auth"))); + return; + } + + int manifest_resource_id = IDR_GAIA_AUTH_MANIFEST; if (chromeos::system::keyboard_settings::ForceKeyboardDrivenUINavigation()) manifest_resource_id = IDR_GAIA_AUTH_KEYBOARD_MANIFEST; else if (!command_line->HasSwitch(chromeos::switches::kDisableSamlSignin)) manifest_resource_id = IDR_GAIA_AUTH_SAML_MANIFEST; #else - manifest_resource_id = IDR_GAIA_AUTH_INLINE_MANIFEST; + int manifest_resource_id = IDR_GAIA_AUTH_INLINE_MANIFEST; #endif component_loader->Add(manifest_resource_id, diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index 539dd0f0fccd01..41f5b56603c887 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js @@ -18,6 +18,10 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { /** @const */ var HELP_TOPIC_ENTERPRISE_REPORTING = 2535613; + /** @const */ var NET_ERROR_ABORTED = 3; + + /** @const */ var NET_ERROR_DISALLOWED_URL_SCHEME = 301; + return { EXTERNAL_API: [ 'loadAuthExtension', @@ -563,10 +567,24 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { /** * Handler for iframe's error notification coming from the outside. - * For more info see C++ class 'SnifferObserver' which calls this method. + * For more info see C++ class 'WebUILoginView' which calls this method. * @param {number} error Error code. - */ - onFrameError: function(error) { + * @param {string} url The URL that failed to load. + */ + onFrameError: function(error, url) { + // Chrome OS requires that the entire authentication flow use https. If + // GAIA attempts to redirect to an http URL, the load will be blocked by + // CSP. Show a fatal error in this case. + // Some tests deviate from the above by disabling the CSP and using a + // mock GAIA implementation served over http. If an http URL fails to load + // in such a test, it has nothing to do with CSP and should not cause a + // fatal error to be shown. + if (error == NET_ERROR_ABORTED && + url.indexOf('http://') == 0 && + this.gaiaAuthParams_.gaiaUrl.indexOf('https://') == 0) { + error = NET_ERROR_DISALLOWED_URL_SCHEME; + this.showFatalAuthError(); + } this.error_ = error; chrome.send('frameLoadingCompleted', [this.error_]); }, diff --git a/chrome/browser/resources/gaia_auth/manifest_saml.json b/chrome/browser/resources/gaia_auth/manifest_saml.json index c30bdaa9f0fec6..2a46e34e9d04db 100644 --- a/chrome/browser/resources/gaia_auth/manifest_saml.json +++ b/chrome/browser/resources/gaia_auth/manifest_saml.json @@ -16,7 +16,7 @@ "all_frames": true } ], - "content_security_policy": "default-src 'self'; script-src 'self'; frame-src *; style-src 'self' 'unsafe-inline'", + "content_security_policy": "default-src 'self'; script-src 'self'; frame-src https:; style-src 'self' 'unsafe-inline'", "description": "GAIA Component Extension", "web_accessible_resources": [ "main.css", diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index daa681d4db6290..fc651c0edfb8e3 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1069,6 +1069,8 @@ 'browser/chromeos/login/screens/mock_update_screen.h', 'browser/chromeos/login/screens/network_screen_browsertest.cc', 'browser/chromeos/login/screens/update_screen_browsertest.cc', + 'browser/chromeos/login/test/https_forwarder.cc', + 'browser/chromeos/login/test/https_forwarder.h', 'browser/chromeos/login/test_login_utils.cc', 'browser/chromeos/login/test_login_utils.h', 'browser/chromeos/login/user_adding_screen_browsertest.cc', diff --git a/chrome/test/data/login/gaia_auth_http_manifest.json b/chrome/test/data/login/gaia_auth_http_manifest.json new file mode 100644 index 00000000000000..c30bdaa9f0fec6 --- /dev/null +++ b/chrome/test/data/login/gaia_auth_http_manifest.json @@ -0,0 +1,38 @@ +{ + // chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/ + "key": "MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC4L17nAfeTd6Xhtx96WhQ6DSr8KdHeQmfzgCkieKLCgUkWdwB9G1DCuh0EPMDn1MdtSwUAT7xE36APEzi0X/UpKjOVyX8tCC3aQcLoRAE0aJAvCcGwK7qIaQaczHmHKvPC2lrRdzSoMMTC5esvHX+ZqIBMi123FOL0dGW6OPKzIwIBIw==", + "name": "GaiaAuthExtension", + "version": "0.0.1", + "manifest_version": 2, + "background" : { + "scripts": ["background.js", "channel.js"] + }, + "content_scripts": [ + { + "matches": [ + "" + ], + "js": ["channel.js", "saml_injected.js"], + "all_frames": true + } + ], + "content_security_policy": "default-src 'self'; script-src 'self'; frame-src *; style-src 'self' 'unsafe-inline'", + "description": "GAIA Component Extension", + "web_accessible_resources": [ + "main.css", + "main.html", + "main.js", + "offline.css", + "offline.html", + "offline.js", + "success.html", + "success.js", + "util.js" + ], + "permissions": [ + "", + "background", + "webRequest", + "webRequestBlocking" + ] +} diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc index ca1dc4a66e00a0..2c447e72107428 100644 --- a/chromeos/chromeos_switches.cc +++ b/chromeos/chromeos_switches.cc @@ -204,6 +204,9 @@ const char kDisableUserImageSync[] = "disable-user-image-sync"; // Disables SAML sigin support. const char kDisableSamlSignin[] = "disable-saml-signin"; +// Overrides the manifest of the GAIA auth extension with the given file. +const char kGAIAAuthExtensionManifest[] = "gaia-auth-extension-manifest"; + // Disables new first-run overlay UI. const char kDisableFirstRunUI[] = "disable-first-run-ui"; diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h index f8db04e6702023..d70af747430766 100644 --- a/chromeos/chromeos_switches.h +++ b/chromeos/chromeos_switches.h @@ -77,6 +77,7 @@ CHROMEOS_EXPORT extern const char kDisableFirstRunUI[]; CHROMEOS_EXPORT extern const char kForceFirstRunUI[]; CHROMEOS_EXPORT extern const char kEnableFirstRunUITransitions[]; CHROMEOS_EXPORT extern const char kDisableSamlSignin[]; +CHROMEOS_EXPORT extern const char kGAIAAuthExtensionManifest[]; CHROMEOS_EXPORT extern const char kTestAutoUpdateUI[]; CHROMEOS_EXPORT extern const char kEnableSupervisedPasswordSync[];