def test_grantable_permissions( session, standard_graph, users, groups, grantable_permissions # noqa: F811 ): perm_grant, perm0, perm1, _ = grantable_permissions assert not user_grantable_permissions(session, users["*****@*****.**"]), "start with none" grant_permission(groups["auditors"], perm_grant, argument="notgrantable.one") assert not user_grantable_permissions( session, users["*****@*****.**"] ), "grant on non-existent is fine" grant_permission(groups["auditors"], perm_grant, argument=perm0.name) grants = user_grantable_permissions(session, users["*****@*****.**"]) assert len(grants) == 1, "only specific permission grant" assert grants[0][0].name == perm0.name, "only specific permission grant" grant_permission(groups["auditors"], perm_grant, argument="grantable.*") grants = user_grantable_permissions(session, users["*****@*****.**"]) assert len(grants) == 3, "wildcard grant should grab appropriat amount" assert sorted([x[0].name for x in grants]) == ["grantable", "grantable.one", "grantable.two"] args_by_perm = get_grantable_permissions(session, None) assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected in list of grantable" grant_permission(groups["auditors"], perm_grant, argument="{}/single_arg".format(perm1.name)) args_by_perm = get_grantable_permissions(session, None) assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected cause no restricted perms" args_by_perm = get_grantable_permissions(session, [perm1.name]) assert args_by_perm[perm1.name] == [ "single_arg" ], "least permissive argument shown cause of restricted perms"
def test_grantable_permissions(session, standard_graph, users, groups, grantable_permissions): perm_grant, perm0, perm1, _ = grantable_permissions assert not user_grantable_permissions(session, users["*****@*****.**"]), "start with none" grant_permission(groups["auditors"], perm_grant, argument="notgrantable.one") assert not user_grantable_permissions(session, users["*****@*****.**"]), "grant on non-existent is fine" grant_permission(groups["auditors"], perm_grant, argument=perm0.name) grants = user_grantable_permissions(session, users["*****@*****.**"]) assert len(grants) == 1, "only specific permission grant" assert grants[0][0].name == perm0.name, "only specific permission grant" grant_permission(groups["auditors"], perm_grant, argument="grantable.*") grants = user_grantable_permissions(session, users["*****@*****.**"]) assert len(grants) == 3, "wildcard grant should grab appropriat amount" assert sorted([x[0].name for x in grants]) == ["grantable", "grantable.one", "grantable.two"] args_by_perm = get_grantable_permissions(session, None) assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected in list of grantable" grant_permission(groups["auditors"], perm_grant, argument="{}/single_arg".format(perm1.name)) args_by_perm = get_grantable_permissions(session, None) assert args_by_perm[perm1.name] == ["*"], "wildcard grant reflected cause no restricted perms" args_by_perm = get_grantable_permissions(session, [perm1.name]) assert args_by_perm[perm1.name] == ["single_arg"], "least permissive argument shown cause of restricted perms"
def get_group_view_template_vars(session, actor, group, graph): # type: (Session, User, Group, GroupGraph) -> Dict[str, Any] ret = {} ret["grantable"] = user_grantable_permissions(session, actor) try: group_md = graph.get_group_details(group.name) except NoSuchGroup: # Very new group with no metadata yet, or it has been disabled and # excluded from in-memory cache. group_md = {} ret["members"] = group.my_members() ret["groups"] = group.my_groups() ret["service_accounts"] = get_service_accounts(session, group) ret["permissions"] = group_md.get("permissions", []) for permission in ret["permissions"]: permission["granted_on"] = datetime.fromtimestamp(permission["granted_on"]) ret["permission_requests_pending"] = [] for req in get_pending_request_by_group(session, group): granters = [] for owner, argument in get_owner_arg_list(session, req.permission, req.argument): granters.append(owner.name) ret["permission_requests_pending"].append((req, granters)) ret["audited"] = group_md.get("audited", False) ret["log_entries"] = group.my_log_entries() ret["num_pending"] = count_requests_by_group(session, group, status="pending") ret["current_user_role"] = { "is_owner": user_role_index(actor, ret["members"]) in OWNER_ROLE_INDICES, "is_approver": user_role_index(actor, ret["members"]) in APPROVER_ROLE_INDICES, "is_manager": user_role(actor, ret["members"]) == "manager", "is_member": user_role(actor, ret["members"]) is not None, "role": user_role(actor, ret["members"]), } ret["can_leave"] = ( ret["current_user_role"]["is_member"] and not ret["current_user_role"]["is_owner"] ) ret["statuses"] = AUDIT_STATUS_CHOICES # Add mapping_id to permissions structure ret["my_permissions"] = group.my_permissions() for perm_up in ret["permissions"]: for perm_direct in ret["my_permissions"]: if ( perm_up["permission"] == perm_direct.name and perm_up["argument"] == perm_direct.argument ): perm_up["mapping_id"] = perm_direct.mapping_id break ret["alerts"] = [] ret["self_pending"] = count_requests_by_group(session, group, status="pending", user=actor) if ret["self_pending"]: ret["alerts"].append(Alert("info", "You have a pending request to join this group.", None)) return ret
def get_group_view_template_vars(session, actor, group, graph): ret = {} ret["grantable"] = user_grantable_permissions(session, actor) try: group_md = graph.get_group_details(group.name) except NoSuchGroup: # Very new group with no metadata yet, or it has been disabled and # excluded from in-memory cache. group_md = {} ret["members"] = group.my_members() ret["groups"] = group.my_groups() ret["service_accounts"] = get_service_accounts(session, group) ret["permissions"] = group_md.get('permissions', []) ret["permission_requests_pending"] = [] for req in get_pending_request_by_group(session, group): granters = [] for owner, argument in get_owner_arg_list(session, req.permission, req.argument): granters.append(owner.name) ret["permission_requests_pending"].append((req, granters)) ret["audited"] = group_md.get('audited', False) ret["log_entries"] = group.my_log_entries() ret["num_pending"] = group.my_requests("pending").count() ret["current_user_role"] = { 'is_owner': user_role_index(actor, ret["members"]) in OWNER_ROLE_INDICES, 'is_approver': user_role_index(actor, ret["members"]) in APPROVER_ROLE_INDICES, 'is_manager': user_role(actor, ret["members"]) == "manager", 'is_member': user_role(actor, ret["members"]) is not None, 'role': user_role(actor, ret["members"]), } ret["can_leave"] = (ret["current_user_role"]['is_member'] and not ret["current_user_role"]['is_owner']) ret["statuses"] = AUDIT_STATUS_CHOICES # Add mapping_id to permissions structure ret["my_permissions"] = group.my_permissions() for perm_up in ret["permissions"]: for perm_direct in ret["my_permissions"]: if (perm_up['permission'] == perm_direct.name and perm_up['argument'] == perm_direct.argument): perm_up['mapping_id'] = perm_direct.mapping_id break ret["alerts"] = [] ret["self_pending"] = group.my_requests("pending", user=actor).count() if ret["self_pending"]: ret["alerts"].append( Alert('info', 'You have a pending request to join this group.', None)) return ret
def get_group_view_template_vars(session, actor, group, graph): ret = {} ret["grantable"] = user_grantable_permissions(session, actor) try: group_md = graph.get_group_details(group.name) except NoSuchGroup: # Very new group with no metadata yet, or it has been disabled and # excluded from in-memory cache. group_md = {} ret["members"] = group.my_members() ret["groups"] = group.my_groups() ret["permissions"] = group_md.get('permissions', []) ret["permission_requests_pending"] = [] for req in get_pending_request_by_group(session, group): granters = [] for owner, argument in get_owner_arg_list(session, req.permission, req.argument): granters.append(owner.name) ret["permission_requests_pending"].append((req, granters)) ret["audited"] = group_md.get('audited', False) ret["log_entries"] = group.my_log_entries() ret["num_pending"] = group.my_requests("pending").count() ret["current_user_role"] = { 'is_owner': user_role_index(actor, ret["members"]) in OWNER_ROLE_INDICES, 'is_approver': user_role_index(actor, ret["members"]) in APPROVER_ROLE_INDICIES, 'is_manager': user_role(actor, ret["members"]) == "manager", 'is_member': user_role(actor, ret["members"]) is not None, 'role': user_role(actor, ret["members"]), } ret["can_leave"] = (ret["current_user_role"]['is_member'] and not ret["current_user_role"]['is_owner']) ret["statuses"] = AUDIT_STATUS_CHOICES # Add mapping_id to permissions structure ret["my_permissions"] = group.my_permissions() for perm_up in ret["permissions"]: for perm_direct in ret["my_permissions"]: if (perm_up['permission'] == perm_direct.name and perm_up['argument'] == perm_direct.argument): perm_up['mapping_id'] = perm_direct.mapping_id break ret["alerts"] = [] ret["self_pending"] = group.my_requests("pending", user=actor).count() if ret["self_pending"]: ret["alerts"].append(Alert('info', 'You have a pending request to join this group.', None)) return ret
def check_access(session: Session, mapping: PermissionMap, user: User): user_is_owner = user_is_owner_of_group(session, mapping.group, user) if user_is_owner: return True grantable = user_grantable_permissions(session, user) for perm in grantable: if perm[0].name == mapping.permission.name: if matches_glob(perm[1], mapping.argument): return True return False
def check_access(session, mapping, user): user_is_owner = user_is_owner_of_group(session, mapping.group, user) if user_is_owner: return True grantable = user_grantable_permissions(session, user) for perm in grantable: if perm[0].name == mapping.permission.name: if matches_glob(perm[1], mapping.argument): return True return False
def get(self, name=None): grantable = user_grantable_permissions(self.session, self.current_user) if not grantable: return self.forbidden() group = Group.get(self.session, None, name) if not group: return self.notfound() form = PermissionGrantForm() form.permission.choices = [["", "(select one)"]] for perm in grantable: grantable = "{} ({})".format(perm[0].name, perm[1]) form.permission.choices.append([perm[0].name, grantable]) return self.render("permission-grant.html", form=form, group=group)
def post(self, *args: Any, **kwargs: Any) -> None: name = self.get_path_argument("name") grantable = user_grantable_permissions(self.session, self.current_user) if not grantable: return self.forbidden() group = Group.get(self.session, name=name) if not group: return self.notfound() form = PermissionGrantForm(self.request.arguments) form.permission.choices = [["", "(select one)"]] for perm in grantable: grantable_str = "{} ({})".format(perm[0].name, perm[1]) form.permission.choices.append([perm[0].name, grantable_str]) if not form.validate(): return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) permission = get_permission(self.session, form.data["permission"]) if not permission: return self.notfound() # Shouldn't happen. argument = form.argument.data.strip() allowed = False for perm in grantable: if perm[0].name == permission.name: if matches_glob(perm[1], argument): allowed = True break if not allowed: form.argument.errors.append( "You do not have grant authority over that permission/argument combination." ) return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) # If the permission is audited, then see if the subtree meets auditing requirements. if permission.audited: try: assert_controllers_are_auditors(group) except UserNotAuditor as e: form.permission.errors.append(str(e)) return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) try: self.plugins.check_permission_argument(permission.name, argument) grant_permission(self.session, group.id, permission.id, argument=argument) except PluginRejectedPermissionArgument as e: self.session.rollback() form.argument.errors.append(f"Rejected by plugin: {e}") return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) except IntegrityError: self.session.rollback() form.argument.errors.append( "Permission and Argument already mapped to this group.") return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) self.session.commit() AuditLog.log( self.session, self.current_user.id, "grant_permission", "Granted permission with argument: {}".format( form.data["argument"]), on_permission_id=permission.id, on_group_id=group.id, ) return self.redirect("/groups/{}?refresh=yes".format(group.name))
def post(self, name=None): grantable = user_grantable_permissions(self.session, self.current_user) if not grantable: return self.forbidden() group = Group.get(self.session, None, name) if not group: return self.notfound() form = PermissionGrantForm(self.request.arguments) form.permission.choices = [["", "(select one)"]] for perm in grantable: grantable_str = "{} ({})".format(perm[0].name, perm[1]) form.permission.choices.append([perm[0].name, grantable_str]) if not form.validate(): return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) permission = get_permission(self.session, form.data["permission"]) if not permission: return self.notfound() # Shouldn't happen. allowed = False for perm in grantable: if perm[0].name == permission.name: if matches_glob(perm[1], form.data["argument"]): allowed = True break if not allowed: form.argument.errors.append( "You do not have grant authority over that permission/argument combination." ) return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) # If the permission is audited, then see if the subtree meets auditing requirements. if permission.audited: fail_message = ( "Permission is audited and this group (or a subgroup) contains " + "owners, np-owners, or managers who have not received audit training." ) try: permission_ok = assert_controllers_are_auditors(group) except UserNotAuditor as e: permission_ok = False fail_message = e if not permission_ok: form.permission.errors.append(fail_message) return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) try: grant_permission(self.session, group.id, permission.id, argument=form.data["argument"]) except IntegrityError: self.session.rollback() form.argument.errors.append( "Permission and Argument already mapped to this group.") return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) self.session.commit() AuditLog.log( self.session, self.current_user.id, "grant_permission", "Granted permission with argument: {}".format( form.data["argument"]), on_permission_id=permission.id, on_group_id=group.id, ) return self.redirect("/groups/{}?refresh=yes".format(group.name))
def get_group_view_template_vars(session, actor, group, graph): # type: (Session, User, Group, GroupGraph) -> Dict[str, Any] ret = {} ret["grantable"] = user_grantable_permissions(session, actor) try: group_md = graph.get_group_details(group.name) except NoSuchGroup: # Very new group with no metadata yet, or it has been disabled and # excluded from in-memory cache. group_md = {} ret["members"] = group.my_members() ret["groups"] = group.my_groups() ret["service_accounts"] = get_service_accounts(session, group) ret["permissions"] = group_md.get("permissions", []) for permission in ret["permissions"]: permission["granted_on"] = datetime.fromtimestamp( permission["granted_on"]) ret["permission_requests_pending"] = [] for req in get_pending_request_by_group(session, group): granters = [] for owner, argument in get_owner_arg_list(session, req.permission, req.argument): granters.append(owner.name) ret["permission_requests_pending"].append((req, granters)) ret["audited"] = group_md.get("audited", False) ret["log_entries"] = group.my_log_entries() ret["num_pending"] = count_requests_by_group(session, group, status="pending") ret["current_user_role"] = { "is_owner": user_role_index(actor, ret["members"]) in OWNER_ROLE_INDICES, "is_approver": user_role_index(actor, ret["members"]) in APPROVER_ROLE_INDICES, "is_manager": user_role(actor, ret["members"]) == "manager", "is_member": user_role(actor, ret["members"]) is not None, "role": user_role(actor, ret["members"]), } ret["can_leave"] = (ret["current_user_role"]["is_member"] and not ret["current_user_role"]["is_owner"]) ret["statuses"] = AUDIT_STATUS_CHOICES # Add mapping_id to permissions structure ret["my_permissions"] = group.my_permissions() for perm_up in ret["permissions"]: for perm_direct in ret["my_permissions"]: if (perm_up["permission"] == perm_direct.name and perm_up["argument"] == perm_direct.argument): perm_up["mapping_id"] = perm_direct.mapping_id break ret["alerts"] = [] ret["self_pending"] = count_requests_by_group(session, group, status="pending", user=actor) if ret["self_pending"]: ret["alerts"].append( Alert("info", "You have a pending request to join this group.", None)) return ret
def test_exclude_disabled_permissions( session, standard_graph, graph, users, groups, permissions # noqa: F811 ): """ Ensure that disabled permissions are excluded from various functions/methods that return data from the models. """ perm_ssh = get_permission(session, "ssh") perm_grant = create_permission(session, PERMISSION_GRANT) session.commit() # this user has grouper.permission.grant with argument "ssh/*" grant_permission(groups["group-admins"], perm_grant, argument="ssh/*") graph.update_from_db(session) grant_perms = [ x for x in user_permissions(session, users["*****@*****.**"]) if x.name == PERMISSION_GRANT ] assert "ssh" == filter_grantable_permissions(session, grant_perms)[0][0].name assert "ssh" in (p.name for p in get_all_permissions(session)) assert "ssh" in (p.name for p in get_all_permissions(session, include_disabled=False)) assert "ssh" in (p.name for p in get_all_permissions(session, include_disabled=True)) assert "ssh" in get_grantable_permissions(session, []) assert "team-sre" in [g[0] for g in get_groups_by_permission(session, perm_ssh)] assert get_owner_arg_list(session, perm_ssh, "*") assert "ssh" in get_owners_by_grantable_permission(session) assert "ssh" in (x[0].name for x in user_grantable_permissions(session, users["*****@*****.**"])) assert user_has_permission(session, users["*****@*****.**"], "ssh") assert "ssh" in (p.name for p in user_permissions(session, users["*****@*****.**"])) assert "ssh" in (p["permission"] for p in graph.get_group_details("team-sre")["permissions"]) assert "ssh" in (pt.name for pt in graph.get_permissions()) assert "team-sre" in graph.get_permission_details("ssh")["groups"] assert "ssh" in (p["permission"] for p in graph.get_user_details("*****@*****.**")["permissions"]) # now disable the ssh permission disable_permission(session, "ssh", users["*****@*****.**"].id) graph.update_from_db(session) grant_perms = [ x for x in user_permissions(session, users["*****@*****.**"]) if x.name == PERMISSION_GRANT ] assert not filter_grantable_permissions(session, grant_perms) assert "ssh" not in (p.name for p in get_all_permissions(session)) assert "ssh" not in (p.name for p in get_all_permissions(session, include_disabled=False)) assert "ssh" in (p.name for p in get_all_permissions(session, include_disabled=True)) assert "ssh" not in get_grantable_permissions(session, []) assert not get_groups_by_permission(session, perm_ssh) assert not get_owner_arg_list(session, perm_ssh, "*") assert "ssh" not in get_owners_by_grantable_permission(session) assert "ssh" not in ( x[0].name for x in user_grantable_permissions(session, users["*****@*****.**"]) ) assert not user_has_permission(session, users["*****@*****.**"], "ssh") assert "ssh" not in (p.name for p in user_permissions(session, users["*****@*****.**"])) assert "ssh" not in ( p["permission"] for p in graph.get_group_details("team-sre")["permissions"] ) assert "ssh" not in (pt.name for pt in graph.get_permissions()) assert not graph.get_permission_details("ssh")["groups"] assert "ssh" not in ( p["permission"] for p in graph.get_user_details("*****@*****.**")["permissions"] )
def post(self, name=None): grantable = user_grantable_permissions(self.session, self.current_user) if not grantable: return self.forbidden() group = Group.get(self.session, None, name) if not group: return self.notfound() form = PermissionGrantForm(self.request.arguments) form.permission.choices = [["", "(select one)"]] for perm in grantable: grantable_str = "{} ({})".format(perm[0].name, perm[1]) form.permission.choices.append([perm[0].name, grantable_str]) if not form.validate(): return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors) ) permission = Permission.get(self.session, form.data["permission"]) if not permission: return self.notfound() # Shouldn't happen. allowed = False for perm in grantable: if perm[0].name == permission.name: if matches_glob(perm[1], form.data["argument"]): allowed = True break if not allowed: form.argument.errors.append( "You do not have grant authority over that permission/argument combination." ) return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) # If the permission is audited, then see if the subtree meets auditing requirements. if permission.audited: fail_message = ("Permission is audited and this group (or a subgroup) contains " + "owners, np-owners, or managers who have not received audit training.") try: permission_ok = assert_controllers_are_auditors(group) except UserNotAuditor as e: permission_ok = False fail_message = e if not permission_ok: form.permission.errors.append(fail_message) return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) try: grant_permission(self.session, group.id, permission.id, argument=form.data["argument"]) except IntegrityError: self.session.rollback() form.argument.errors.append( "Permission and Argument already mapped to this group." ) return self.render( "permission-grant.html", form=form, group=group, alerts=self.get_form_alerts(form.errors), ) self.session.commit() AuditLog.log(self.session, self.current_user.id, 'grant_permission', 'Granted permission with argument: {}'.format(form.data["argument"]), on_permission_id=permission.id, on_group_id=group.id) return self.redirect("/groups/{}?refresh=yes".format(group.name))