def post(self, user_id=None, name=None): user = User.get(self.session, user_id, name) if not user: return self.notfound() if not self.check_access(self.session, self.current_user, user): return self.forbidden() try: if user.role_user: disable_role_user(self.session, user=user) else: disable_user(self.session, user) except PluginRejectedDisablingUser as e: alert = Alert("danger", str(e)) return self.redirect("/users/{}".format(user.name), alerts=[alert]) self.session.commit() AuditLog.log(self.session, self.current_user.id, 'disable_user', 'Disabled user.', on_user_id=user.id) return self.redirect("/users/{}?refresh=yes".format(user.name))
def post(self, group_id=None, name=None): group = Group.get(self.session, group_id, name) if not group: return self.notfound() if not user_can_manage_group(self.session, group, self.current_user): return self.forbidden() form = GroupRemoveForm(self.request.arguments) if not form.validate(): return self.send_error(status_code=400) member_type, member_name = form.data["member_type"], form.data[ "member"] members = group.my_members() if not members.get((member_type.capitalize(), member_name), None): return self.notfound() removed_member = get_user_or_group(self.session, member_name, user_or_group=member_type) if self.current_user == removed_member: return self.send_error( status_code=400, reason="Can't remove yourself. Leave group instead.") role_user = is_role_user(self.session, group=group) if (role_user and get_role_user(self.session, group=group).user.name == removed_member.name): return self.send_error( status_code=400, reason= "Can't remove a service account user from the service account group." ) try: group.revoke_member(self.current_user, removed_member, "Removed by owner/np-owner/manager") AuditLog.log(self.session, self.current_user.id, 'remove_from_group', '{} was removed from the group.'.format( removed_member.name), on_group_id=group.id, on_user_id=removed_member.id) except PluginRejectedGroupMembershipUpdate as e: alert = Alert("danger", str(e)) if role_user: return self.redirect("/service/{}".format(group.name), alerts=[alert]) else: return self.redirect("/groups/{}".format(group.name), alerts=[alert]) return self.redirect("/groups/{}?refresh=yes".format(group.name))
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 post(self, request_id): # check for request existence request = permissions.get_request_by_id(self.session, request_id) if not request: return self.notfound() # check that this user should be actioning this request user_requests, total = permissions.get_requests( self.session, status="pending", limit=None, offset=0, owner=self.current_user) user_request_ids = [ur.id for ur in user_requests.requests] if request.id not in user_request_ids: return self.forbidden() form = PermissionRequestUpdateForm(self.request.arguments) form.status.choices = self._get_choices(request.status) if not form.validate(): change_comment_list = [ (sc, user_requests.comment_by_status_change_id[sc.id]) for sc in user_requests.status_change_by_request_id[request.id] ] return self.render( "permission-request-update.html", form=form, request=request, change_comment_list=change_comment_list, statuses=REQUEST_STATUS_CHOICES, alerts=self.get_form_alerts(form.errors), ) try: permissions.update_request(self.session, request, self.current_user, form.status.data, form.reason.data) except UserNotAuditor as e: alerts = [Alert("danger", str(e))] change_comment_list = [ (sc, user_requests.comment_by_status_change_id[sc.id]) for sc in user_requests.status_change_by_request_id[request.id] ] return self.render( "permission-request-update.html", form=form, request=request, change_comment_list=change_comment_list, statuses=REQUEST_STATUS_CHOICES, alerts=alerts, ) return self.redirect("/permissions/requests?status=pending")
def grant_permission_to_service_account_failed_permission_denied( self, permission, argument, service, message): # type: (str, str, str, str) -> None form = self._get_form(self._grantable) self.render( "service-account-permission-grant.html", form=form, service=service, owner=self._owner, alerts=[Alert("error", message)], )
def disable_permission_failed_existing_grants( self, name, # type: str group_grants, # type: List[GroupPermissionGrant] service_account_grants, # type: List[ServiceAccountPermissionGrant] ): # type: (...) -> None """The permission view page will show the grants, so we don't include them in the error.""" alert = Alert( "danger", ("Permission cannot be disabled while it is still granted to some groups or" " service accounts"), ) self.redirect("/permissions/{}".format(name), alerts=[alert])
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None form, args_by_perm = self._build_form(self.request.arguments) if not form.validate(): return self.render( "permission-request.html", args_by_perm_json=json.dumps(args_by_perm), form=form, alerts=self.get_form_alerts(form.errors), ) group = Group.get(self.session, name=form.group_name.data) if group is None: raise HTTPError(status_code=400, reason="that group does not exist") permission = get_permission(self.session, form.permission_name.data) if permission is None: raise HTTPError(status_code=400, reason="that permission does not exist") if permission.name not in args_by_perm: raise HTTPError(status_code=400, reason="that permission was not in the form") # save off request try: request = permissions.create_request( self.session, self.current_user, group, permission, form.argument.data, form.reason.data, ) except permissions.RequestAlreadyGranted: alerts = [Alert("danger", "This group already has this permission and argument.")] except permissions.RequestAlreadyExists: alerts = [ Alert( "danger", "Request for permission and argument already exists, please wait patiently.", ) ] except permissions.NoOwnersAvailable: self.log_message( "prefilled perm+arg have no owner", group_name=group.name, permission_name=permission.name, argument=form.argument.data, ) alerts = [ Alert( "danger", "No owners available for requested permission and argument." " If this error persists please contact an adminstrator.", ) ] except UserNotAuditor as e: alerts = [Alert("danger", str(e))] else: alerts = [] if alerts: return self.render( "permission-request.html", args_by_perm_json=json.dumps(args_by_perm), form=form, alerts=alerts, ) else: return self.redirect("/permissions/requests/{}".format(request.id))
def post(self, *args, **kwargs): # type: (*Any, **Any) -> None group_id = kwargs.get("group_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] group = Group.get(self.session, group_id, name) if not group or not group.enabled: return self.notfound() members = group.my_members() member_groups = {g for t, g in members if t == "Group"} user_is_member = self._is_user_a_member(group, members) form = GroupJoinForm(self.request.arguments) form.member.choices = self._get_choices(group, member_groups, user_is_member) if not form.validate(): return self.render("group-join.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)) member = self._get_member(form.data["member"]) if not member: return self.render( "group-join.html", form=form, group=group, alerts=[ Alert( "danger", "Unknown user or group: {}".format( form.data["member"])) ], ) fail_message = "This join is denied with this role at this time." try: user_can_join = assert_can_join(group, member, role=form.data["role"]) except UserNotAuditor as e: user_can_join = False fail_message = str(e) if not user_can_join: return self.render( "group-join.html", form=form, group=group, alerts=[ Alert("danger", fail_message, "Audit Policy Enforcement") ], ) if group.canjoin == "nobody": fail_message = "This group cannot be joined at this time." return self.render("group-join.html", form=form, group=group, alerts=[Alert("danger", fail_message)]) if group.require_clickthru_tojoin: if not form.data["clickthru_agreement"]: return self.render( "group-join.html", form=form, group=group, alerts=[ Alert( "danger", "please accept review of the group's description", "Clickthru Enforcement", ) ], ) # We only use the default expiration time if no expiration time was given # This does mean that if a user wishes to join a group with no expiration # (even with an owner's permission) that has an auto expiration, they must # first be accepted to the group and then have the owner edit the user to # have no expiration. expiration = None if form.data["expiration"]: expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y") elif group.auto_expire: expiration = datetime.utcnow() + group.auto_expire request = group.add_member( requester=self.current_user, user_or_group=member, reason=form.data["reason"], status=GROUP_JOIN_CHOICES[group.canjoin], expiration=expiration, role=form.data["role"], ) self.session.commit() if group.canjoin == "canask": AuditLog.log( self.session, self.current_user.id, "join_group", "{} requested to join with role: {}".format( member.name, form.data["role"]), on_group_id=group.id, ) mail_to = [ user.name for user in group.my_users() if GROUP_EDGE_ROLES[user.role] in ("manager", "owner", "np-owner") ] email_context = { "requester": member.name, "requested_by": self.current_user.name, "request_id": request.id, "group_name": group.name, "reason": form.data["reason"], "expiration": expiration, "role": form.data["role"], "references_header": request.reference_id, } subj = self.render_template("email/pending_request_subj.tmpl", group=group.name, user=self.current_user.name) send_email(self.session, mail_to, subj, "pending_request", settings(), email_context) elif group.canjoin == "canjoin": AuditLog.log( self.session, self.current_user.id, "join_group", "{} auto-approved to join with role: {}".format( member.name, form.data["role"]), on_group_id=group.id, ) else: raise Exception("Need to update the GroupJoin.post audit logging") return self.redirect("/groups/{}?refresh=yes".format(group.name))
def post(self, request_id, group_id=None, name=None): group = Group.get(self.session, group_id, name) if not group: return self.notfound() members = group.my_members() my_role = user_role(self.current_user, members) if my_role not in ("manager", "owner", "np-owner"): return self.forbidden() request = self.session.query(Request).filter_by(id=request_id).scalar() if not request: return self.notfound() form = GroupRequestModifyForm(self.request.arguments) form.status.choices = self._get_choices(request.status) updates = request.my_status_updates() if not form.validate(): return self.render("group-request-update.html", group=group, request=request, members=members, form=form, alerts=self.get_form_alerts(form.errors), statuses=REQUEST_STATUS_CHOICES, updates=updates) # We have to test this here, too, to ensure that someone can't sneak in with a pending # request that used to be allowed. if form.data["status"] != "cancelled": fail_message = 'This join is denied with this role at this time.' try: user_can_join = assert_can_join(request.requesting, request.get_on_behalf(), role=request.edge.role) except UserNotAuditor as e: user_can_join = False fail_message = e if not user_can_join: return self.render("group-request-update.html", group=group, request=request, members=members, form=form, statuses=REQUEST_STATUS_CHOICES, updates=updates, alerts=[ Alert('danger', fail_message, 'Audit Policy Enforcement') ]) request.update_status(self.current_user, form.data["status"], form.data["reason"]) self.session.commit() AuditLog.log(self.session, self.current_user.id, 'update_request', 'Updated request to status: {}'.format( form.data["status"]), on_group_id=group.id, on_user_id=request.requester.id) edge = self.session.query(GroupEdge).filter_by( id=request.edge_id).one() approver_mail_to = [ user.name for user in group.my_approver_users() if user.name != self.current_user.name and user.name != request.requester.username ] send_email( self.session, approver_mail_to, "Request to join {} by {} has been {}".format( group.groupname, request.requester.name, form.data['status']), "approver_request_updated", settings, { 'group_name': group.name, 'requester': request.requester.username, 'changed_by': self.current_user.name, 'status': form.data['status'], 'role': edge.role, 'reason': form.data['reason'], }, ) if form.data['status'] == 'actioned': send_email( self.session, [request.requester.name], 'Added to group: {}'.format(group.groupname), 'request_actioned', settings, { 'group_name': group.name, 'actioned_by': self.current_user.name, 'reason': form.data['reason'], 'expiration': edge.expiration, 'role': edge.role, }) elif form.data['status'] == 'cancelled': send_email( self.session, [request.requester.name], 'Request to join cancelled: {}'.format(group.groupname), 'request_cancelled', settings, { 'group_name': group.name, 'cancelled_by': self.current_user.name, 'reason': form.data['reason'], 'expiration': edge.expiration, 'role': edge.role, }) # No explicit refresh because handler queries SQL. if form.data['redirect_aggregate']: return self.redirect("/user/requests") else: return self.redirect("/groups/{}/requests".format(group.name))
def post(self, group_id=None, name=None, name2=None, member_type=None): group = Group.get(self.session, group_id, name) if not group: return self.notfound() if self.current_user.name == name2: return self.forbidden() members = group.my_members() my_role = user_role(self.current_user, members) if my_role not in ("manager", "owner", "np-owner"): return self.forbidden() member = members.get((member_type.capitalize(), name2), None) if not member: return self.notfound() if member.type == "Group": user_or_group = Group.get(self.session, member.id) else: user_or_group = User.get(self.session, member.id) if not user_or_group: return self.notfound() edge = GroupEdge.get( self.session, group_id=group.id, member_type=OBJ_TYPES[member.type], member_pk=member.id, ) if not edge: return self.notfound() form = GroupEditMemberForm(self.request.arguments) form.role.choices = [["member", "Member"]] if my_role in ("owner", "np-owner"): form.role.choices.append(["manager", "Manager"]) form.role.choices.append(["owner", "Owner"]) form.role.choices.append(["np-owner", "No-Permissions Owner"]) if not form.validate(): return self.render( "group-edit-member.html", group=group, member=member, edge=edge, form=form, alerts=self.get_form_alerts(form.errors), ) fail_message = 'This join is denied with this role at this time.' try: user_can_join = assert_can_join(group, user_or_group, role=form.data["role"]) except UserNotAuditor as e: user_can_join = False fail_message = e if not user_can_join: return self.render("group-edit-member.html", form=form, group=group, member=member, edge=edge, alerts=[ Alert('danger', fail_message, 'Audit Policy Enforcement') ]) expiration = None if form.data["expiration"]: expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y") try: group.edit_member(self.current_user, user_or_group, form.data["reason"], role=form.data["role"], expiration=expiration) except (InvalidRoleForMember, PluginRejectedGroupMembershipUpdate) as e: return self.render("group-edit-member.html", form=form, group=group, member=member, edge=edge, alerts=[Alert('danger', e.message)]) return self.redirect("/groups/{}?refresh=yes".format(group.name))
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 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 post(self, group_id=None, name=None): group = Group.get(self.session, group_id, name) if not group: return self.notfound() form = GroupJoinForm(self.request.arguments) form.member.choices = self._get_choices(group) if not form.validate(): return self.render("group-join.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)) member = self._get_member(form.data["member"]) fail_message = 'This join is denied with this role at this time.' try: user_can_join = assert_can_join(group, member, role=form.data["role"]) except UserNotAuditor as e: user_can_join = False fail_message = e if not user_can_join: return self.render("group-join.html", form=form, group=group, alerts=[ Alert('danger', fail_message, 'Audit Policy Enforcement') ]) if group.canjoin == "nobody": fail_message = 'This group cannot be joined at this time.' return self.render("group-join.html", form=form, group=group, alerts=[Alert('danger', fail_message)]) # We only use the default expiration time if no expiration time was given # This does mean that if a user wishes to join a group with no expiration # (even with an owner's permission) that has an auto expiration, they must # first be accepted to the group and then have the owner edit the user to # have no expiration. expiration = None if form.data["expiration"]: expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y") elif group.auto_expire: expiration = datetime.utcnow() + group.auto_expire request = group.add_member(requester=self.current_user, user_or_group=member, reason=form.data["reason"], status=GROUP_JOIN_CHOICES[group.canjoin], expiration=expiration, role=form.data["role"]) self.session.commit() if group.canjoin == 'canask': AuditLog.log(self.session, self.current_user.id, 'join_group', '{} requested to join with role: {}'.format( member.name, form.data["role"]), on_group_id=group.id) mail_to = [ user.name for user in group.my_users() if GROUP_EDGE_ROLES[user.role] in ('manager', 'owner', 'np-owner') ] email_context = { "requester": member.name, "requested_by": self.current_user.name, "request_id": request.id, "group_name": group.name, "reason": form.data["reason"], "expiration": expiration, "role": form.data["role"], "references_header": request.reference_id, } subj = self.render_template('email/pending_request_subj.tmpl', group=group.name, user=self.current_user.name) send_email(self.session, mail_to, subj, 'pending_request', settings, email_context) elif group.canjoin == 'canjoin': AuditLog.log(self.session, self.current_user.id, 'join_group', '{} auto-approved to join with role: {}'.format( member.name, form.data["role"]), on_group_id=group.id) else: raise Exception('Need to update the GroupJoin.post audit logging') return self.redirect("/groups/{}?refresh=yes".format(group.name))
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 post(self, *args, **kwargs): # type: (*Any, **Any) -> None request_id = kwargs["request_id"] # type: int group_id = kwargs.get("group_id") # type: Optional[int] name = kwargs.get("name") # type: Optional[str] group = Group.get(self.session, group_id, name) if not group: return self.notfound() members = group.my_members() my_role = user_role(self.current_user, members) if my_role not in ("manager", "owner", "np-owner"): return self.forbidden() request = self.session.query(Request).filter_by(id=request_id).scalar() if not request: return self.notfound() on_behalf = get_on_behalf_by_request(self.session, request) form = GroupRequestModifyForm(self.request.arguments) form.status.choices = self._get_choices(request.status) updates = request.my_status_updates() if not form.status.choices: alerts = [Alert("info", "Request has already been processed")] return self.render( "group-request-update.html", group=group, request=request, on_behalf=on_behalf, members=members, form=form, alerts=alerts, statuses=REQUEST_STATUS_CHOICES, updates=updates, ) if not form.validate(): return self.render( "group-request-update.html", group=group, request=request, on_behalf=on_behalf, members=members, form=form, alerts=self.get_form_alerts(form.errors), statuses=REQUEST_STATUS_CHOICES, updates=updates, ) # We have to test this here, too, to ensure that someone can't sneak in with a pending # request that used to be allowed. if form.data["status"] != "cancelled": fail_message = "This join is denied with this role at this time." try: user_can_join = assert_can_join( request.requesting, on_behalf, role=request.edge.role ) except UserNotAuditor as e: user_can_join = False fail_message = str(e) if not user_can_join: return self.render( "group-request-update.html", group=group, request=request, on_behalf=on_behalf, members=members, form=form, statuses=REQUEST_STATUS_CHOICES, updates=updates, alerts=[Alert("danger", fail_message, "Audit Policy Enforcement")], ) request.update_status(self.current_user, form.data["status"], form.data["reason"]) self.session.commit() AuditLog.log( self.session, self.current_user.id, "update_request", "Updated request to status: {}".format(form.data["status"]), on_group_id=group.id, on_user_id=request.requester.id, ) edge = self.session.query(GroupEdge).filter_by(id=request.edge_id).one() approver_mail_to = [ user.name for user in group.my_approver_users() if user.name != self.current_user.name and user.name != request.requester.username ] subj = "Re: " + self.render_template( "email/pending_request_subj.tmpl", group=group.name, user=request.requester.username ) send_email( self.session, approver_mail_to, subj, "approver_request_updated", settings(), { "group_name": group.name, "requester": request.requester.username, "changed_by": self.current_user.name, "status": form.data["status"], "role": edge.role, "reason": form.data["reason"], "references_header": request.reference_id, }, ) if form.data["status"] == "actioned": send_email( self.session, [request.requester.name], "Added to group: {}".format(group.groupname), "request_actioned", settings(), { "group_name": group.name, "actioned_by": self.current_user.name, "reason": form.data["reason"], "expiration": edge.expiration, "role": edge.role, }, ) elif form.data["status"] == "cancelled": send_email( self.session, [request.requester.name], "Request to join cancelled: {}".format(group.groupname), "request_cancelled", settings(), { "group_name": group.name, "cancelled_by": self.current_user.name, "reason": form.data["reason"], "expiration": edge.expiration, "role": edge.role, }, ) # No explicit refresh because handler queries SQL. if form.data["redirect_aggregate"]: return self.redirect("/user/requests") else: return self.redirect("/groups/{}/requests".format(group.name))
def post(self, group_id=None, name=None): group = Group.get(self.session, group_id, name) if not group: return self.notfound() if not user_can_manage_group(self.session, group, self.current_user): return self.forbidden() members = group.my_members() my_role = user_role(self.current_user, members) form = self.get_form(role=my_role) if not form.validate(): return self.render("group-add.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)) member = get_user_or_group(self.session, form.data["member"]) if member.type == "User" and is_role_user(self.session, member): # For service accounts, we want to always add the group to other groups, not the user member = get_role_user(self.session, user=member).group if not member: form.member.errors.append("User or group not found.") elif (member.type, member.name) in group.my_members(): form.member.errors.append( "User or group is already a member of this group.") elif group.name == member.name: form.member.errors.append( "By definition, this group is a member of itself already.") # Ensure this doesn't violate auditing constraints fail_message = 'This join is denied with this role at this time.' try: user_can_join = assert_can_join(group, member, role=form.data["role"]) except UserNotAuditor as e: user_can_join = False fail_message = e if not user_can_join: form.member.errors.append(fail_message) if form.member.errors: return self.render("group-add.html", form=form, group=group, alerts=self.get_form_alerts(form.errors)) expiration = None if form.data["expiration"]: expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y") try: group.add_member(requester=self.current_user, user_or_group=member, reason=form.data["reason"], status='actioned', expiration=expiration, role=form.data["role"]) except InvalidRoleForMember as e: return self.render("group-add.html", form=form, group=group, alerts=[Alert('danger', e.message)]) self.session.commit() on_user_id = member.id if member.type == "User" else None AuditLog.log(self.session, self.current_user.id, 'join_group', '{} added to group with role: {}'.format( member.name, form.data["role"]), on_group_id=group.id, on_user_id=on_user_id) if member.type == "User": send_email( self.session, [member.name], 'Added to group: {}'.format(group.name), 'request_actioned', settings, { 'group_name': group.name, 'actioned_by': self.current_user.name, 'reason': form.data['reason'], 'expiration': expiration, 'role': form.data['role'], }) return self.redirect("/groups/{}?refresh=yes".format(group.name))
def post(self, group_id=None, name=None): group = Group.get(self.session, group_id, name) if not group: return self.notfound() # Only members can request permissions if not self.current_user.is_member(group.my_members()): return self.forbidden() # check inputs args_by_perm = get_grantable_permissions( self.session, settings.restricted_ownership_permissions) dropdown_form, text_form = GroupPermissionRequest._get_forms( args_by_perm, self.request.arguments) argument_type = self.request.arguments.get("argument_type") if argument_type and argument_type[0] == "text": form = text_form elif argument_type and argument_type[0] == "dropdown": form = dropdown_form form.argument.choices = [ (a, a) for a in args_by_perm[form.permission_name.data] ] else: # someone messing with the form self.log_message("unknown argument type", group_name=group.name, argument_type=argument_type) return self.forbidden() if not form.validate(): return self.render( "group-permission-request.html", dropdown_form=dropdown_form, text_form=text_form, group=group, args_by_perm_json=json.dumps(args_by_perm), alerts=self.get_form_alerts(form.errors), dropdown_help=settings.permission_request_dropdown_help, text_help=settings.permission_request_text_help, ) permission = Permission.get(self.session, form.permission_name.data) assert permission is not None, "our prefilled permission should exist or we have problems" # save off request try: request = permissions.create_request(self.session, self.current_user, group, permission, form.argument.data, form.reason.data) except permissions.RequestAlreadyGranted: alerts = [ Alert("danger", "This group already has this permission and argument.") ] except permissions.RequestAlreadyExists: alerts = [ Alert( "danger", "Request for permission and argument already exists, please wait patiently." ) ] except permissions.NoOwnersAvailable: self.log_message("prefilled perm+arg have no owner", group_name=group.name, permission_name=permission.name, argument=form.argument.data) alerts = [ Alert( "danger", "No owners available for requested permission and argument." " If this error persists please contact an adminstrator.") ] else: alerts = None if alerts: return self.render( "group-permission-request.html", dropdown_form=dropdown_form, text_form=text_form, group=group, args_by_perm_json=json.dumps(args_by_perm), alerts=alerts, ) else: return self.redirect("/permissions/requests/{}".format(request.id))