def handle(self, request, organization, member_id): try: member = OrganizationMember.objects.get( Q(user__is_active=True) | Q(user__isnull=True), organization=organization, id=member_id, ) except OrganizationMember.DoesNotExist: return self.redirect(get_login_url()) if request.POST.get('op') == 'reinvite' and member.is_pending: return self.resend_invite(request, organization, member) can_admin = request.access.has_scope('member:delete') if can_admin and not request.is_superuser(): acting_member = OrganizationMember.objects.get( user=request.user, organization=organization, ) if roles.get(acting_member.role).priority < roles.get(member.role).priority: can_admin = False else: allowed_roles = [ r for r in roles.get_all() if r.priority <= roles.get(acting_member.role).priority ] can_admin = bool(allowed_roles) elif request.is_superuser(): allowed_roles = roles.get_all() if member.user == request.user or not can_admin: return self.view_member(request, organization, member) form = self.get_form(request, member, allowed_roles) if form.is_valid(): member = form.save(request.user, organization, request.META['REMOTE_ADDR']) messages.add_message(request, messages.SUCCESS, _('Your changes were saved.')) redirect = reverse('sentry-organization-member-settings', args=[organization.slug, member.id]) return self.redirect(redirect) context = { 'member': member, 'form': form, 'role_list': [ (r, r in allowed_roles) for r in roles.get_all() ] } return self.respond('sentry/organization-member-settings.html', context)
def get_allowed_roles(self, request, organization, member=None): can_admin = request.access.has_scope("member:delete") allowed_roles = [] if can_admin and not request.is_superuser(): acting_member = OrganizationMember.objects.get(user=request.user, organization=organization) if member and roles.get(acting_member.role).priority < roles.get(member.role).priority: can_admin = False else: allowed_roles = [r for r in roles.get_all() if r.priority <= roles.get(acting_member.role).priority] can_admin = bool(allowed_roles) elif request.is_superuser(): allowed_roles = roles.get_all() return (can_admin, allowed_roles)
def has_object_permission(self, request, view, project): result = super(ProjectPermission, self).has_object_permission(request, view, project.organization) if not result: return result if project.teams.exists(): return any( has_team_permission(request, team, self.scope_map) for team in project.teams.all() ) elif request.user.is_authenticated(): # this is only for team-less projects if is_active_superuser(request): return True try: role = OrganizationMember.objects.filter( organization=project.organization, user=request.user, ).values_list('role', flat=True).get() except OrganizationMember.DoesNotExist: # this should probably never happen? return False return roles.get(role).is_global elif hasattr(request.auth, 'project_id') and project.id == request.auth.project_id: return True return False
def get_project_ids(self, request, organization): project_ids = set(map(int, request.GET.getlist('project'))) requested_projects = project_ids.copy() om_role = OrganizationMember.objects.filter( user=request.user, organization=organization, ).values_list('role', flat=True).get() if request.user.is_superuser or (om_role and roles.get(om_role).is_global): qs = Project.objects.filter( organization=organization, status=ProjectStatus.VISIBLE, ) else: qs = Project.objects.filter( organization=organization, teams__in=OrganizationMemberTeam.objects.filter( organizationmember__user=request.user, organizationmember__organization=organization, ).values_list('team'), status=ProjectStatus.VISIBLE, ) if project_ids: qs = qs.filter(id__in=project_ids) project_ids = set(qs.values_list('id', flat=True)) if requested_projects and project_ids != requested_projects: raise PermissionDenied return list(project_ids)
def from_member(member, scopes=None): # TODO(dcramer): we want to optimize this access pattern as its several # network hops and needed in a lot of places requires_sso, sso_is_valid = _sso_params(member) team_list = member.get_teams() project_list = list(Project.objects.filter( status=ProjectStatus.VISIBLE, teams__in=team_list ).distinct()) if scopes is not None: scopes = set(scopes) & member.get_scopes() else: scopes = member.get_scopes() return Access( is_active=True, requires_sso=requires_sso, sso_is_valid=sso_is_valid, scopes=scopes, organization_id=member.organization_id, teams=team_list, projects=project_list, has_global_access=bool(member.organization.flags.allow_joinleave) or roles.get(member.role).is_global, permissions=UserPermission.for_user(member.user_id), )
def send_request_email(self): from sentry.models import OrganizationMember from sentry.utils.email import MessageBuilder user = self.member.user email = user.email organization = self.team.organization context = { 'email': email, 'name': user.get_display_name(), 'organization': organization, 'team': self.team, 'url': absolute_uri(reverse('sentry-organization-members', kwargs={ 'organization_slug': organization.slug, }) + '?ref=access-requests'), } msg = MessageBuilder( subject='Sentry Access Request', template='sentry/emails/request-team-access.txt', html_template='sentry/emails/request-team-access.html', context=context, ) roles_capable = [ r.id for r in roles.with_scope('team:write') ] non_global_roles = [ r for r in roles_capable if not roles.get(r).is_global or roles.get(r).has_scope('member:write') ] # find members which are either team scoped or have access to all teams member_list = OrganizationMember.objects.filter( Q(role__in=non_global_roles) | Q(teams=self.team, role__in=roles_capable), organization=self.team.organization, user__isnull=False, ).select_related('user') msg.send_async([m.user.email for m in member_list])
def get_allowed_roles(request, organization, member=None): can_admin = request.access.has_scope('member:admin') allowed_roles = [] if can_admin and not is_active_superuser(request): acting_member = member or OrganizationMember.objects.get( user=request.user, organization=organization, ) if member and roles.get(acting_member.role).priority < roles.get(member.role).priority: can_admin = False else: allowed_roles = [ r for r in roles.get_all() if r.priority <= roles.get(acting_member.role).priority ] can_admin = bool(allowed_roles) elif is_active_superuser(request): allowed_roles = roles.get_all() return (can_admin, allowed_roles, )
def get_teams(self): from sentry.models import Team if roles.get(self.role).is_global: return self.organization.team_set.all() return Team.objects.filter( id__in=OrganizationMemberTeam.objects.filter( organizationmember=self, is_active=True, ).values('team') )
def has_projects_access(self, member, organization, requested_projects): has_global_access = roles.get(member.role).is_global if has_global_access: return True member_project_list = Project.objects.filter( organization=organization, teams__in=OrganizationMemberTeam.objects.filter( organizationmember=member, ).values('team'), ).values_list('id', flat=True) return set(requested_projects).issubset(set(member_project_list))
def _can_access(self, request, member, organization): if is_active_superuser(request): return True if not request.user.is_authenticated(): return False if request.user.id == member.user_id: return True acting_member = OrganizationMember.objects.get( organization=organization, user__id=request.user.id, user__is_active=True, ) if roles.get(acting_member.role).is_global and \ roles.can_manage(acting_member.role, member.role): return True return False
def get_access_by_project(self, item_list, user): request = env.request project_teams = list( ProjectTeam.objects.filter( project__in=item_list, ).select_related('team') ) project_team_map = defaultdict(list) for pt in project_teams: project_team_map[pt.project_id].append(pt.team) team_memberships = get_team_memberships([pt.team for pt in project_teams], user) org_roles = get_org_roles([i.organization_id for i in item_list], user) is_superuser = (request and is_active_superuser(request) and request.user == user) result = {} for project in item_list: is_member = any( t.id in team_memberships for t in project_team_map.get(project.id, []) ) org_role = org_roles.get(project.organization_id) if is_member: has_access = True elif is_superuser: has_access = True elif project.organization.flags.allow_joinleave: has_access = True elif org_role and roles.get(org_role).is_global: has_access = True else: has_access = False result[project] = { 'is_member': is_member, 'has_access': has_access, } return result
def get_attrs(self, item_list, user): request = env.request memberships = get_team_memberships(item_list, user) if user.is_authenticated(): access_requests = frozenset( OrganizationAccessRequest.objects.filter( team__in=item_list, member__user=user, ).values_list('team', flat=True) ) else: access_requests = frozenset() org_roles = get_org_roles([t.organization_id for t in item_list], user) avatars = {a.team_id: a for a in TeamAvatar.objects.filter(team__in=item_list)} is_superuser = (request and is_active_superuser(request) and request.user == user) result = {} for team in item_list: is_member = team.id in memberships org_role = org_roles.get(team.organization_id) if is_member: has_access = True elif is_superuser: has_access = True elif team.organization.flags.allow_joinleave: has_access = True elif org_role and roles.get(org_role).is_global: has_access = True else: has_access = False result[team] = { 'pending_request': team.id in access_requests, 'is_member': is_member, 'has_access': has_access, 'avatar': avatars.get(team.id), } return result
def get_attrs(self, item_list, user): request = env.request org_ids = set([t.organization_id for t in item_list]) org_roles = get_org_roles(org_ids, user) member_totals = get_member_totals(item_list, user) memberships = get_team_memberships(item_list, user) access_requests = get_access_requests(item_list, user) avatars = {a.team_id: a for a in TeamAvatar.objects.filter(team__in=item_list)} is_superuser = (request and is_active_superuser(request) and request.user == user) result = {} for team in item_list: is_member = team.id in memberships org_role = org_roles.get(team.organization_id) if is_member: has_access = True elif is_superuser: has_access = True elif team.organization.flags.allow_joinleave: has_access = True elif org_role and roles.get(org_role).is_global: has_access = True else: has_access = False result[team] = { 'pending_request': team.id in access_requests, 'is_member': is_member, 'has_access': has_access, 'avatar': avatars.get(team.id), 'member_count': member_totals.get(team.id, 0), } return result
def merge_to(from_user, to_user): # TODO: we could discover relations automatically and make this useful from sentry import roles from sentry.models import ( AuditLogEntry, Activity, AuthIdentity, GroupAssignee, GroupBookmark, GroupSeen, OrganizationMember, OrganizationMemberTeam, UserAvatar, UserOption ) for obj in OrganizationMember.objects.filter(user=from_user): try: with transaction.atomic(): obj.update(user=to_user) except IntegrityError: pass # identify the highest priority membership to_member = OrganizationMember.objects.get( organization=obj.organization_id, user=to_user, ) if roles.get(obj.role).priority > roles.get(to_member.role).priority: to_member.update(role=obj.role) for team in obj.teams.all(): try: with transaction.atomic(): OrganizationMemberTeam.objects.create( organizationmember=to_member, team=team, ) except IntegrityError: pass model_list = ( GroupAssignee, GroupBookmark, GroupSeen, UserAvatar, UserOption ) for model in model_list: for obj in model.objects.filter(user=from_user): try: with transaction.atomic(): obj.update(user=to_user) except IntegrityError: pass Activity.objects.filter( user=from_user, ).update(user=to_user) AuditLogEntry.objects.filter( actor=from_user, ).update(actor=to_user) AuditLogEntry.objects.filter( target_user=from_user, ).update(target_user=to_user) # remove any duplicate identities that exist on the current user that # might conflict w/ the new users existing SSO AuthIdentity.objects.filter( user=from_user, auth_provider__organization__in=AuthIdentity.objects.filter( user=to_user, ).values('auth_provider__organization') ).delete() AuthIdentity.objects.filter( user=from_user, ).update(user=to_user)
def get_scopes(self): return roles.get(self.role).scopes
def validate_debugFilesRole(self, value): try: roles.get(value) except KeyError: raise serializers.ValidationError("Invalid role") return value
def merge_to(from_user, to_user): # TODO: we could discover relations automatically and make this useful from sentry import roles from sentry.models import ( Activity, AuditLogEntry, AuthIdentity, Authenticator, GroupAssignee, GroupBookmark, GroupSeen, GroupShare, GroupSubscription, OrganizationMember, OrganizationMemberTeam, UserAvatar, UserEmail, UserOption, ) audit_logger.info('user.merge', extra={ 'from_user_id': from_user.id, 'to_user_id': to_user.id, }) for obj in OrganizationMember.objects.filter(user=from_user): try: with transaction.atomic(): obj.update(user=to_user) except IntegrityError: pass # identify the highest priority membership to_member = OrganizationMember.objects.get( organization=obj.organization_id, user=to_user, ) if roles.get(obj.role).priority > roles.get( to_member.role).priority: to_member.update(role=obj.role) for team in obj.teams.all(): try: with transaction.atomic(): OrganizationMemberTeam.objects.create( organizationmember=to_member, team=team, ) except IntegrityError: pass model_list = ( Authenticator, GroupAssignee, GroupBookmark, GroupSeen, GroupShare, GroupSubscription, UserAvatar, UserEmail, UserOption, ) for model in model_list: for obj in model.objects.filter(user=from_user): try: with transaction.atomic(): obj.update(user=to_user) except IntegrityError: pass Activity.objects.filter(user=from_user, ).update(user=to_user) AuditLogEntry.objects.filter(actor=from_user, ).update(actor=to_user) AuditLogEntry.objects.filter( target_user=from_user, ).update(target_user=to_user) # remove any duplicate identities that exist on the current user that # might conflict w/ the new users existing SSO AuthIdentity.objects.filter( user=from_user, auth_provider__organization__in=AuthIdentity.objects.filter( user=to_user, ).values( 'auth_provider__organization')).delete() AuthIdentity.objects.filter(user=from_user, ).update(user=to_user)