"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "linotpd/src/linotp/lib/policy/evaluate.py" between
LinOTP-release-2.12.tar.gz and LinOTP-release-2.12.1.tar.gz

About: LinOTP is a flexible and versatile OTP-platform for strong user authentication (two-factor authentication with one time passwords).

evaluate.py  (LinOTP-release-2.12):evaluate.py  (LinOTP-release-2.12.1)
skipping to change at line 110 skipping to change at line 110
:param: dict with filter conditions :param: dict with filter conditions
:return: list of matching policies :return: list of matching policies
""" """
try: try:
# preserve the old filters # preserve the old filters
sec_filters = self.filters sec_filters = self.filters
self.set_filters(param) self.set_filters(param)
policies = self.evaluate(multiple=True) policies = self.evaluate()
finally: finally:
# and restore the preserved ones # and restore the preserved ones
self.filters = sec_filters self.filters = sec_filters
return policies return policies
def evaluate(self, policy_set=None, multiple=True): def evaluate(self, policy_set=None):
""" """
evaluate - compare all policies against the access request evaluate - compare all policies against the access request
implementation detail: implementation detail:
- The evaluate iterates over all given policies. - The evaluate iterates over all given policies.
- During the iteration all filter comparisons are made against - During the iteration all filter comparisons are made against
the one policy. This allows an early exit, thus if one filter does the one policy. This allows an early exit, thus if one filter does
not match, all further comparison of the given policy could be not match, all further comparison of the given policy could be
skipped. skipped.
- during the filter definition the comparison function is defined, thus - during the filter definition the comparison function is defined, thus
all filter evaluation steps could be treated equal by just calling all filter evaluation steps could be treated equal by just calling
the comparison function with the actual value. the comparison function with the actual value.
- There is a special treatment of the user matching in policies, which
classifies the policies in those with a pure wildcard match, a regex
match and an exact matching. If there are exact matching, this set of
policies is prefered over those with a regex match, which is prefered
over the set of pure wildcard '*' match. Thus in case of a wildcard
match, all policies are returned
:param policy_set: optional, base policies against which all filter :param policy_set: optional, base policies against which all filter
are evaluated are evaluated
:param multiple: define if the policies should be post processed to
return the best matching ones. Default is to do no
post proessing
:return: the set of matching policies :return: the set of matching policies
""" """
matching_policies = {} matching_policies = {}
#
# provide information about the policy evaluation - for debugging :)
matching_details = {}
all_policies = self.all_policies all_policies = self.all_policies
if policy_set: if policy_set:
all_policies = policy_set all_policies = policy_set
if not self.filters: if not self.filters:
return all_policies return all_policies
# preserve a dict with which policy matched best wrt the user
user_match = {}
for p_name, p_dict in all_policies.items(): for p_name, p_dict in all_policies.items():
matching = False
# #
# special case: for filtering of policies by name: # special case: for filtering of policies by name:
# we add the name of the policy to the policy description # we add the name of the policy to the policy description
# so we can use the same machine for the name compare # so we can use the same machine for the name compare
if 'name' not in p_dict: if 'name' not in p_dict:
p_dict['name'] = p_name p_dict['name'] = p_name
# #
# evaluate each filter against the policy. if one filter fails # evaluate each filter against the policy. if one filter fails
# we can skip the evaluation the given policy # we can skip the evaluation the given policy
for (f_key, f_value, f_compare) in self.filters: user_match_type = None
for (f_key, f_value, f_compare) in self.filters:
policy_condition = p_dict.get(f_key) policy_condition = p_dict.get(f_key)
matching = f_compare(policy_condition, f_value)
# here we honor the user matching, which in difference to the
# other matching functions returns more than a boolean -
# it returns the matching precission, which is either:
# exact:match, regex:match or wildcard:match
# - the evaluation of the set of policy conditions can
# only be evaluated within the user_list_compare
# function
if f_key == 'user':
user_match_type, matching = f_compare(
policy_condition, f_value)
else:
matching = f_compare(policy_condition, f_value)
if not matching: if not matching:
break break
if matching: # --------------------------------------------------------------- --
matching_policies[p_name] = p_dict
# if we have multiple policies and post processing should be made:
if not multiple and len(matching_policies):
#
# so we do some post selection but dont care for the result, as
# this is done in the upper level
matching_policies = self._most_precise_policy(matching_policies)
return matching_policies
return matching_policies
def _most_precise_policy(self, matching_policies):
no_wild_card_match = {} # all conditions are evaluated: preserve results in case of a match
for key in ['user', 'client', 'realm']: if not matching:
entry = [] continue
for name, policy in matching_policies.items():
conditions = [x.strip() for x in policy[key].split(',')]
if '*' not in conditions:
entry.append(name)
if len(entry) > 0: matching_policies[p_name] = p_dict
no_wild_card_match[key] = entry
res = None if user_match_type:
if user_match_type not in user_match:
user_match[user_match_type] = {}
if ('realm' in no_wild_card_match and user_match[user_match_type][p_name] = all_policies[p_name]
len(no_wild_card_match['realm']) == 1):
res = no_wild_card_match['realm'] # ----------------------------------------------------------------- --
elif ('client' in no_wild_card_match and # all policies are evaluated:
len(no_wild_card_match['client']) == 1): # identify the most relvant policies wrt. to the user matching:
# user name >> ( *@realm | *.resolver: ) >> *
# if there is no exact or regex user match, we return all identified
# policies
res = no_wild_card_match['client'] if 'exact:match' in user_match:
return user_match['exact:match']
elif ('user' in no_wild_card_match and elif 'regex:match' in user_match:
len(no_wild_card_match['user']) == 1): return user_match['regex:match']
res = no_wild_card_match['user']
if res:
policy_name = res[0]
return {policy_name: matching_policies[policy_name]}
return matching_policies return matching_policies
def set_filters(self, params): def set_filters(self, params):
""" """
set up a set of filters from a dictionary set up a set of filters from a dictionary
interface to ease the migration interface to ease the migration
""" """
skipping to change at line 536 skipping to change at line 532
user = login user = login
elif isinstance(login, str) or isinstance(login, unicode): elif isinstance(login, str) or isinstance(login, unicode):
if '@' in login: if '@' in login:
usr, _sep, realm = login.rpartition('@') usr, _sep, realm = login.rpartition('@')
user = User(usr, realm) user = User(usr, realm)
else: else:
user = User(login) user = User(login)
else: else:
raise Exception("unsupported type of login") raise Exception("unsupported type of login")
full_qualified_names = user.get_full_qalified_names()
matched = False matched = False
match_type = ''
domain_comp = UserDomainCompare() domain_comp = UserDomainCompare()
attr_comp = AttributeCompare() attr_comp = AttributeCompare()
for condition in conditions: for condition in conditions:
if not condition: if not condition:
continue continue
its_a_not_condition = False its_a_not_condition = False
skipping to change at line 608 skipping to change at line 607
usr, _sep, realm = login.rpartition('@') usr, _sep, realm = login.rpartition('@')
if realm in getRealms(): if realm in getRealms():
c_user = User(usr, realm) c_user = User(usr, realm)
else: else:
c_user = User(login) c_user = User(login)
else: else:
c_user = user c_user = user
# check resolver of the user
identified = domain_comp.exists(c_user, condition) identified = domain_comp.exists(c_user, condition)
else: # simple user condition with string compare and wild cards else: # simple user condition with string compare and wild cards
identified = domain_comp.compare(user, condition) identified = domain_comp.compare(user, condition)
if identified: if not identified:
matched = True continue
if its_a_not_condition: # early exit on a not condition # early exit on a not condition: !user1
return False
return matched if its_a_not_condition:
return 'not:match', False
# if we came here, we got a least one match
matched = True
# evaluate the precission of the user match
if condition in full_qualified_names:
match_type = 'exact:match'
if condition == '*':
if not match_type:
match_type = 'wildcard:match'
else:
if match_type != 'exact:match':
match_type = 'regex:match'
return match_type, matched
def _compare_cron_value(value, target): def _compare_cron_value(value, target):
""" """
cron value comparison - compare the target, if it matches the cron value cron value comparison - compare the target, if it matches the cron value
a cron values could be like a cron values could be like
*/15 */6 1,15,31 * 1-5 * */15 */6 1,15,31 * 1-5 *
or or
0 12 * * 1-5 * (0 12 * * Mon-Fri *) 0 12 * * 1-5 * (0 12 * * Mon-Fri *)
 End of changes. 27 change blocks. 
58 lines changed or deleted 75 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)