1 # Copyright 2016, Tresys Technology, LLC 2 # 3 # This file is part of SETools. 4 # 5 # SETools is free software: you can redistribute it and/or modify 6 # it under the terms of the GNU Lesser General Public License as 7 # published by the Free Software Foundation, either version 2.1 of 8 # the License, or (at your option) any later version. 9 # 10 # SETools is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU Lesser General Public License for more details. 14 # 15 # You should have received a copy of the GNU Lesser General Public 16 # License along with SETools. If not, see 17 # <http://www.gnu.org/licenses/>. 18 # 19 from collections import namedtuple 20 21 from ..policyrep.exception import MLSDisabled 22 23 from .descriptors import DiffResultDescriptor 24 from .difference import Difference, SymbolWrapper 25 from .mls import LevelWrapper, RangeWrapper 26 27 28 modified_users_record = namedtuple("modified_user", ["added_roles", 29 "removed_roles", 30 "matched_roles", 31 "added_level", 32 "removed_level", 33 "added_range", 34 "removed_range"]) 35 36 37 class UsersDifference(Difference): 38 39 """Determine the difference in users between two policies.""" 40 41 added_users = DiffResultDescriptor("diff_users") 42 removed_users = DiffResultDescriptor("diff_users") 43 modified_users = DiffResultDescriptor("diff_users") 44 45 def diff_users(self): 46 """Generate the difference in users between the policies.""" 47 48 self.log.info( 49 "Generating user differences from {0.left_policy} to {0.right_policy}".format(self)) 50 51 self.added_users, self.removed_users, matched_users = self._set_diff( 52 (SymbolWrapper(r) for r in self.left_policy.users()), 53 (SymbolWrapper(r) for r in self.right_policy.users())) 54 55 self.modified_users = dict() 56 57 for left_user, right_user in matched_users: 58 # Criteria for modified users 59 # 1. change to role set, or 60 # 2. change to default level, or 61 # 3. change to range 62 added_roles, removed_roles, matched_roles = self._set_diff( 63 (SymbolWrapper(r) for r in left_user.roles), 64 (SymbolWrapper(r) for r in right_user.roles)) 65 66 # keep wrapped and unwrapped MLS objects here so there 67 # are not several nested try blocks 68 try: 69 left_level_wrap = LevelWrapper(left_user.mls_level) 70 left_range_wrap = RangeWrapper(left_user.mls_range) 71 left_level = left_user.mls_level 72 left_range = left_user.mls_range 73 except MLSDisabled: 74 left_level_wrap = None 75 left_range_wrap = None 76 left_level = "None (MLS Disabled)" 77 left_range = "None (MLS Disabled)" 78 79 try: 80 right_level_wrap = LevelWrapper(right_user.mls_level) 81 right_range_wrap = RangeWrapper(right_user.mls_range) 82 right_level = right_user.mls_level 83 right_range = right_user.mls_range 84 except MLSDisabled: 85 right_level_wrap = None 86 right_range_wrap = None 87 right_level = "None (MLS Disabled)" 88 right_range = "None (MLS Disabled)" 89 90 if left_level_wrap != right_level_wrap: 91 added_level = right_level 92 removed_level = left_level 93 else: 94 added_level = None 95 removed_level = None 96 97 if left_range_wrap != right_range_wrap: 98 added_range = right_range 99 removed_range = left_range 100 else: 101 added_range = None 102 removed_range = None 103 104 if added_roles or removed_roles or removed_level or removed_range: 105 self.modified_users[left_user] = modified_users_record(added_roles, 106 removed_roles, 107 matched_roles, 108 added_level, 109 removed_level, 110 added_range, 111 removed_range) 112 113 # 114 # Internal functions 115 # 116 def _reset_diff(self): 117 """Reset diff results on policy changes.""" 118 self.log.debug("Resetting user differences") 119 self.added_users = None 120 self.removed_users = None 121 self.modified_users = None 122