# Copyright 2015 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging from autotest_lib.client.cros import httpd from autotest_lib.client.common_lib import error from autotest_lib.client.cros import enterprise_policy_base POLICY_NAME = 'URLWhitelist' URL_HOST = 'http://localhost' URL_PORT = 8080 URL_BASE = '%s:%d/%s' % (URL_HOST, URL_PORT, 'test_data') BLOCKED_URLS_LIST = [URL_BASE + website for website in ['/website1.html', '/website2.html', '/website3.html']] SINGLE_WHITELISTED_FILE_DATA = BLOCKED_URLS_LIST[:1] MULTIPLE_WHITELISTED_FILES_DATA = BLOCKED_URLS_LIST[:2] BLOCKED_USER_MESSAGE = 'Webpage Blocked' BLOCKED_ERROR_MESSAGE = 'ERR_BLOCKED_BY_ADMINISTRATOR' SUPPORTING_POLICIES = {'URLBlacklist': BLOCKED_URLS_LIST} class policy_URLWhitelist(enterprise_policy_base.EnterprisePolicyTest): """ Test effect of URLWhitleist policy on Chrome OS behavior. Navigate to all the websites in the BLOCKED_URLS_LIST. Verify that the websites specified by the URLWhitelist policy value are not blocked. Also verify that the websites not in the URLWhitelist policy value are blocked. Two TEST_CASES (SingleWhitelistedFile, MultipleWhitelistedFiles) are designed to verify that the functionality works regardless of whether a a SINGLE website is specified in the URLWhitelist policy or if MULTIPLE websites are specified. The third TEST_CASE (NotSet) is designed to verify that all of the websites are blocked since the URLWhitelistlist policy is set to None. The test case shall pass if the URLs that are part of the URLWhitelist policy value are not blocked. The test case shall also pass if the URLs that are not part of the URLWhitelist policy value are blocked. The test case shall fail if the above behavior is not enforced. """ version = 1 TEST_CASES = { 'NotSet': '', 'SingleWhitelistedFile': SINGLE_WHITELISTED_FILE_DATA, 'MultipleWhitelistedFiles': MULTIPLE_WHITELISTED_FILES_DATA } def initialize(self, args=()): super(policy_URLWhitelist, self).initialize(args) self.start_webserver(URL_PORT) def _navigate_to_website(self, url): """ Open a new tab in the browser and navigate to the URL. @param url: the website that the browser is navigated to. @returns: a chrome browser tab navigated to the URL. """ tab = self.cr.browser.tabs.New() logging.info('Navigating to URL:%s', url) try: tab.Navigate(url, timeout=10) except Exception, err: logging.error('Timeout Exception in navigating URL: %s\n %s', url, err) tab.WaitForDocumentReadyStateToBeComplete() return tab def _scrape_text_from_website(self, tab): """ Returns a list of the the text content displayed on the page matching the page_scrape_cmd filter. @param tab: tab containing the website to be parsed. @raises: TestFail if the expected text content was not found on the page. """ parsed_message_string = '' parsed_message_list = [] page_scrape_cmd = 'document.getElementById("main-message").innerText;' try: parsed_message_string = tab.EvaluateJavaScript(page_scrape_cmd) except Exception as err: raise error.TestFail('Unable to find the expected ' 'text content on the test ' 'page: %s\n %r'%(tab.url, err)) logging.info('Parsed message:%s', parsed_message_string) parsed_message_list = [str(word) for word in parsed_message_string.split('\n') if word] return parsed_message_list def _is_url_blocked(self, url): """ Returns True if the URL is blocked else returns False. @param url: The URL to be checked whether it is blocked. """ parsed_message_list = [] tab = self._navigate_to_website(url) parsed_message_list = self._scrape_text_from_website(tab) if len(parsed_message_list) == 2 and \ parsed_message_list[0] == 'Website enabled' and \ parsed_message_list[1] == 'Website is enabled': return False # Check if the accurate user error message displayed on the error page. if parsed_message_list[0] != BLOCKED_USER_MESSAGE or \ parsed_message_list[1] != BLOCKED_ERROR_MESSAGE: logging.warning('The Blocked page user notification ' 'messages, %s and %s are not displayed on ' 'the blocked page. The messages may have ' 'been modified. Please check and update the ' 'messages in this file accordingly.', BLOCKED_USER_MESSAGE, BLOCKED_ERROR_MESSAGE) return True def _test_URLWhitelist(self, policy_value, policies_json): """ Verify CrOS enforces URLWhitelist policy value. Navigate to all the websites in the BLOCKED_URLS_LIST. Verify that the websites specified by the URLWhitelist policy value are not blocked. Also verify that the websites not in the URLWhitelist policy value are blocked. @param policy_value: policy value expected on chrome://policy page. @param policies_json: policy JSON data to send to the fake DM server. @raises: TestFail if url is blocked/not blocked based on the corresponding policy values. """ url_is_blocked = None logging.info('Running _test_Whitelist(%s, %s)', policy_value, policies_json) self.setup_case(POLICY_NAME, policy_value, policies_json) for url in BLOCKED_URLS_LIST: url_is_blocked = self._is_url_blocked(url) if policy_value: if url in policy_value and url_is_blocked: raise error.TestFail('The URL %s should have been allowed' ' by policy, but it was blocked' % url) elif url not in policy_value and not url_is_blocked: raise error.TestFail('The URL %s should have been blocked' ' by policy, but it was allowed' % url) elif not url_is_blocked: raise error.TestFail('The URL %s should have been blocked' 'by policy, but it was allowed' % url) def _run_test_case(self, case): """ Setup and run the test configured for the specified test case. Set the expected |policy_value| and |policies_json| data based on the test |case|. If the user specified an expected |value| in the command line args, then use it to set the |policy_value| and blank out the |policies_json|. @param case: Name of the test case to run. """ policy_value = None policies_json = None if self.is_value_given: # If |value| was given in the command line args, then set expected # |policy_value| to the given value, and |policies_json| to None. policy_value = self.value policies_json = None else: # Otherwise, set expected |policy_value| and setup |policies_json| # data to the values required by the specified test |case|. policies_json = SUPPORTING_POLICIES.copy() if not self.TEST_CASES[case]: policy_value = None else: policy_value = ','.join(self.TEST_CASES[case]) policies_json.update({'URLWhitelist': self.TEST_CASES[case]}) # Run test using the values configured for the test case. self._test_URLWhitelist(policy_value, policies_json) def run_once(self): self.run_once_impl(self._run_test_case)