def post(self, request, organization): serializer = OrganizationMemberSerializer( data={ "email": request.data.get("userName"), "role": roles.get(organization.default_role).id, }, context={ "organization": organization, "allowed_roles": [roles.get(organization.default_role)], "allow_existing_invite_request": True, }, ) if not serializer.is_valid(): if "email" in serializer.errors and any( ("is already a member" in error) for error in serializer.errors["email"]): # we include conflict logic in the serializer, check to see if that was # our error and if so, return a 409 so the scim IDP knows how to handle raise ConflictError(detail=SCIM_409_USER_EXISTS) return Response(serializer.errors, status=400) result = serializer.validated_data with transaction.atomic(): member = OrganizationMember( organization=organization, email=result["email"], role=result["role"], inviter=request.user, ) # TODO: are invite tokens needed for SAML orgs? if settings.SENTRY_ENABLE_INVITES: member.token = member.generate_token() member.save() self.create_audit_entry( request=request, organization_id=organization.id, target_object=member.id, data=member.get_audit_log_data(), event=AuditLogEntryEvent.MEMBER_INVITE if settings.SENTRY_ENABLE_INVITES else AuditLogEntryEvent.MEMBER_ADD, ) if settings.SENTRY_ENABLE_INVITES and result.get("sendInvite"): member.send_invite_email() member_invited.send_robust( member=member, user=request.user, sender=self, referrer=request.data.get("referrer"), ) context = serialize( member, serializer=_scim_member_serializer_with_expansion(organization), ) return Response(context, status=201)
def openid_login_callback(request): #构造需要检查签名的内容 OPENID_RESPONSE = dict(request.GET) SIGNED_CONTENT = [] #import json #print json.dumps(OPENID_RESPONSE, indent=4) for k in OPENID_RESPONSE['openid.signed'][0].split(","): response_data = OPENID_RESPONSE["openid.%s" % k] SIGNED_CONTENT.append("%s:%s\n" % (k, response_data[0])) SIGNED_CONTENT = "".join(SIGNED_CONTENT).encode("UTF-8") # 使用associate请求获得的mac_key与SIGNED_CONTENT进行assoc_type hash, # 检查是否与OpenID Server返回的一致 SIGNED_CONTENT_SIG = base64.b64encode( hmac.new(base64.b64decode(request.session.get('mac_key', '')), SIGNED_CONTENT, hashlib.sha256).digest()) if SIGNED_CONTENT_SIG != OPENID_RESPONSE['openid.sig'][0]: return '认证失败,请重新登录验证' request.session.pop('mac_key', None) email = request.GET.get('openid.sreg.email', '') fullname = request.GET.get('openid.sreg.fullname', '') next_url = request.GET.get('next', '/') login_user = User.objects.filter(username__iexact=email) if login_user.exists(): login_user = login_user[0] login_user.set_password("sentry_netease_openid_pwd") login_user.name = fullname # update by hzwangzhiwei @20160329 login_user.save() else: #不存在数据,则增加数据数用户表 login_user = User(username=email, name=fullname, email=email) login_user.set_password("sentry_netease_openid_pwd") login_user.save() #save to db # 如果不存在将这个人加入到组织member表中 if not OrganizationMember.objects.filter( user=login_user, organization=Organization.get_default()).exists(): # 同时给他们默认的trace收集 # 将用户到组织中 orgMember = OrganizationMember(user=login_user, organization=Organization.get_default()) orgMember.save() orgMember = OrganizationMember.objects.get( user=login_user, organization=Organization.get_default()) # 保存组织者到第一个小组 orgMemTeam = OrganizationMemberTeam(organizationmember=orgMember, team=Team.objects.get(id=1)) orgMemTeam.save() # HACK: grab whatever the first backend is and assume it works login_user.backend = settings.AUTHENTICATION_BACKENDS[0] auth.login(request, login_user) # can_register should only allow a single registration request.session.pop('can_register', None) request.session.pop('needs_captcha', None) return HttpResponseRedirect(next_url)
def test_token_expires_at_set_on_save(self): organization = self.create_organization() member = OrganizationMember(organization=organization, email="*****@*****.**") member.token = member.generate_token() member.save() expires_at = timezone.now() + timedelta(days=INVITE_DAYS_VALID) assert member.token_expires_at assert member.token_expires_at.date() == expires_at.date()
def test_token_expiration(self): organization = self.create_organization() member = OrganizationMember(organization=organization, email="*****@*****.**") member.token = member.generate_token() member.save() assert member.is_pending assert member.token_expired is False member.token_expires_at = timezone.now() - timedelta(minutes=1) assert member.token_expired
def test_token_expires_at_set_on_save(self): organization = self.create_organization() member = OrganizationMember( organization=organization, email='*****@*****.**') member.token = member.generate_token() member.save() expires_at = timezone.now() + timedelta(days=INVITE_DAYS_VALID) assert member.token_expires_at assert member.token_expires_at.date() == expires_at.date()
def sentry_update_organization_member(organization, user, role): model = sentry_find_organization_member(organization, user) existing = model is not None if not existing: model = OrganizationMember() model.user = user model.organization = organization model.role = role model.save() return model, existing
def test_set_user(self): organization = self.create_organization() member = OrganizationMember(organization=organization, email="*****@*****.**") member.token = member.generate_token() member.save() user = self.create_user(email="*****@*****.**") member.set_user(user) assert member.is_pending is False assert member.token_expires_at is None assert member.token is None assert member.email is None
def test_token_expiration(self): organization = self.create_organization() member = OrganizationMember( organization=organization, email='*****@*****.**') member.token = member.generate_token() member.save() assert member.is_pending assert member.token_expired is False member.token_expires_at = timezone.now() - timedelta(minutes=1) assert member.token_expired
def test_set_user(self): organization = self.create_organization() member = OrganizationMember( organization=organization, email='*****@*****.**') member.token = member.generate_token() member.save() user = self.create_user(email='*****@*****.**') member.set_user(user) assert member.is_pending is False assert member.token_expires_at is None assert member.token is None assert member.email is None
def post(self, request, organization): """ Add a Member to Organization ```````````````````````````` Invite a member to the organization. :pparam string organization_slug: the slug of the organization the member will belong to :param string email: the email address to invite :param string role: the role of the new member :param array teams: the slugs of the teams the member should belong to. :auth: required """ # TODO: If the member already exists, should this still update the role and team? # For now, it doesn't, but simply returns the existing object if not features.has('organizations:invite-members', organization, actor=request.user): return Response( { 'organization': 'Your organization is not allowed to invite members' }, status=403) serializer = OrganizationMemberSerializer(data=request.DATA) if not serializer.is_valid(): return Response(serializer.errors, status=400) result = serializer.object _, allowed_roles = get_allowed_roles(request, organization) # ensure listed teams are real teams teams = list( Team.objects.filter( organization=organization, status=TeamStatus.VISIBLE, slug__in=result['teams'], )) if len(set(result['teams'])) != len(teams): return Response({'teams': 'Invalid team'}, 400) if not result['role'] in {r.id for r in allowed_roles}: return Response( {'role': 'You do not have permission to invite that role.'}, 403) # This is needed because `email` field is case sensitive, but from a user perspective, # Sentry treats email as case-insensitive ([email protected] equals [email protected]). existing = OrganizationMember.objects.filter( organization=organization, user__email__iexact=result['email'], user__is_active=True, ).exists() if existing: return Response( {'email': 'The user %s is already a member' % result['email']}, 409) om = OrganizationMember(organization=organization, email=result['email'], role=result['role']) if settings.SENTRY_ENABLE_INVITES: om.token = om.generate_token() try: with transaction.atomic(): om.save() except IntegrityError: return Response( {'email': 'The user %s is already a member' % result['email']}, 409) lock = locks.get(u'org:member:{}'.format(om.id), duration=5) with TimedRetryPolicy(10)(lock.acquire): self.save_team_assignments(om, teams) if settings.SENTRY_ENABLE_INVITES: om.send_invite_email() member_invited.send_robust(member=om, user=request.user, sender=self, referrer=request.DATA.get('referrer')) self.create_audit_entry( request=request, organization_id=organization.id, target_object=om.id, data=om.get_audit_log_data(), event=AuditLogEntryEvent.MEMBER_INVITE if settings.SENTRY_ENABLE_INVITES else AuditLogEntryEvent.MEMBER_ADD, ) return Response(serialize(om), status=201)
def post(self, request, organization): """ Add a Member to Organization ```````````````````````````` Invite a member to the organization. :pparam string organization_slug: the slug of the organization the member will belong to :param string email: the email address to invite :param string role: the role of the new member :param array teams: the slugs of the teams the member should belong to. :auth: required """ if not features.has("organizations:invite-members", organization, actor=request.user): return Response( { "organization": "Your organization is not allowed to invite members" }, status=403) _, allowed_roles = get_allowed_roles(request, organization) serializer = OrganizationMemberSerializer( data=request.data, context={ "organization": organization, "allowed_roles": allowed_roles, "allow_existing_invite_request": True, }, ) if not serializer.is_valid(): return Response(serializer.errors, status=400) result = serializer.validated_data with transaction.atomic(): # remove any invitation requests for this email before inviting OrganizationMember.objects.filter( Q(invite_status=InviteStatus.REQUESTED_TO_BE_INVITED.value) | Q(invite_status=InviteStatus.REQUESTED_TO_JOIN.value), email=result["email"], organization=organization, ).delete() om = OrganizationMember( organization=organization, email=result["email"], role=result["role"], inviter=request.user, ) if settings.SENTRY_ENABLE_INVITES: om.token = om.generate_token() om.save() if result["teams"]: lock = locks.get(u"org:member:{}".format(om.id), duration=5) with TimedRetryPolicy(10)(lock.acquire): save_team_assignments(om, result["teams"]) if settings.SENTRY_ENABLE_INVITES and result.get("sendInvite"): om.send_invite_email() member_invited.send_robust(member=om, user=request.user, sender=self, referrer=request.data.get("referrer")) self.create_audit_entry( request=request, organization_id=organization.id, target_object=om.id, data=om.get_audit_log_data(), event=AuditLogEntryEvent.MEMBER_INVITE if settings.SENTRY_ENABLE_INVITES else AuditLogEntryEvent.MEMBER_ADD, ) return Response(serialize(om), status=201)
def _set_linked_flag(member: OrganizationMember) -> None: if getattr(member.flags, "sso:invalid") or not getattr(member.flags, "sso:linked"): setattr(member.flags, "sso:invalid", False) setattr(member.flags, "sso:linked", True) member.save()
def post(self, request, organization): """ Add a Member to Organization ```````````````````````````` Invite a member to the organization. :pparam string organization_slug: the slug of the organization the member will belong to :param string email: the email address to invite :param string role: the role of the new member :param array teams: the slugs of the teams the member should belong to. :auth: required """ # TODO: If the member already exists, should this still update the role and team? # For now, it doesn't, but simply returns the existing object if not features.has('organizations:invite-members', organization, actor=request.user): return Response( {'organization': 'Your organization is not allowed to invite members'}, status=403) serializer = OrganizationMemberSerializer(data=request.DATA) if not serializer.is_valid(): return Response(serializer.errors, status=400) result = serializer.object _, allowed_roles = get_allowed_roles(request, organization) # ensure listed teams are real teams teams = list(Team.objects.filter( organization=organization, status=TeamStatus.VISIBLE, slug__in=result['teams'], )) if len(set(result['teams'])) != len(teams): return Response({'teams': 'Invalid team'}, 400) if not result['role'] in {r.id for r in allowed_roles}: return Response({'role': 'You do not have permission to invite that role.'}, 403) # This is needed because `email` field is case sensitive, but from a user perspective, # Sentry treats email as case-insensitive ([email protected] equals [email protected]). existing = OrganizationMember.objects.filter( organization=organization, user__email__iexact=result['email'], user__is_active=True, ).exists() if existing: return Response({'email': 'The user %s is already a member' % result['email']}, 409) om = OrganizationMember( organization=organization, email=result['email'], role=result['role']) if settings.SENTRY_ENABLE_INVITES: om.token = om.generate_token() try: with transaction.atomic(): om.save() except IntegrityError: return Response({'email': 'The user %s is already a member' % result['email']}, 409) lock = locks.get(u'org:member:{}'.format(om.id), duration=5) with TimedRetryPolicy(10)(lock.acquire): self.save_team_assignments(om, teams) if settings.SENTRY_ENABLE_INVITES: om.send_invite_email() member_invited.send_robust(member=om, user=request.user, sender=self, referrer=request.DATA.get('referrer')) self.create_audit_entry( request=request, organization_id=organization.id, target_object=om.id, data=om.get_audit_log_data(), event=AuditLogEntryEvent.MEMBER_INVITE if settings.SENTRY_ENABLE_INVITES else AuditLogEntryEvent.MEMBER_ADD, ) return Response(serialize(om), status=201)
user = User.objects.get(pk=1) name = 'AgoraVoting' name2 = 'AuthApi' if Organization.objects.filter(name=name).count() == 0: organization = Organization() organization.name = name organization.save() om = OrganizationMember() om.organization = organization om.role = 'owner' om.user = user om.save() team = Team() team.name = name team.organization = organization team.save() project = Project() project.team = team project.name = name2 project.organization = organization project.save() else: organization = Organization.objects.filter(name=name).all()[0] team = Team.objects.filter(name=name, organization=organization).all()[0] project =Project.objects.filter(team=team, name=name2, organization=organization).all()[0]
user = User.objects.get(pk=1) name = 'AgoraVoting' name2 = 'AuthApi' if Organization.objects.filter(name=name).count() == 0: organization = Organization() organization.name = name organization.save() om = OrganizationMember() om.organization = organization om.role = 'owner' om.user = user om.save() team = Team() team.name = name team.organization = organization team.save() project = Project() project.team = team project.name = name2 project.organization = organization project.save() else: organization = Organization.objects.filter(name=name).all()[0] team = Team.objects.filter(name=name, organization=organization).all()[0] project = Project.objects.filter(team=team,
def put( self, request: Request, organization: Organization, member: OrganizationMember, ) -> Response: serializer = OrganizationMemberSerializer(data=request.data, partial=True) if not serializer.is_valid(): return Response(status=400) try: auth_provider = AuthProvider.objects.get(organization=organization) auth_provider = auth_provider.get_provider() except AuthProvider.DoesNotExist: auth_provider = None allowed_roles = None result = serializer.validated_data # XXX(dcramer): if/when this expands beyond reinvite we need to check # access level if result.get("reinvite"): if member.is_pending: if ratelimits.for_organization_member_invite( organization=organization, email=member.email, user=request.user, auth=request.auth, ): metrics.incr( "member-invite.attempt", instance="rate_limited", skip_internal=True, sample_rate=1.0, ) return Response({"detail": ERR_RATE_LIMITED}, status=429) if result.get("regenerate"): if request.access.has_scope("member:admin"): member.regenerate_token() member.save() else: return Response({"detail": ERR_INSUFFICIENT_SCOPE}, status=400) if member.token_expired: return Response({"detail": ERR_EXPIRED}, status=400) member.send_invite_email() elif auth_provider and not getattr(member.flags, "sso:linked"): member.send_sso_link_email(request.user, auth_provider) else: # TODO(dcramer): proper error message return Response({"detail": ERR_UNINVITABLE}, status=400) if "teams" in result: # dupe code from member_index # ensure listed teams are real teams teams = list( Team.objects.filter(organization=organization, status=TeamStatus.VISIBLE, slug__in=result["teams"])) if len(set(result["teams"])) != len(teams): return Response({"teams": "Invalid team"}, status=400) with transaction.atomic(): # teams may be empty OrganizationMemberTeam.objects.filter( organizationmember=member).delete() OrganizationMemberTeam.objects.bulk_create([ OrganizationMemberTeam(team=team, organizationmember=member) for team in teams ]) if result.get("role"): _, allowed_roles = get_allowed_roles(request, organization) allowed_role_ids = {r.id for r in allowed_roles} # A user cannot promote others above themselves if result["role"] not in allowed_role_ids: return Response( { "role": "You do not have permission to assign the given role." }, status=403) # A user cannot demote a superior if member.role not in allowed_role_ids: return Response( { "role": "You do not have permission to assign a role to the given user." }, status=403, ) if member.user == request.user and (result["role"] != member.role): return Response( {"detail": "You cannot make changes to your own role."}, status=400) member.update(role=result["role"]) self.create_audit_entry( request=request, organization=organization, target_object=member.id, target_user=member.user, event=AuditLogEntryEvent.MEMBER_EDIT, data=member.get_audit_log_data(), ) context = self._serialize_member(member, request, allowed_roles) return Response(context)