De-duplicate ACI attributes and permissions

Ensure uniqueuess in attributes and permissions in the ACI class.

A set() is not used because it doesn't guarantee order which ends up
causing cascading and unpredictable test failures. Since all we
really need is de-duplication and not a true mathematical set iterating
through the list is sufficiently fast, particularly since the number
of elements will always be low.

https://pagure.io/freeipa/issue/8443

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
Rob Crittenden
2020-09-11 12:03:01 -04:00
committed by Alexander Bokovoy
parent e92a4ba4ae
commit cdf830af18

View File

@@ -83,7 +83,7 @@ class ACI:
op = v['operator'] op = v['operator']
if type(v['expression']) in (tuple, list): if type(v['expression']) in (tuple, list):
target = "" target = ""
for l in v['expression']: for l in self._unique_list(v['expression']):
target = target + l + " || " target = target + l + " || "
target = target[:-4] target = target[:-4]
aci = aci + "(%s %s \"%s\")" % (t, op, target) aci = aci + "(%s %s \"%s\")" % (t, op, target)
@@ -92,6 +92,20 @@ class ACI:
aci = aci + "(version 3.0;acl \"%s\";%s (%s) %s %s \"%s\"" % (self.name, self.action, ",".join(self.permissions), self.bindrule['keyword'], self.bindrule['operator'], self.bindrule['expression']) + ";)" aci = aci + "(version 3.0;acl \"%s\";%s (%s) %s %s \"%s\"" % (self.name, self.action, ",".join(self.permissions), self.bindrule['keyword'], self.bindrule['operator'], self.bindrule['expression']) + ";)"
return aci return aci
def _unique_list(self, l):
"""
A set() doesn't maintain order so make a list unique ourselves.
The number of entries in our lists are always going to be
relatively low and this code will be called infrequently
anyway so the overhead will be small.
"""
unique = []
for item in l:
if item not in unique:
unique.append(item)
return unique
def _remove_quotes(self, s): def _remove_quotes(self, s):
# Remove leading and trailing quotes # Remove leading and trailing quotes
if s.startswith('"'): if s.startswith('"'):
@@ -149,7 +163,9 @@ class ACI:
if not bindperms or len(bindperms.groups()) < 3: if not bindperms or len(bindperms.groups()) < 3:
raise SyntaxError("malformed ACI, permissions match failed %s" % acistr) raise SyntaxError("malformed ACI, permissions match failed %s" % acistr)
self.action = bindperms.group(1) self.action = bindperms.group(1)
self.permissions = bindperms.group(2).replace(' ','').split(',') self.permissions = self._unique_list(
bindperms.group(2).replace(' ','').split(',')
)
self.set_bindrule(bindperms.group(3)) self.set_bindrule(bindperms.group(3))
def validate(self): def validate(self):
@@ -175,6 +191,11 @@ class ACI:
raise SyntaxError("bindrule is missing a component") raise SyntaxError("bindrule is missing a component")
return True return True
def set_permissions(self, permissions):
if type(permissions) not in (tuple, list):
permissions = [permissions]
self.permissions = self._unique_list(permissions)
def set_target_filter(self, filter, operator="="): def set_target_filter(self, filter, operator="="):
self.target['targetfilter'] = {} self.target['targetfilter'] = {}
if not filter.startswith("("): if not filter.startswith("("):
@@ -190,7 +211,7 @@ class ACI:
if type(attr) not in (tuple, list): if type(attr) not in (tuple, list):
attr = [attr] attr = [attr]
self.target['targetattr'] = {} self.target['targetattr'] = {}
self.target['targetattr']['expression'] = attr self.target['targetattr']['expression'] = self._unique_list(attr)
self.target['targetattr']['operator'] = operator self.target['targetattr']['operator'] = operator
def set_target(self, target, operator="="): def set_target(self, target, operator="="):