PolicyDifference: implement user diff

Closes #29
This commit is contained in:
Chris PeBenito 2016-01-08 09:55:34 -05:00
parent f7118a262e
commit aebe3f8706
6 changed files with 236 additions and 3 deletions

45
sediff
View File

@ -225,6 +225,51 @@ try:
print()
if all_differences or args.user:
if diff.added_users or diff.removed_users or diff.modified_users or args.user:
print("Users ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_users),
len(diff.removed_users),
len(diff.modified_users)))
if diff.added_users and not args.stats:
print(" Added Users: {0}".format(len(diff.added_users)))
for u in sorted(diff.added_users):
print(" + {0}".format(u))
if diff.removed_users and not args.stats:
print(" Removed Users: {0}".format(len(diff.removed_users)))
for u in sorted(diff.removed_users):
print(" - {0}".format(u))
if diff.modified_users and not args.stats:
print(" Modified Users: {0}".format(len(diff.modified_users)))
for name, mod in sorted(diff.modified_users.items()):
change = []
if mod.added_roles:
change.append("{0} Added roles".format(len(mod.added_roles)))
if mod.removed_roles:
change.append("{0} Removed roles".format(len(mod.removed_roles)))
if mod.removed_level:
change.append("Modified default level")
if mod.removed_range:
change.append("Modified range")
print(" * {0} ({1})".format(name, ", ".join(change)))
if mod.added_roles or mod.removed_roles:
print(" Roles:")
for t in sorted(mod.added_roles):
print(" + {0}".format(t))
for t in sorted(mod.removed_roles):
print(" - {0}".format(t))
if mod.removed_level:
print(" Default level:")
print(" + {0}".format(mod.added_level))
print(" - {0}".format(mod.removed_level))
if mod.removed_range:
print(" Range:")
print(" + {0}".format(mod.added_range))
print(" - {0}".format(mod.removed_range))
print()
if all_differences or args.allow:
if diff.added_allows or diff.removed_allows or diff.modified_allows or args.allow:
print("Allow Rules ({0} Added, {1} Removed, {2} Modified)".format(

View File

@ -23,6 +23,7 @@ from .rbacrules import RBACRulesDifference
from .roles import RolesDifference
from .terules import TERulesDifference
from .types import TypesDifference
from .users import UsersDifference
__all__ = ['PolicyDifference']
@ -33,7 +34,8 @@ class PolicyDifference(CommonDifference,
RBACRulesDifference,
RolesDifference,
TERulesDifference,
TypesDifference):
TypesDifference,
UsersDifference):
"""
Determine the differences from the left policy to the right policy.

121
setools/diff/users.py Normal file
View File

@ -0,0 +1,121 @@
# Copyright 2016, Tresys Technology, LLC
#
# This file is part of SETools.
#
# SETools is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 2.1 of
# the License, or (at your option) any later version.
#
# SETools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with SETools. If not, see
# <http://www.gnu.org/licenses/>.
#
from collections import namedtuple
from ..policyrep.exception import MLSDisabled
from .descriptors import DiffResultDescriptor
from .difference import Difference, SymbolWrapper
from .mls import LevelWrapper, RangeWrapper
modified_users_record = namedtuple("modified_user", ["added_roles",
"removed_roles",
"matched_roles",
"added_level",
"removed_level",
"added_range",
"removed_range"])
class UsersDifference(Difference):
"""Determine the difference in users between two policies."""
added_users = DiffResultDescriptor("diff_users")
removed_users = DiffResultDescriptor("diff_users")
modified_users = DiffResultDescriptor("diff_users")
def diff_users(self):
"""Generate the difference in users between the policies."""
self.log.info(
"Generating user differences from {0.left_policy} to {0.right_policy}".format(self))
self.added_users, self.removed_users, matched_users = self._set_diff(
(SymbolWrapper(r) for r in self.left_policy.users()),
(SymbolWrapper(r) for r in self.right_policy.users()))
self.modified_users = dict()
for left_user, right_user in matched_users:
# Criteria for modified users
# 1. change to role set, or
# 2. change to default level, or
# 3. change to range
added_roles, removed_roles, matched_roles = self._set_diff(
(SymbolWrapper(r) for r in left_user.roles),
(SymbolWrapper(r) for r in right_user.roles))
# keep wrapped and unwrapped MLS objects here so there
# are not several nested try blocks
try:
left_level_wrap = LevelWrapper(left_user.mls_level)
left_range_wrap = RangeWrapper(left_user.mls_range)
left_level = left_user.mls_level
left_range = left_user.mls_range
except MLSDisabled:
left_level_wrap = None
left_range_wrap = None
left_level = "None (MLS Disabled)"
left_range = "None (MLS Disabled)"
try:
right_level_wrap = LevelWrapper(right_user.mls_level)
right_range_wrap = RangeWrapper(right_user.mls_range)
right_level = right_user.mls_level
right_range = right_user.mls_range
except MLSDisabled:
right_level_wrap = None
right_range_wrap = None
right_level = "None (MLS Disabled)"
right_range = "None (MLS Disabled)"
if left_level_wrap != right_level_wrap:
added_level = right_level
removed_level = left_level
else:
added_level = None
removed_level = None
if left_range_wrap != right_range_wrap:
added_range = right_range
removed_range = left_range
else:
added_range = None
removed_range = None
if added_roles or removed_roles or removed_level or removed_range:
self.modified_users[left_user] = modified_users_record(added_roles,
removed_roles,
matched_roles,
added_level,
removed_level,
added_range,
removed_range)
#
# Internal functions
#
def _reset_diff(self):
"""Reset diff results on policy changes."""
self.log.debug("Resetting user differences")
self.added_users = None
self.removed_users = None
self.modified_users = None

View File

@ -853,6 +853,45 @@ class PolicyDifferenceTest(ValidateRule, unittest.TestCase):
self.assertEqual("role_tr_new_role", added_default)
self.assertEqual("role_tr_old_role", removed_default)
#
# Users
#
def test_added_user(self):
"""Diff: added user."""
self.assertSetEqual(set(["added_user"]), self.diff.added_users)
def test_removed_user(self):
"""Diff: removed user."""
self.assertSetEqual(set(["removed_user"]), self.diff.removed_users)
def test_modified_user_count(self):
"""Diff: modified user count."""
self.assertEqual(4, len(self.diff.modified_users))
def test_modified_user_add_role(self):
"""Diff: modified user with added role."""
self.assertSetEqual(set(["added_role"]),
self.diff.modified_users["modified_add_role"].added_roles)
self.assertFalse(self.diff.modified_users["modified_add_role"].removed_roles)
def test_modified_user_remove_role(self):
"""Diff: modified user with removed role."""
self.assertSetEqual(set(["removed_role"]),
self.diff.modified_users["modified_remove_role"].removed_roles)
self.assertFalse(self.diff.modified_users["modified_remove_role"].added_roles)
def test_modified_user_change_level(self):
"""Diff: modified user due to modified default level."""
self.assertEqual("s2:c0", self.diff.modified_users["modified_change_level"].removed_level)
self.assertEqual("s2:c1", self.diff.modified_users["modified_change_level"].added_level)
def test_modified_user_change_range(self):
"""Diff: modified user due to modified range."""
self.assertEqual("s3:c1.c3",
self.diff.modified_users["modified_change_range"].removed_range)
self.assertEqual("s3:c1.c4",
self.diff.modified_users["modified_change_range"].added_range)
class PolicyDifferenceTestNoDiff(unittest.TestCase):
@ -1029,3 +1068,15 @@ class PolicyDifferenceTestNoDiff(unittest.TestCase):
def test_modified_role_transitions(self):
"""NoDiff: no modified role_transition rules."""
self.assertFalse(self.diff.modified_role_transitions)
def test_added_users(self):
"""NoDiff: no added user rules."""
self.assertFalse(self.diff.added_users)
def test_removed_users(self):
"""NoDiff: no removed user rules."""
self.assertFalse(self.diff.removed_users)
def test_modified_users(self):
"""NoDiff: no modified user rules."""
self.assertFalse(self.diff.modified_users)

View File

@ -586,7 +586,14 @@ role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_
################################################################################
#users
user system roles system level s0 range s0 - s46:c0.c4;
user system roles system level s0 range s0 - s46:c1.c4;
user removed_user roles system level s0 range s0;
user modified_add_role roles system level s2 range s2;
user modified_remove_role roles { system removed_role } level s2 range s2;
user modified_change_level roles system level s2:c0 range s2:c0,c1;
user modified_change_range roles system level s3:c1 range s3:c1.c3;
#normal constraints
constrain infoflow hi_w (u1 == u2);

View File

@ -587,7 +587,14 @@ role_transition role_tr_matched_source role_tr_matched_target:infoflow3 role_tr_
################################################################################
#users
user system roles system level s0 range s0 - s46:c0.c4;
user system roles system level s0 range s0 - s46:c1.c4;
user added_user roles system level s1 range s1;
user modified_add_role roles { system added_role } level s2 range s2;
user modified_remove_role roles system level s2 range s2;
user modified_change_level roles system level s2:c1 range s2:c0,c1;
user modified_change_range roles system level s3:c1 range s3:c1.c4;
#normal constraints
constrain infoflow hi_w (u1 == u2);