def get(self): user = self.get_current_user() if not (user_has_permission(self.session, user, AUDIT_VIEWER) or user_has_permission(self.session, user, AUDIT_MANAGER)): return self.forbidden() offset = int(self.get_argument("offset", 0)) limit = int(self.get_argument("limit", 50)) if limit > 200: limit = 200 open_filter = self.get_argument("filter", "Open Audits") audits = get_audits(self.session, only_open=(open_filter == "Open Audits")) open_audits = any([not audit.complete for audit in audits]) total = audits.count() audits = audits.offset(offset).limit(limit).all() open_audits = self.session.query(Audit).filter( Audit.complete == False).all() can_start = user_has_permission(self.session, user, AUDIT_MANAGER) # FIXME(herb): make limit selected from ui audit_log_entries = AuditLog.get_entries(self.session, category=AuditLogCategory.audit, limit=100) self.render( "audits.html", audits=audits, open_filter=open_filter, can_start=can_start, offset=offset, limit=limit, total=total, open_audits=open_audits, audit_log_entries=audit_log_entries, )
def check_access_without_membership(session: Session, actor: User, target: User) -> bool: return (user_has_permission(session, actor, USER_ADMIN) or (target.role_user and is_owner_of_role_user(session, actor, tuser=target)) or user_has_permission( session, actor, USER_ENABLE, argument=target.name))
def post(self, name=None, mapping_id=None): mapping = TagPermissionMap.get(self.session, id=mapping_id) if not mapping: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, mapping.tag.name): return self.forbidden() permission = mapping.permission tag = mapping.tag mapping.delete(self.session) Counter.incr(self.session, "updates") self.session.commit() AuditLog.log( self.session, self.current_user.id, "revoke_tag_permission", "Revoked permission with argument: {}".format(mapping.argument), on_tag_id=tag.id, on_permission_id=permission.id, ) return self.redirect("/tags/{}?refresh=yes".format(tag.name))
def can_manage_role_user(session, user, tuser=None, tgroup=None): # type: (Session, User, User, Group) -> bool """ Indicates whether the user has permission to manage the service account that tuser/tgroup is part of Args: session: the database session user: the User whose permissions are being verified tuser: the service account User we're checking to see can be managed tgroup: the service account Group we're checking to see can be managed Returns: a boolean indicating if user can manage the service account of tuser/tgroup """ try: target = get_role_user(session, tuser, tgroup) except RoleUserNotFound: return False if target.user.name == user.name: return True if user_can_manage_group(session, target.group, user): return True return user_has_permission(session, user, USER_ADMIN)
def is_owner_of_role_user(session, user, tuser=None, tgroup=None): # type: (Session, User, User, Group) -> bool """ Indicates whether the user is an owner of the service account that tuser/tgroup is part of Args: session: the database session user: the User whose permissions are being verified tuser: the service account User we're checking to see is owned tgroup: the service account Group we're checking to see is owned Returns: a boolean indicating if user is an owner of the service account of tuser/tgroup """ try: target = get_role_user(session, tuser, tgroup) except RoleUserNotFound: return False if target.user.name == user.name: return True if user.name in target.group.my_owners_as_strings(): return True return user_has_permission(session, user, USER_ADMIN)
def post(self, tag_id=None, name=None): tag = PublicKeyTag.get(self.session, tag_id, name) if not tag: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name): return self.forbidden() form = TagEditForm(self.request.arguments, obj=tag) if not form.validate(): return self.render( "tag-edit.html", tag=tag, form=form, alerts=self.get_form_alerts(form.errors) ) tag.description = form.data["description"] tag.enabled = form.data["enabled"] Counter.incr(self.session, "updates") try: self.session.commit() except IntegrityError: self.session.rollback() form.tagname.errors.append( "{} already exists".format(form.data["tagname"]) ) return self.render( "tag-edit.html", tag=tag, form=form, alerts=self.get_form_alerts(form.errors) ) AuditLog.log(self.session, self.current_user.id, 'edit_tag', 'Edited tag.', on_tag_id=tag.id) return self.redirect("/tags/{}".format(tag.name))
def get(self, *args, **kwargs): # type: (*Any, **Any) -> None if not user_has_permission(self.session, self.current_user, AUDIT_MANAGER): return self.forbidden() self.render("audit-create.html", form=AuditCreateForm())
def get(self): user = self.get_current_user() if not user_has_permission(self.session, user, AUDIT_MANAGER): return self.forbidden() self.render( "audit-create.html", form=AuditCreateForm(), )
def get(self, name=None, mapping_id=None): mapping = TagPermissionMap.get(self.session, id=mapping_id) if not mapping: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, mapping.tag.name): return self.forbidden() self.render("permission-revoke-tag.html", mapping=mapping)
def post(self, name=None): tag = PublicKeyTag.get(self.session, None, name) if not tag: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name): return self.forbidden() form = PermissionGrantTagForm(self.request.arguments) form.permission.choices = [["", "(select one)"]] for perm in get_all_permissions(self.session): form.permission.choices.append( [perm.name, "{} (*)".format(perm.name)]) if not form.validate(): return self.render( "permission-grant-tag.html", form=form, tag=tag, alerts=self.get_form_alerts(form.errors), ) permission = get_permission(self.session, form.data["permission"]) if not permission: return self.notfound() # Shouldn't happen. success = grant_permission_to_tag(self.session, tag.id, permission.id, argument=form.data["argument"]) if not success: form.argument.errors.append( "Permission and Argument already mapped to this tag.") return self.render( "permission-grant-tag.html", form=form, tag=tag, alerts=self.get_form_alerts(form.errors), ) AuditLog.log( self.session, self.current_user.id, "grant_permission_tag", "Granted permission with argument: {}".format( form.data["argument"]), on_permission_id=permission.id, on_tag_id=tag.id, ) return self.redirect("/tags/{}?refresh=yes".format(tag.name))
def get(self, tag_id=None, name=None): tag = PublicKeyTag.get(self.session, tag_id, name) if not tag: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name): return self.forbidden() form = TagEditForm(obj=tag) self.render("tag-edit.html", tag=tag, form=form)
def post(self, user_id=None, name=None): if not ( user_is_permission_admin(self.session, self.current_user) or user_has_permission(self.session, self.current_user, AUDIT_MANAGER) ): return self.forbidden() try: disable_permission_auditing(self.session, name, self.current_user.id) except NoSuchPermission: return self.notfound() # No explicit refresh because handler queries SQL. return self.redirect("/permissions/{}".format(name))
def get(self, tag_id=None, name=None): self.handle_refresh() tag = PublicKeyTag.get(self.session, tag_id, name) if not tag: return self.notfound() permissions = get_public_key_tag_permissions(self.session, tag) log_entries = tag.my_log_entries() is_owner = user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name) can_grant = self.session.query(Permission).all() if is_owner else [] self.render( "tag.html", tag=tag, permissions=permissions, can_grant=can_grant, log_entries=log_entries, is_owner=is_owner, )
def post(self, *args: Any, **kwargs: Any) -> None: name = self.get_path_argument("name") if not (user_is_permission_admin(self.session, self.current_user) or user_has_permission(self.session, self.current_user, AUDIT_MANAGER)): return self.forbidden() try: disable_permission_auditing(self.session, name, self.current_user.id) except NoSuchPermission: return self.notfound() # No explicit refresh because handler queries SQL. return self.redirect("/permissions/{}".format(name))
def get(self, name=None): tag = PublicKeyTag.get(self.session, None, name) if not tag: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name): return self.forbidden() form = PermissionGrantTagForm() form.permission.choices = [["", "(select one)"]] for perm in get_all_permissions(self.session): form.permission.choices.append( [perm.name, "{} (*)".format(perm.name)]) return self.render("permission-grant-tag.html", form=form, tag=tag)
def get(self, name=None): tag = PublicKeyTag.get(self.session, None, name) if not tag: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name): return self.forbidden() form = PermissionGrantTagForm() form.permission.choices = [["", "(select one)"]] for perm in self.session.query(Permission).all(): form.permission.choices.append([perm.name, "{} (*)".format(perm.name)]) return self.render( "permission-grant-tag.html", form=form, tag=tag, )
def test_has_permission(session, standard_graph, users): # noqa """ Tests the has_permission method of a user object. """ # In our setup, zorkian has 'audited' with no arguments assert user_has_permission(session, users["*****@*****.**"], "audited"), "zorkian has permission audited" assert not user_has_permission(session, users["*****@*****.**"], "audited", argument='foo'), \ "zorkian has permission audited:foo" assert not user_has_permission(session, users["*****@*****.**"], "audited", argument='*'), \ "zorkian has permission audited:*" # zay has ssh:* assert user_has_permission(session, users["*****@*****.**"], "ssh"), "zay has permission ssh" assert user_has_permission(session, users["*****@*****.**"], "ssh", argument='foo'), "zay has permission ssh:foo" assert user_has_permission(session, users["*****@*****.**"], "ssh", argument='*'), "zay has permission ssh:*"
def expire_nonauditors(self, session): """Checks all enabled audited groups and ensures that all approvers for that group have the PERMISSION_AUDITOR permission. All approvers of audited groups that aren't auditors have their membership in the audited group set to expire settings.nonauditor_expiration_days days in the future. Args: session (Session): database session """ now = datetime.utcnow() graph = Graph() exp_days = timedelta(days=settings.nonauditor_expiration_days) # Hack to ensure the graph is loaded before we access it graph.update_from_db(session) # TODO(tyleromeara): replace with graph call for group in get_audited_groups(session): members = group.my_members() # Go through every member of the group and set them to expire if they are an approver # but not an auditor for (type_, member), edge in members.iteritems(): # Auditing is already inherited, so we don't need to handle that here if type_ == "Group": continue member = User.get(session, name=member) member_is_approver = user_role_index( member, members) in APPROVER_ROLE_INDICIES member_is_auditor = user_has_permission( session, member, PERMISSION_AUDITOR) if not member_is_approver or member_is_auditor: continue edge = GroupEdge.get(session, id=edge.edge_id) if edge.expiration and edge.expiration < now + exp_days: continue exp = now + exp_days exp = exp.date() edge.apply_changes_dict({ "expiration": "{}/{}/{}".format(exp.month, exp.day, exp.year) }) edge.add(session) notify_nonauditor_flagged(settings, session, edge) session.commit()
def post(self, name=None, mapping_id=None): mapping = TagPermissionMap.get(self.session, id=mapping_id) if not mapping: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, mapping.tag.name): return self.forbidden() permission = mapping.permission tag = mapping.tag mapping.delete(self.session) Counter.incr(self.session, "updates") self.session.commit() AuditLog.log(self.session, self.current_user.id, 'revoke_tag_permission', 'Revoked permission with argument: {}'.format(mapping.argument), on_tag_id=tag.id, on_permission_id=permission.id) return self.redirect('/tags/{}?refresh=yes'.format(tag.name))
def post(self, name=None): tag = PublicKeyTag.get(self.session, None, name) if not tag: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name): return self.forbidden() form = PermissionGrantTagForm(self.request.arguments) form.permission.choices = [["", "(select one)"]] for perm in self.session.query(Permission).all(): form.permission.choices.append([perm.name, "{} (*)".format(perm.name)]) if not form.validate(): return self.render( "permission-grant-tag.html", form=form, tag=tag, alerts=self.get_form_alerts(form.errors) ) permission = Permission.get(self.session, form.data["permission"]) if not permission: return self.notfound() # Shouldn't happen. success = grant_permission_to_tag(self.session, tag.id, permission.id, argument=form.data["argument"]) if not success: form.argument.errors.append( "Permission and Argument already mapped to this tag." ) return self.render( "permission-grant-tag.html", form=form, tag=tag, alerts=self.get_form_alerts(form.errors), ) AuditLog.log(self.session, self.current_user.id, 'grant_permission_tag', 'Granted permission with argument: {}'.format(form.data["argument"]), on_permission_id=permission.id, on_tag_id=tag.id) return self.redirect("/tags/{}?refresh=yes".format(tag.name))
def get(self, name=None): # TODO: use cached data instead, add refresh to appropriate redirects. permission = get_permission(self.session, name) if not permission: return self.notfound() can_change_audit_status = user_is_permission_admin( self.session, self.current_user) or user_has_permission( self.session, self.current_user, AUDIT_MANAGER) can_disable = user_is_permission_admin(self.session, self.current_user) mapped_groups = get_groups_by_permission(self.session, permission) log_entries = get_log_entries_by_permission(self.session, permission) self.render( "permission.html", permission=permission, can_disable=can_disable, mapped_groups=mapped_groups, log_entries=log_entries, can_change_audit_status=can_change_audit_status, )
def expire_nonauditors(self, session): # type: (Session) -> None """Checks all enabled audited groups and ensures that all approvers for that group have the PERMISSION_AUDITOR permission. All approvers of audited groups that aren't auditors have their membership in the audited group set to expire settings.nonauditor_expiration_days days in the future. Args: session (Session): database session """ now = datetime.utcnow() graph = Graph() exp_days = timedelta(days=self.settings.nonauditor_expiration_days) # Hack to ensure the graph is loaded before we access it graph.update_from_db(session) # TODO(tyleromeara): replace with graph call for group in get_audited_groups(session): members = group.my_members() # Go through every member of the group and set them to expire if they are an approver # but not an auditor for (type_, member), edge in members.iteritems(): # Auditing is already inherited, so we don't need to handle that here if type_ == "Group": continue member = User.get(session, name=member) member_is_approver = user_role_index(member, members) in APPROVER_ROLE_INDICES member_is_auditor = user_has_permission(session, member, PERMISSION_AUDITOR) if not member_is_approver or member_is_auditor: continue edge = GroupEdge.get(session, id=edge.edge_id) if edge.expiration and edge.expiration < now + exp_days: continue exp = (now + exp_days).date() edge.apply_changes( {"expiration": "{}/{}/{}".format(exp.month, exp.day, exp.year)} ) edge.add(session) notify_nonauditor_flagged(self.settings, session, edge) session.commit()
def post(self, tag_id=None, name=None): tag = PublicKeyTag.get(self.session, tag_id, name) if not tag: return self.notfound() if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name): return self.forbidden() form = TagEditForm(self.request.arguments, obj=tag) if not form.validate(): return self.render("tag-edit.html", tag=tag, form=form, alerts=self.get_form_alerts(form.errors)) tag.description = form.data["description"] tag.enabled = form.data["enabled"] Counter.incr(self.session, "updates") try: self.session.commit() except IntegrityError: self.session.rollback() form.tagname.errors.append("{} already exists".format( form.data["tagname"])) return self.render("tag-edit.html", tag=tag, form=form, alerts=self.get_form_alerts(form.errors)) AuditLog.log(self.session, self.current_user.id, "edit_tag", "Edited tag.", on_tag_id=tag.id) return self.redirect("/tags/{}".format(tag.name))
def check_access(session, actor, target): if user_has_permission(session, actor, USER_ADMIN): return True return can_manage_service_account(session, target, actor)
def check_access(session: Session, actor: User, target: ServiceAccount) -> bool: if user_has_permission(session, actor, USER_ADMIN): return True return can_manage_service_account(session, target, actor)
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None form = AuditCreateForm(self.request.arguments) if not form.validate(): return self.render( "audit-create.html", form=form, alerts=self.get_form_alerts(form.errors) ) if not user_has_permission(self.session, self.current_user, AUDIT_MANAGER): return self.forbidden() # Step 1, detect if there are non-completed audits and fail if so. open_audits = self.session.query(Audit).filter(Audit.complete == False).all() if open_audits: raise Exception("Sorry, there are audits in progress.") ends_at = datetime.strptime(form.data["ends_at"], "%m/%d/%Y") # Step 2, find all audited groups and schedule audits for each. audited_groups = [] for groupname in self.graph.groups: if not self.graph.get_group_details(groupname)["audited"]: continue group = Group.get(self.session, name=groupname) audit = Audit(group_id=group.id, ends_at=ends_at) try: audit.add(self.session) self.session.flush() except IntegrityError: self.session.rollback() raise Exception("Failed to start the audit. Please try again.") # Update group with new audit audited_groups.append(group) group.audit_id = audit.id # Step 3, now get all members of this group and set up audit rows for those edges. for member in itervalues(group.my_members()): auditmember = AuditMember(audit_id=audit.id, edge_id=member.edge_id) try: auditmember.add(self.session) except IntegrityError: self.session.rollback() raise Exception("Failed to start the audit. Please try again.") self.session.commit() AuditLog.log( self.session, self.current_user.id, "start_audit", "Started global audit.", category=AuditLogCategory.audit, ) # Calculate schedule of emails, basically we send emails at various periods in advance # of the end of the audit period. schedule_times = [] not_before = datetime.utcnow() + timedelta(1) for days_prior in (28, 21, 14, 7, 3, 1): email_time = ends_at - timedelta(days_prior) email_time.replace(hour=17, minute=0, second=0) if email_time > not_before: schedule_times.append((days_prior, email_time)) # Now send some emails. We do this separately/later to ensure that the audits are all # created. Email notifications are sent multiple times if group audits are still # outstanding. for group in audited_groups: mail_to = [ member.name for member in group.my_users() if GROUP_EDGE_ROLES[member.role] in ("owner", "np-owner") ] send_email( self.session, mail_to, "Group Audit: {}".format(group.name), "audit_notice", settings(), {"group": group.name, "ends_at": ends_at}, ) for days_prior, email_time in schedule_times: send_async_email( self.session, mail_to, "Group Audit: {} - {} day(s) left".format(group.name, days_prior), "audit_notice_reminder", settings(), {"group": group.name, "ends_at": ends_at, "days_left": days_prior}, email_time, async_key="audit-{}".format(group.id), ) return self.redirect("/audits")
def post(self, audit_id): if not user_has_permission(self.session, self.current_user, PERMISSION_AUDITOR): return self.forbidden() audit = self.session.query(Audit).filter(Audit.id == audit_id).one() # only owners can complete owner_ids = {member.id for member in audit.group.my_owners().values()} if self.current_user.id not in owner_ids: return self.forbidden() if audit.complete: return self.redirect("/groups/{}".format(audit.group.name)) edges = {} for argument in self.request.arguments: if argument.startswith("audit_"): edges[int(argument.split("_") [1])] = self.request.arguments[argument][0].decode() for audit_member_info in get_group_audit_members_infos( self.session, audit.group): if audit_member_info.audit_member_obj.id in edges: # You can only approve yourself (otherwise you can remove yourself # from the group and leave it ownerless) if audit_member_info.member_obj.id == self.current_user.id: audit_member_info.audit_member_obj.status = "approved" elif edges[audit_member_info.audit_member_obj. id] in AUDIT_STATUS_CHOICES: audit_member_info.audit_member_obj.status = edges[ audit_member_info.audit_member_obj.id] self.session.commit() # If there are still pending statuses, then redirect to the group page. if group_has_pending_audit_members(self.session, audit.group): return self.redirect("/groups/{}".format(audit.group.name)) # Complete audits have to be "enacted" now. This means anybody marked as remove has to # be removed from the group now. try: for audit_member_info in get_group_audit_members_infos( self.session, audit.group): member_obj = audit_member_info.member_obj if audit_member_info.audit_member_obj.status == "remove": audit.group.revoke_member(self.current_user, member_obj, "Revoked as part of audit.") AuditLog.log( self.session, self.current_user.id, "remove_member", "Removed membership in audit: {}".format( member_obj.name), on_group_id=audit.group.id, on_user_id=member_obj.id, category=AuditLogCategory.audit, ) except PluginRejectedGroupMembershipUpdate as e: alert = Alert("danger", str(e)) return self.redirect("/groups/{}".format(audit.group.name), alerts=[alert]) audit.complete = True self.session.commit() # Now cancel pending emails cancel_async_emails(self.session, "audit-{}".format(audit.group.id)) AuditLog.log( self.session, self.current_user.id, "complete_audit", "Completed group audit.", on_group_id=audit.group.id, category=AuditLogCategory.audit, ) # check if all audits are complete if get_audits(self.session, only_open=True).count() == 0: AuditLog.log( self.session, self.current_user.id, "complete_global_audit", "last open audit have been completed", category=AuditLogCategory.audit, ) return self.redirect("/groups/{}".format(audit.group.name))
def check_access(session, actor, target): return user_has_permission(session, actor, USER_ADMIN)
def post(self, audit_id): user = self.get_current_user() if not user_has_permission(self.session, user, PERMISSION_AUDITOR): return self.forbidden() audit = self.session.query(Audit).filter(Audit.id == audit_id).one() # only owners can complete owner_ids = {member.id for member in audit.group.my_owners().values()} if user.id not in owner_ids: return self.forbidden() if audit.complete: return self.redirect("/groups/{}".format(audit.group.name)) edges = {} for argument in self.request.arguments: if argument.startswith('audit_'): edges[int(argument.split('_')[1])] = self.request.arguments[argument][0] for member in audit.my_members(): if member.id in edges: # You can only approve yourself (otherwise you can remove yourself # from the group and leave it ownerless) if member.member.id == user.id: member.status = "approved" elif edges[member.id] in AUDIT_STATUS_CHOICES: member.status = edges[member.id] self.session.commit() # Now if it's completable (no pendings) then mark it complete, else redirect them # to the group page. if not audit.completable: return self.redirect('/groups/{}'.format(audit.group.name)) # Complete audits have to be "enacted" now. This means anybody marked as remove has to # be removed from the group now. for member in audit.my_members(): if member.status == "remove": audit.group.revoke_member(self.current_user, member.member, "Revoked as part of audit.") AuditLog.log(self.session, self.current_user.id, 'remove_member', 'Removed membership in audit: {}'.format(member.member.name), on_group_id=audit.group.id, on_user_id=member.member.id, category=AuditLogCategory.audit) audit.complete = True self.session.commit() # Now cancel pending emails cancel_async_emails(self.session, 'audit-{}'.format(audit.group.id)) AuditLog.log(self.session, self.current_user.id, 'complete_audit', 'Completed group audit.', on_group_id=audit.group.id, category=AuditLogCategory.audit) # check if all audits are complete if get_audits(self.session, only_open=True).count() == 0: AuditLog.log(self.session, self.current_user.id, 'complete_global_audit', 'last open audit have been completed', category=AuditLogCategory.audit) return self.redirect('/groups/{}'.format(audit.group.name))
def check_access(session, actor, target): return (user_has_permission(session, actor, USER_ADMIN) or user_has_permission( session, actor, USER_ENABLE, argument=target.name) or (target.role_user and is_owner_of_service_account( session, actor, tuser=target)))
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 check_access(session: Session, actor: User, target: User) -> bool: return user_has_permission(session, actor, USER_ADMIN) or ( target.role_user and is_owner_of_role_user(session, actor, tuser=target))
def check_access(session: Session, actor: User, target: User) -> bool: return (user_has_permission(session, actor, USER_ADMIN) or user_has_permission( session, actor, USER_DISABLE, argument=target.name) or (target.role_user and is_owner_of_role_user(session, actor, tuser=target)))
def check_access(session: Session, actor: User, target: ServiceAccount) -> bool: return user_has_permission(session, actor, USER_ADMIN)
def post(self): form = AuditCreateForm(self.request.arguments) if not form.validate(): return self.render("audit-create.html", form=form, alerts=self.get_form_alerts(form.errors)) user = self.get_current_user() if not user_has_permission(self.session, user, AUDIT_MANAGER): return self.forbidden() # Step 1, detect if there are non-completed audits and fail if so. open_audits = self.session.query(Audit).filter( Audit.complete == False).all() if open_audits: raise Exception("Sorry, there are audits in progress.") ends_at = datetime.strptime(form.data["ends_at"], "%m/%d/%Y") # Step 2, find all audited groups and schedule audits for each. audited_groups = [] for groupname in self.graph.groups: if not self.graph.get_group_details(groupname)["audited"]: continue group = Group.get(self.session, name=groupname) audit = Audit(group_id=group.id, ends_at=ends_at) try: audit.add(self.session) self.session.flush() except IntegrityError: self.session.rollback() raise Exception("Failed to start the audit. Please try again.") # Update group with new audit audited_groups.append(group) group.audit_id = audit.id # Step 3, now get all members of this group and set up audit rows for those edges. for member in group.my_members().values(): auditmember = AuditMember(audit_id=audit.id, edge_id=member.edge_id) try: auditmember.add(self.session) except IntegrityError: self.session.rollback() raise Exception( "Failed to start the audit. Please try again.") self.session.commit() AuditLog.log( self.session, self.current_user.id, "start_audit", "Started global audit.", category=AuditLogCategory.audit, ) # Calculate schedule of emails, basically we send emails at various periods in advance # of the end of the audit period. schedule_times = [] not_before = datetime.utcnow() + timedelta(1) for days_prior in (28, 21, 14, 7, 3, 1): email_time = ends_at - timedelta(days_prior) email_time.replace(hour=17, minute=0, second=0) if email_time > not_before: schedule_times.append((days_prior, email_time)) # Now send some emails. We do this separately/later to ensure that the audits are all # created. Email notifications are sent multiple times if group audits are still # outstanding. for group in audited_groups: mail_to = [ member.name for member in group.my_users() if GROUP_EDGE_ROLES[member.role] in ("owner", "np-owner") ] send_email( self.session, mail_to, "Group Audit: {}".format(group.name), "audit_notice", settings, { "group": group.name, "ends_at": ends_at }, ) for days_prior, email_time in schedule_times: send_async_email( self.session, mail_to, "Group Audit: {} - {} day(s) left".format( group.name, days_prior), "audit_notice_reminder", settings, { "group": group.name, "ends_at": ends_at, "days_left": days_prior }, email_time, async_key="audit-{}".format(group.id), ) return self.redirect("/audits")
def check_access(session, actor, target): return ( user_has_permission(session, actor, USER_ADMIN) or user_has_permission(session, actor, USER_DISABLE, argument=target.name) or (target.role_user and is_owner_of_role_user(session, actor, tuser=target)) )
def check_access(session, actor, target): return user_has_permission(session, actor, USER_ADMIN) or ( target.role_user and is_owner_of_role_user(session, actor, tuser=target) )
def post(self, audit_id): user = self.get_current_user() if not user_has_permission(self.session, user, PERMISSION_AUDITOR): return self.forbidden() audit = self.session.query(Audit).filter(Audit.id == audit_id).one() # only owners can complete owner_ids = {member.id for member in audit.group.my_owners().values()} if user.id not in owner_ids: return self.forbidden() if audit.complete: return self.redirect("/groups/{}".format(audit.group.name)) edges = {} for argument in self.request.arguments: if argument.startswith('audit_'): edges[int(argument.split('_') [1])] = self.request.arguments[argument][0] for member in audit.my_members(): if member.id in edges: # You can only approve yourself (otherwise you can remove yourself # from the group and leave it ownerless) if member.member.id == user.id: member.status = "approved" elif edges[member.id] in AUDIT_STATUS_CHOICES: member.status = edges[member.id] self.session.commit() # Now if it's completable (no pendings) then mark it complete, else redirect them # to the group page. if not audit.completable: return self.redirect('/groups/{}'.format(audit.group.name)) # Complete audits have to be "enacted" now. This means anybody marked as remove has to # be removed from the group now. try: for member in audit.my_members(): if member.status == "remove": audit.group.revoke_member(self.current_user, member.member, "Revoked as part of audit.") AuditLog.log(self.session, self.current_user.id, 'remove_member', 'Removed membership in audit: {}'.format( member.member.name), on_group_id=audit.group.id, on_user_id=member.member.id, category=AuditLogCategory.audit) except PluginRejectedGroupMembershipUpdate as e: alert = Alert("danger", str(e)) return self.redirect('/groups/{}'.format(audit.group.name), alerts=[alert]) audit.complete = True self.session.commit() # Now cancel pending emails cancel_async_emails(self.session, 'audit-{}'.format(audit.group.id)) AuditLog.log(self.session, self.current_user.id, 'complete_audit', 'Completed group audit.', on_group_id=audit.group.id, category=AuditLogCategory.audit) # check if all audits are complete if get_audits(self.session, only_open=True).count() == 0: AuditLog.log(self.session, self.current_user.id, 'complete_global_audit', 'last open audit have been completed', category=AuditLogCategory.audit) return self.redirect('/groups/{}'.format(audit.group.name))
def check_access_without_membership(session, actor, target): return ( user_has_permission(session, actor, USER_ADMIN) or (target.role_user and is_owner_of_role_user(session, actor, tuser=target)) or user_has_permission(session, actor, USER_ENABLE, argument=target.name) )