Home | History | Annotate | Download | only in diff
      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