1# Copyright 2019 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 5import logging 6 7from autotest_lib.client.common_lib import error 8 9 10class Policy(object): 11 """ 12 Class structure for a single policy object. 13 14 A policy has the following attributes: 15 value 16 source 17 level 18 scope 19 name 20 21 All of the attributes are protected in @setter's. To set a value simply 22 create a policy object (e.g. "somePolicy = Policy()") and set the desired 23 value (somePolicy.value=True). 24 25 This class will be used by the policy_manager for configuring and checking 26 policies for Enterprise tests. 27 28 """ 29 30 def __init__(self): 31 self._value = None 32 self._source = None 33 self._scope = None 34 self._level = None 35 self._name = None 36 37 def is_formatted_value(self, data): 38 """ 39 Checks if the received value is a a dict containing all policy stats. 40 41 """ 42 if not isinstance(data, dict): 43 return False 44 received_keys = set(['scope', 'source', 'level', 'value']) 45 return received_keys.issubset(set(data.keys())) 46 47 def get_policy_as_dict(self): 48 """ 49 Returns the policy as a dict, in the same format as in the 50 chrome://policy json file. 51 52 """ 53 return {self.name: {'scope': self._scope, 54 'source': self._source, 55 'level': self._level, 56 'value': self._value}} 57 58 def set_policy_from_dict(self, data): 59 """ 60 Sets the policy attributes from a provided dict matching the following 61 format: 62 63 {"scope": scopeValue, "source": sourceValue, "level": levelValue, 64 "value": value} 65 66 @param data: a dict representing the policy values, as specified above. 67 68 """ 69 if not self.is_formatted_value(data): 70 raise error.TestError("""Incorrect input data provided. Value 71 provided must be dict with the keys: "scope", "source", 72 "level", "value". Got {}""".format(data)) 73 self.scope = data['scope'] 74 self.source = data['source'] 75 self.level = data['level'] 76 self.value = data['value'] 77 if data.get('error', None): 78 logging.warning('\n[Policy Error] error reported with policy:\n{}' 79 .format(data['error'])) 80 81 @property 82 def value(self): 83 return self._value 84 85 @value.setter 86 def value(self, value): 87 self._value = value 88 89 @property 90 def name(self): 91 return self._name 92 93 @name.setter 94 def name(self, name): 95 self._name = name 96 97 @property 98 def level(self): 99 return self._level 100 101 @level.setter 102 def level(self, level): 103 self._level = level 104 105 @property 106 def scope(self): 107 return self._scope 108 109 @scope.setter 110 def scope(self, scope): 111 self._scope = scope 112 113 @property 114 def source(self): 115 return self._source 116 117 @source.setter 118 def source(self, source): 119 self._source = source 120 121 @property 122 def group(self): 123 return None 124 125 @group.setter 126 def group(self, group): 127 """ 128 If setting a policy, you can also set it from a group ("user", 129 "suggested_user", "device"). Doing this will automatically set the other 130 policy attributes. 131 132 If the group is None, nothing will be set. 133 134 @param group: None or value of the policy group. 135 136 """ 137 if not group: 138 return 139 self._source = 'cloud' 140 if group != 'suggested_user': 141 self._level = 'mandatory' 142 else: 143 self._level = 'recommended' 144 if group == 'device': 145 self._scope = 'machine' 146 else: 147 self._scope = 'user' 148 149 def __ne__(self, other): 150 return not self.__eq__(other) 151 152 def __eq__(self, other): 153 """ 154 Override of the "==" statment. Verify one policy object verse another. 155 156 Will return True if the policy value, source, scope, and level are 157 equal, otherwise False. 158 159 There is a special check for the Network Policy, due to a displayed 160 policy having visual obfuscation (********). 161 162 """ 163 if self.value != other.value: 164 if is_network_policy(other.name): 165 return check_obfuscation(other.value) 166 else: 167 logging.info('value configured {} != received {}' 168 .format(self.value, other.value)) 169 return False 170 if self.source != other.source: 171 logging.info('source configured {} != received {}' 172 .format(self.source, other.source)) 173 return False 174 if self.scope != other.scope: 175 logging.info('scope configured {} != received {}' 176 .format(self.scope, other.scope)) 177 return False 178 if self.level != other.level: 179 logging.info('level configured {} != received {}' 180 .format(self.level, other.level)) 181 return False 182 return True 183 184 def __repr__(self): 185 policy_data = self.get_policy_as_dict() 186 return "<POLICY DATA OBJECT> | {}".format(policy_data) 187 188 189def is_network_policy(policy_name): 190 """ 191 Returns true if the policy name is that of an OpenNetworkConfiguration. 192 193 """ 194 if policy_name.endswith('OpenNetworkConfiguration'): 195 return True 196 197 198def check_obfuscation(other_value): 199 """Checks if value is a network policy, and is obfuscated.""" 200 DISPLAY_PWORD = '*' * 8 201 202 for network in other_value.get('NetworkConfigurations', []): 203 wifi = network.get('WiFi', {}) 204 if 'Passphrase' in wifi and wifi['Passphrase'] != DISPLAY_PWORD: 205 return False 206 if ('EAP' in wifi and 207 'Password' in wifi['EAP'] and 208 wifi['EAP']['Password'] != DISPLAY_PWORD): 209 return False 210 for cert in other_value.get('Certificates', []): 211 if 'PKCS12' in cert: 212 if cert['PKCS12'] != DISPLAY_PWORD: 213 return False 214 return True 215