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