def testRequestElementHandling(self): name = "req_name" groups = ["g1", "g2"] # The request should be empty after instantiation req = pyhbac.HbacRequest() self.assertIsInstance(req.user, pyhbac.HbacRequestElement) self.assertIsInstance(req.service, pyhbac.HbacRequestElement) self.assertIsInstance(req.targethost, pyhbac.HbacRequestElement) self.assertIsInstance(req.srchost, pyhbac.HbacRequestElement) self.assertEqual(req.user.name, "") self.assertIsInstance(req.user.groups, list) self.assertCountEqual(req.user.groups, []) # Assign by copying a HbacRequestElement user_el = pyhbac.HbacRequestElement(name=name, groups=groups) req = pyhbac.HbacRequest() req.user = user_el self.assertCountEqual(req.user.name, name) self.assertCountEqual(req.user.groups, groups) # Assign directly req = pyhbac.HbacRequest() req.user.name = name req.user.groups = groups self.assertCountEqual(req.user.name, name) self.assertCountEqual(req.user.groups, groups)
def testRepr(self): name = "someuser" service = "ssh" srchost = "host1" targethost = "host2" req = pyhbac.HbacRequest() self.assertEqual( req.__repr__(), "<user <name groups []> " "service <name groups []> " "targethost <name groups []> " "srchost <name groups []>>") req.user.name = name req.service.name = service req.srchost.name = srchost req.targethost.name = targethost self.assertEqual( req.__repr__(), "<user <name %s groups []> " "service <name %s groups []> " "targethost <name %s groups []> " "srchost <name %s groups []>>" % (name, service, targethost, srchost))
def testEvaluate(self): name = "someuser" service = "ssh" srchost = "host1" targethost = "host2" allow_rule = pyhbac.HbacRule("allowRule", enabled=True) allow_rule.users.names = [name] allow_rule.services.names = [service] allow_rule.srchosts.names = [srchost] allow_rule.targethosts.names = [targethost] req = pyhbac.HbacRequest() req.user.name = name req.service.name = service req.srchost.name = srchost req.targethost.name = targethost # Test that an allow rule on its own allows access res = req.evaluate((allow_rule, )) self.assertEqual(res, pyhbac.HBAC_EVAL_ALLOW) self.assertEqual(req.rule_name, "allowRule") # Test that a user not in the rule is not allowed savename = req.user.name req.user.name = "someotheruser" res = req.evaluate((allow_rule, )) self.assertEqual(res, pyhbac.HBAC_EVAL_DENY) self.assertEqual(req.rule_name, None) # But allows if the rule is an ALL rule allow_rule.users.category.add(pyhbac.HBAC_CATEGORY_ALL) res = req.evaluate((allow_rule, )) self.assertEqual(res, pyhbac.HBAC_EVAL_ALLOW)
def _acl_make_request(principal_type, principal, ca_id, profile_id): """Construct HBAC request for the given principal, CA and profile""" req = pyhbac.HbacRequest() req.targethost.name = ca_id req.service.name = profile_id if principal_type == 'user': req.user.name = principal.username elif principal_type == 'host': req.user.name = principal.hostname elif principal_type == 'service': req.user.name = unicode(principal) groups = [] if principal_type == 'user': user_obj = api.Command.user_show(principal.username)['result'] groups = user_obj.get('memberof_group', []) groups += user_obj.get('memberofindirect_group', []) elif principal_type == 'host': host_obj = api.Command.host_show(principal.hostname)['result'] groups = host_obj.get('memberof_hostgroup', []) groups += host_obj.get('memberofindirect_hostgroup', []) req.user.groups = sorted(set(groups)) return req
def testEvaluateNegative(self): name = "someuser" service = "ssh" srchost = "host1" targethost = "host2" allow_rule = pyhbac.HbacRule("allowRule", enabled=True) allow_rule.users.names = [name] allow_rule.services.names = [service] allow_rule.srchosts.names = [srchost] allow_rule.targethosts.names = [targethost] req = pyhbac.HbacRequest() req.service.name = service req.srchost.name = srchost req.targethost.name = targethost req.user.name = name saveuser = req.user req.user = None # need to catch this # catch invalid category value savecat = copy.copy(allow_rule.users.category) allow_rule.users.category.add(pyhbac.HBAC_EVAL_ERROR) self.assertRaises(ValueError, req.evaluate, (allow_rule, )) allow_rule.users.category = savecat # Test that invalid type is raised self.assertRaises(TypeError, req.evaluate, (allow_rule, )) req.user = saveuser allow_rule.users = None # need to catch this self.assertRaises(TypeError, req.evaluate, (allow_rule, )) # catch invalid rule type self.assertRaises(TypeError, req.evaluate, (allow_rule, None))
def testRuleName(self): req = pyhbac.HbacRequest() self.assertEqual(req.rule_name, None) # python 2.4 raises TypError, 2.7 raises AttributeError self.assertRaises((TypeError, AttributeError), req.__setattr__, "rule_name", "foo")
def _load_user_allowed_hosts(self): self._all_ssh_hosts = self._load_all_hosts(self.api) hbacset = [] rules = [] sizelimit = None hbacset = api.Command.hbacrule_find(sizelimit=sizelimit)['result'] for rule in hbacset: ipa_rule = self.convert_to_ipa_rule(rule) if ipa_rule.enabled: rules.append(ipa_rule) for ipa_rule in rules: for host in self._all_ssh_hosts: request = pyhbac.HbacRequest() #Build request user/usergroups try: request.user.name = self.user search_result = api.Command.user_show( request.user.name)['result'] groups = search_result['memberof_group'] if 'memberofindirect_group' in search_result: groups += search_result['memberofindirect_group'] request.user.groups = sorted(set(groups)) except: pass # Add sshd service + service groups it belongs to try: request.service.name = "sshd" service_result = api.Command.hbacsvc_show( request.service.name)['result'] if 'memberof_hbacsvcgroup' in service_result: request.service.groups = service_result[ 'memberof_hbacsvcgroup'] except: pass # Build request host/hostgroups try: request.targethost.name = host tgthost_result = api.Command.host_show( request.targethost.name)['result'] groups = tgthost_result['memberof_hostgroup'] if 'memberofindirect_hostgroup' in tgthost_result: groups += tgthost_result['memberofindirect_hostgroup'] request.targethost.groups = sorted(set(groups)) except: pass try: logging.debug("Core: Checking %s", host) res = request.evaluate([ipa_rule]) if res == pyhbac.HBAC_EVAL_ALLOW: logging.debug("Core: ALLOWED_HOSTS %s", host) self._allowed_ssh_hosts.append(host) except pyhbac.HbacError as (code, rule_name): if code == pyhbac.HBAC_EVAL_ERROR: #TODO log error print('Native IPA HBAC rule "%s" parsing error: %s' % \ (rule_name, pyhbac.hbac_result_string(code))) except (TypeError, IOError) as (info): print('Native IPA HBAC module error: %s' % (info))
def execute(self, *args, **options): # First receive all needed information: # 1. HBAC rules (whether enabled or disabled) # 2. Required options are (user, target host, service) # 3. Options: rules to test (--rules, --enabled, --disabled), request for detail output rules = [] # Use all enabled IPA rules by default all_enabled = True all_disabled = False # We need a local copy of test rules in order find incorrect ones testrules = {} if 'rules' in options: testrules = list(options['rules']) # When explicit rules are provided, disable assumptions all_enabled = False all_disabled = False sizelimit = None if 'sizelimit' in options: sizelimit = int(options['sizelimit']) # Check if --disabled is specified, include all disabled IPA rules if options['disabled']: all_disabled = True all_enabled = False # Finally, if enabled is specified implicitly, override above decisions if options['enabled']: all_enabled = True hbacset = [] if len(testrules) == 0: hbacset = self.api.Command.hbacrule_find( sizelimit=sizelimit, no_members=False)['result'] else: for rule in testrules: try: hbacset.append(self.api.Command.hbacrule_show(rule)['result']) except Exception: pass # We have some rules, import them # --enabled will import all enabled rules (default) # --disabled will import all disabled rules # --rules will implicitly add the rules from a rule list for rule in hbacset: ipa_rule = convert_to_ipa_rule(rule) if ipa_rule.name in testrules: ipa_rule.enabled = True rules.append(ipa_rule) testrules.remove(ipa_rule.name) elif all_enabled and ipa_rule.enabled: # Option --enabled forces to include all enabled IPA rules into test rules.append(ipa_rule) elif all_disabled and not ipa_rule.enabled: # Option --disabled forces to include all disabled IPA rules into test ipa_rule.enabled = True rules.append(ipa_rule) # Check if there are unresolved rules left if len(testrules) > 0: # Error, unresolved rules are left in --rules return {'summary' : unicode(_(u'Unresolved rules in --rules')), 'error': testrules, 'matched': None, 'notmatched': None, 'warning' : None, 'value' : False} # Rules are converted to pyhbac format, build request and then test it request = pyhbac.HbacRequest() if options['user'] != u'all': # check first if this is not a trusted domain user if _dcerpc_bindings_installed: is_valid_sid = ipaserver.dcerpc.is_sid_valid(options['user']) else: is_valid_sid = False components = util.normalize_name(options['user']) if is_valid_sid or 'domain' in components or 'flatname' in components: # this is a trusted domain user if not _dcerpc_bindings_installed: raise errors.NotFound(reason=_( 'Cannot perform external member validation without ' 'Samba 4 support installed. Make sure you have installed ' 'server-trust-ad sub-package of IPA on the server')) domain_validator = ipaserver.dcerpc.DomainValidator(self.api) if not domain_validator.is_configured(): raise errors.NotFound(reason=_( 'Cannot search in trusted domains without own domain configured. ' 'Make sure you have run ipa-adtrust-install on the IPA server first')) user_sid, group_sids = domain_validator.get_trusted_domain_user_and_groups(options['user']) request.user.name = user_sid # Now search for all external groups that have this user or # any of its groups in its external members. Found entires # memberOf links will be then used to gather all groups where # this group is assigned, including the nested ones filter_sids = "(&(objectclass=ipaexternalgroup)(|(ipaExternalMember=%s)))" \ % ")(ipaExternalMember=".join(group_sids + [user_sid]) ldap = self.api.Backend.ldap2 group_container = DN(api.env.container_group, api.env.basedn) try: entries, _truncated = ldap.find_entries( filter_sids, ['memberof'], group_container) except errors.NotFound: request.user.groups = [] else: groups = [] for entry in entries: memberof_dns = entry.get('memberof', []) for memberof_dn in memberof_dns: if memberof_dn.endswith(group_container): groups.append(memberof_dn[0][0].value) request.user.groups = sorted(set(groups)) else: # try searching for a local user try: request.user.name = options['user'] search_result = self.api.Command.user_show(request.user.name)['result'] groups = search_result['memberof_group'] if 'memberofindirect_group' in search_result: groups += search_result['memberofindirect_group'] request.user.groups = sorted(set(groups)) except Exception: pass if options['service'] != u'all': try: request.service.name = options['service'] service_result = self.api.Command.hbacsvc_show(request.service.name)['result'] if 'memberof_hbacsvcgroup' in service_result: request.service.groups = service_result['memberof_hbacsvcgroup'] except Exception: pass if options['targethost'] != u'all': try: request.targethost.name = self.canonicalize(options['targethost']) tgthost_result = self.api.Command.host_show(request.targethost.name)['result'] groups = tgthost_result['memberof_hostgroup'] if 'memberofindirect_hostgroup' in tgthost_result: groups += tgthost_result['memberofindirect_hostgroup'] request.targethost.groups = sorted(set(groups)) except Exception: pass matched_rules = [] notmatched_rules = [] error_rules = [] warning_rules = [] result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None} if not options['nodetail']: # Validate runs rules one-by-one and reports failed ones for ipa_rule in rules: try: res = request.evaluate([ipa_rule]) if res == pyhbac.HBAC_EVAL_ALLOW: matched_rules.append(ipa_rule.name) if res == pyhbac.HBAC_EVAL_DENY: notmatched_rules.append(ipa_rule.name) except pyhbac.HbacError as e: code, rule_name = e.args if code == pyhbac.HBAC_EVAL_ERROR: error_rules.append(rule_name) self.log.info('Native IPA HBAC rule "%s" parsing error: %s' % \ (rule_name, pyhbac.hbac_result_string(code))) except (TypeError, IOError) as info: self.log.error('Native IPA HBAC module error: %s' % info) access_granted = len(matched_rules) > 0 else: res = request.evaluate(rules) access_granted = (res == pyhbac.HBAC_EVAL_ALLOW) result['summary'] = _('Access granted: %s') % (access_granted) if len(matched_rules) > 0: result['matched'] = matched_rules if len(notmatched_rules) > 0: result['notmatched'] = notmatched_rules if len(error_rules) > 0: result['error'] = error_rules if len(warning_rules) > 0: result['warning'] = warning_rules result['value'] = access_granted return result
def execute(self, *args, **options): # First receive all needed information: # 1. HBAC rules (whether enabled or disabled) # 2. Required options are (user, target host, service) # 3. Options: rules to test (--rules, --enabled, --disabled), request for detail output rules = [] # Use all enabled IPA rules by default all_enabled = True all_disabled = False # We need a local copy of test rules in order find incorrect ones testrules = {} if 'rules' in options: testrules = list(options['rules']) # When explicit rules are provided, disable assumptions all_enabled = False all_disabled = False sizelimit = None if 'sizelimit' in options: sizelimit = int(options['sizelimit']) # Check if --disabled is specified, include all disabled IPA rules if options['disabled']: all_disabled = True all_enabled = False # Finally, if enabled is specified implicitly, override above decisions if options['enabled']: all_enabled = True hbacset = [] if len(testrules) == 0: hbacset = self.api.Command.hbacrule_find(sizelimit=sizelimit)['result'] else: for rule in testrules: try: hbacset.append(self.api.Command.hbacrule_show(rule)['result']) except: pass # We have some rules, import them # --enabled will import all enabled rules (default) # --disabled will import all disabled rules # --rules will implicitly add the rules from a rule list for rule in hbacset: ipa_rule = convert_to_ipa_rule(rule) if ipa_rule.name in testrules: ipa_rule.enabled = True rules.append(ipa_rule) testrules.remove(ipa_rule.name) elif all_enabled and ipa_rule.enabled: # Option --enabled forces to include all enabled IPA rules into test rules.append(ipa_rule) elif all_disabled and not ipa_rule.enabled: # Option --disabled forces to include all disabled IPA rules into test ipa_rule.enabled = True rules.append(ipa_rule) # Check if there are unresolved rules left if len(testrules) > 0: # Error, unresolved rules are left in --rules return {'summary' : unicode(_(u'Unresolved rules in --rules')), 'error': testrules, 'matched': None, 'notmatched': None, 'warning' : None, 'value' : False} # Rules are converted to pyhbac format, build request and then test it request = pyhbac.HbacRequest() if options['user'] != u'all': try: request.user.name = options['user'] search_result = self.api.Command.user_show(request.user.name)['result'] groups = search_result['memberof_group'] if 'memberofindirect_group' in search_result: groups += search_result['memberofindirect_group'] request.user.groups = sorted(set(groups)) except: pass if options['service'] != u'all': try: request.service.name = options['service'] service_result = self.api.Command.hbacsvc_show(request.service.name)['result'] if 'memberof_hbacsvcgroup' in service_result: request.service.groups = service_result['memberof_hbacsvcgroup'] except: pass if options['targethost'] != u'all': try: request.targethost.name = self.canonicalize(options['targethost']) tgthost_result = self.api.Command.host_show(request.targethost.name)['result'] groups = tgthost_result['memberof_hostgroup'] if 'memberofindirect_hostgroup' in tgthost_result: groups += tgthost_result['memberofindirect_hostgroup'] request.targethost.groups = sorted(set(groups)) except: pass matched_rules = [] notmatched_rules = [] error_rules = [] warning_rules = [] result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None} if not options['nodetail']: # Validate runs rules one-by-one and reports failed ones for ipa_rule in rules: try: res = request.evaluate([ipa_rule]) if res == pyhbac.HBAC_EVAL_ALLOW: matched_rules.append(ipa_rule.name) if res == pyhbac.HBAC_EVAL_DENY: notmatched_rules.append(ipa_rule.name) except pyhbac.HbacError as (code, rule_name): if code == pyhbac.HBAC_EVAL_ERROR: error_rules.append(rule_name) self.log.info('Native IPA HBAC rule "%s" parsing error: %s' % \ (rule_name, pyhbac.hbac_result_string(code))) except (TypeError, IOError) as (info): self.log.error('Native IPA HBAC module error: %s' % (info))