1 # Copyright 2015 The Chromium OS 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. 4 5 import logging 6 7 from autotest_lib.client.cros import httpd 8 from autotest_lib.client.common_lib import error 9 from autotest_lib.client.cros import enterprise_policy_base 10 11 POLICY_NAME = 'URLWhitelist' 12 URL_HOST = 'http://localhost' 13 URL_PORT = 8080 14 URL_BASE = '%s:%d/%s' % (URL_HOST, URL_PORT, 'test_data') 15 BLOCKED_URLS_LIST = [URL_BASE + website for website in 16 ['/website1.html', 17 '/website2.html', 18 '/website3.html']] 19 SINGLE_WHITELISTED_FILE_DATA = BLOCKED_URLS_LIST[:1] 20 MULTIPLE_WHITELISTED_FILES_DATA = BLOCKED_URLS_LIST[:2] 21 BLOCKED_USER_MESSAGE = 'Webpage Blocked' 22 BLOCKED_ERROR_MESSAGE = 'ERR_BLOCKED_BY_ADMINISTRATOR' 23 SUPPORTING_POLICIES = {'URLBlacklist': BLOCKED_URLS_LIST} 24 25 26 class policy_URLWhitelist(enterprise_policy_base.EnterprisePolicyTest): 27 """ 28 Test effect of URLWhitleist policy on Chrome OS behavior. 29 30 Navigate to all the websites in the BLOCKED_URLS_LIST. Verify that the 31 websites specified by the URLWhitelist policy value are not blocked. 32 Also verify that the websites not in the URLWhitelist policy 33 value are blocked. 34 35 Two TEST_CASES (SingleWhitelistedFile, MultipleWhitelistedFiles) are 36 designed to verify that the functionality works regardless of whether a 37 a SINGLE website is specified in the URLWhitelist policy or if MULTIPLE 38 websites are specified. 39 The third TEST_CASE (NotSet) is designed to verify that all of the websites 40 are blocked since the URLWhitelistlist policy is set to None. 41 42 The test case shall pass if the URLs that are part of the URLWhitelist 43 policy value are not blocked. 44 The test case shall also pass if the URLs that are not part of the 45 URLWhitelist policy value are blocked. 46 The test case shall fail if the above behavior is not enforced. 47 48 """ 49 version = 1 50 TEST_CASES = { 51 'NotSet': '', 52 'SingleWhitelistedFile': SINGLE_WHITELISTED_FILE_DATA, 53 'MultipleWhitelistedFiles': MULTIPLE_WHITELISTED_FILES_DATA 54 } 55 56 def initialize(self, args=()): 57 super(policy_URLWhitelist, self).initialize(args) 58 self.start_webserver(URL_PORT) 59 60 def _navigate_to_website(self, url): 61 """ 62 Open a new tab in the browser and navigate to the URL. 63 64 @param url: the website that the browser is navigated to. 65 @returns: a chrome browser tab navigated to the URL. 66 67 """ 68 tab = self.cr.browser.tabs.New() 69 logging.info('Navigating to URL:%s', url) 70 try: 71 tab.Navigate(url, timeout=10) 72 except Exception, err: 73 logging.error('Timeout Exception in navigating URL: %s\n %s', 74 url, err) 75 tab.WaitForDocumentReadyStateToBeComplete() 76 return tab 77 78 def _scrape_text_from_website(self, tab): 79 """ 80 Returns a list of the the text content displayed on the page 81 matching the page_scrape_cmd filter. 82 83 @param tab: tab containing the website to be parsed. 84 @raises: TestFail if the expected text content was not found on the 85 page. 86 87 """ 88 parsed_message_string = '' 89 parsed_message_list = [] 90 page_scrape_cmd = 'document.getElementById("main-message").innerText;' 91 try: 92 parsed_message_string = tab.EvaluateJavaScript(page_scrape_cmd) 93 except Exception as err: 94 raise error.TestFail('Unable to find the expected ' 95 'text content on the test ' 96 'page: %s\n %r'%(tab.url, err)) 97 logging.info('Parsed message:%s', parsed_message_string) 98 parsed_message_list = [str(word) for word in 99 parsed_message_string.split('\n') if word] 100 return parsed_message_list 101 102 def _is_url_blocked(self, url): 103 """ 104 Returns True if the URL is blocked else returns False. 105 106 @param url: The URL to be checked whether it is blocked. 107 108 """ 109 parsed_message_list = [] 110 tab = self._navigate_to_website(url) 111 parsed_message_list = self._scrape_text_from_website(tab) 112 if len(parsed_message_list) == 2 and \ 113 parsed_message_list[0] == 'Website enabled' and \ 114 parsed_message_list[1] == 'Website is enabled': 115 return False 116 117 # Check if the accurate user error message displayed on the error page. 118 if parsed_message_list[0] != BLOCKED_USER_MESSAGE or \ 119 parsed_message_list[1] != BLOCKED_ERROR_MESSAGE: 120 logging.warning('The Blocked page user notification ' 121 'messages, %s and %s are not displayed on ' 122 'the blocked page. The messages may have ' 123 'been modified. Please check and update the ' 124 'messages in this file accordingly.', 125 BLOCKED_USER_MESSAGE, BLOCKED_ERROR_MESSAGE) 126 return True 127 128 def _test_URLWhitelist(self, policy_value, policies_json): 129 """ 130 Verify CrOS enforces URLWhitelist policy value. 131 132 Navigate to all the websites in the BLOCKED_URLS_LIST. Verify that 133 the websites specified by the URLWhitelist policy value are not 134 blocked. Also verify that the websites not in the URLWhitelist policy 135 value are blocked. 136 137 @param policy_value: policy value expected on chrome://policy page. 138 @param policies_json: policy JSON data to send to the fake DM server. 139 @raises: TestFail if url is blocked/not blocked based on the 140 corresponding policy values. 141 142 """ 143 url_is_blocked = None 144 logging.info('Running _test_Whitelist(%s, %s)', 145 policy_value, policies_json) 146 self.setup_case(POLICY_NAME, policy_value, policies_json) 147 148 for url in BLOCKED_URLS_LIST: 149 url_is_blocked = self._is_url_blocked(url) 150 if policy_value: 151 if url in policy_value and url_is_blocked: 152 raise error.TestFail('The URL %s should have been allowed' 153 ' by policy, but it was blocked' % url) 154 elif url not in policy_value and not url_is_blocked: 155 raise error.TestFail('The URL %s should have been blocked' 156 ' by policy, but it was allowed' % url) 157 158 elif not url_is_blocked: 159 raise error.TestFail('The URL %s should have been blocked' 160 'by policy, but it was allowed' % url) 161 162 def _run_test_case(self, case): 163 """ 164 Setup and run the test configured for the specified test case. 165 166 Set the expected |policy_value| and |policies_json| data based on the 167 test |case|. If the user specified an expected |value| in the command 168 line args, then use it to set the |policy_value| and blank out the 169 |policies_json|. 170 171 @param case: Name of the test case to run. 172 173 """ 174 policy_value = None 175 policies_json = None 176 177 if self.is_value_given: 178 # If |value| was given in the command line args, then set expected 179 # |policy_value| to the given value, and |policies_json| to None. 180 policy_value = self.value 181 policies_json = None 182 else: 183 # Otherwise, set expected |policy_value| and setup |policies_json| 184 # data to the values required by the specified test |case|. 185 policies_json = SUPPORTING_POLICIES.copy() 186 if not self.TEST_CASES[case]: 187 policy_value = None 188 else: 189 policy_value = ','.join(self.TEST_CASES[case]) 190 policies_json.update({'URLWhitelist': self.TEST_CASES[case]}) 191 192 # Run test using the values configured for the test case. 193 self._test_URLWhitelist(policy_value, policies_json) 194 195 def run_once(self): 196 self.run_once_impl(self._run_test_case) 197