def test_send_request_notification_email(self): organization = self.create_organization() user1 = self.create_user(email="manager@localhost") user2 = self.create_user(email="owner@localhost") user3 = self.create_user(email="member@localhost") self.create_member(organization=organization, user=user1, role="manager") self.create_member(organization=organization, user=user2, role="owner") self.create_member(organization=organization, user=user3, role="member") member = OrganizationMember( id=1, role="manager", organization=organization, email="*****@*****.**", inviter=user3, invite_status=InviteStatus.REQUESTED_TO_BE_INVITED.value, ) with self.options({"system.url-prefix": "http://example.com"}), self.tasks(): member.send_request_notification_email() assert len(mail.outbox) == 2 assert mail.outbox[0].to == ["manager@localhost"] assert mail.outbox[1].to == ["owner@localhost"] expected_subject = "Access request to %s" % (organization.name, ) assert mail.outbox[0].subject == expected_subject
def serialize(self, obj: OrganizationMember, attrs: Mapping[str, Any], user: Any, **kwargs: Any) -> MutableMapping[str, JSONData]: d = { "id": str(obj.id), "email": obj.get_email(), "name": obj.user.get_display_name() if obj.user else obj.get_email(), "user": attrs["user"], "role": obj.role, "roleName": roles.get(obj.role).name, "pending": obj.is_pending, "expired": obj.token_expired, "flags": { "sso:linked": bool(getattr(obj.flags, "sso:linked")), "sso:invalid": bool(getattr(obj.flags, "sso:invalid")), "member-limit:restricted": bool(getattr(obj.flags, "member-limit:restricted")), }, "dateCreated": obj.date_added, "inviteStatus": obj.get_invite_status_name(), "inviterName": obj.inviter.get_display_name() if obj.inviter else None, } if "externalUsers" in self.expand: d["externalUsers"] = attrs.get("externalUsers", []) return d
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_send_sso_link_email(self): organization = self.create_organization() member = OrganizationMember(id=1, organization=organization, email="*****@*****.**") with self.options({"system.url-prefix": "http://example.com"}), self.tasks(): member.send_invite_email() assert len(mail.outbox) == 1 msg = mail.outbox[0] assert msg.to == ["*****@*****.**"]
def test_delete_expired_leave_null_expires(self): organization = self.create_organization() member = OrganizationMember.objects.create( organization=organization, role="member", email="*****@*****.**", token="abc-def", token_expires_at=None, ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.get(id=member.id)
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_regenerate_token(self): organization = self.create_organization() member = OrganizationMember(organization=organization, email="*****@*****.**") assert member.token is None assert member.token_expires_at is None member.regenerate_token() assert member.token assert member.token_expires_at expires_at = timezone.now() + timedelta(days=INVITE_DAYS_VALID) assert member.token_expires_at.date() == expires_at.date()
def test_delete_expired_leave_null_expires(self): organization = self.create_organization() member = OrganizationMember.objects.create( organization=organization, role='member', email='*****@*****.**', token='abc-def', token_expires_at=None ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.get(id=member.id)
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 test_send_sso_link_email(self): organization = self.create_organization() member = OrganizationMember(id=1, organization=organization, email='*****@*****.**') with self.options({'system.url-prefix': 'http://example.com'}), self.tasks(): member.send_invite_email() assert len(mail.outbox) == 1 msg = mail.outbox[0] assert msg.to == ['*****@*****.**']
def test_send_sso_link_email(self): organization = self.create_organization() member = OrganizationMember(id=1, organization=organization, email='*****@*****.**') with self.settings(SENTRY_URL_PREFIX='http://example.com'): member.send_invite_email() assert len(mail.outbox) == 1 msg = mail.outbox[0] assert msg.to == ['*****@*****.**']
def get(self, request): org = Organization(id=1, slug="organization", name="sentry corp") member = OrganizationMember(id=1, organization=org, email="*****@*****.**") context = {"url": member.get_invite_link(), "organization": org} return MailPreview( html_template="sentry/emails/setup_2fa.html", text_template="sentry/emails/setup_2fa.txt", context=context, ).render(request)
def test_send_invite_email(self): organization = self.create_organization() member = OrganizationMember(id=1, organization=organization, email='*****@*****.**') with self.options({'system.url-prefix': 'http://example.com'}), self.tasks(): member.send_invite_email() assert len(mail.outbox) == 1 msg = mail.outbox[0] assert msg.to == ['*****@*****.**']
def test_delete_expired_clear(self): organization = self.create_organization() ninety_one_days = timezone.now() - timedelta(days=1) member = OrganizationMember.objects.create( organization=organization, role="member", email="*****@*****.**", token="abc-def", token_expires_at=ninety_one_days, ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.filter(id=member.id).first() is None
def test_delete_expired_miss(self): organization = self.create_organization() tomorrow = timezone.now() + timedelta(days=1) member = OrganizationMember.objects.create( organization=organization, role='member', email='*****@*****.**', token='abc-def', token_expires_at=tomorrow ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.get(id=member.id)
def test_delete_expired_clear(self): organization = self.create_organization() ninety_one_days = timezone.now() - timedelta(days=1) member = OrganizationMember.objects.create( organization=organization, role='member', email='*****@*****.**', token='abc-def', token_expires_at=ninety_one_days ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.filter(id=member.id).first() is None
def test_delete_expired_miss(self): organization = self.create_organization() tomorrow = timezone.now() + timedelta(days=1) member = OrganizationMember.objects.create( organization=organization, role="member", email="*****@*****.**", token="abc-def", token_expires_at=tomorrow, ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.get(id=member.id)
def test_regenerate_token(self): organization = self.create_organization() member = OrganizationMember( organization=organization, email='*****@*****.**') assert member.token is None assert member.token_expires_at is None member.regenerate_token() assert member.token assert member.token_expires_at expires_at = timezone.now() + timedelta(days=INVITE_DAYS_VALID) assert member.token_expires_at.date() == expires_at.date()
def test_delete_expired_leave_claimed(self): user = self.create_user() organization = self.create_organization() member = OrganizationMember.objects.create( organization=organization, role="member", user=user, email="*****@*****.**", token="abc-def", token_expires_at="2018-01-01 10:00:00", ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.get(id=member.id)
def test_delete_expired_leave_claimed(self): user = self.create_user() organization = self.create_organization() member = OrganizationMember.objects.create( organization=organization, role='member', user=user, email='*****@*****.**', token='abc-def', token_expires_at='2018-01-01 10:00:00' ) OrganizationMember.delete_expired(timezone.now()) assert OrganizationMember.objects.get(id=member.id)
def from_member( member: OrganizationMember, scopes: Optional[Iterable[str]] = None, is_superuser: bool = False, ) -> Access: if scopes is not None: scopes = set(scopes) & member.get_scopes() else: scopes = member.get_scopes() permissions = get_permissions_for_user( member.user_id) if is_superuser else frozenset() return OrganizationMemberAccess(member, scopes, permissions)
def get(self, request: Request) -> Response: org = Organization(id=1, slug="default", name="Default") requester = User(name="Rick Swan") pending_member = OrganizationMember(email="*****@*****.**", organization=org, inviter=requester) recipient = User(name="James Bond") recipient_member = OrganizationMember(user=recipient, organization=org) notification = InviteRequestNotification(pending_member, requester) # hack to avoid a query notification.role_based_recipient_strategy.set_member_in_cache( recipient_member) return render_preview_email_for_notification(notification, recipient)
def invitation(request): org = Organization( id=1, slug='example', name='Example', ) om = OrganizationMember( id=1, email='*****@*****.**', organization=org, ) return MailPreview( html_template='sentry/emails/member-invite.html', text_template='sentry/emails/member-invite.txt', context={ 'email': '*****@*****.**', 'organization': org, 'url': absolute_uri( reverse('sentry-accept-invite', kwargs={ 'member_id': om.id, 'token': om.token, })), }, ).render(request)
def serialize( self, obj: OrganizationMember, attrs: Mapping[str, Any], user: Any, **kwargs: Any ) -> MutableMapping[str, JSONData]: d = { "schemas": [SCIM_SCHEMA_USER], "id": str(obj.id), "userName": obj.get_email(), # TODO: does this get weird with secondary emails? "name": {"givenName": "N/A", "familyName": "N/A"}, "emails": [ {"primary": True, "value": obj.get_email(), "type": "work"} ], # TODO: secondary emails? "active": True, "meta": {"resourceType": "User"}, } return d
def serialize( self, obj: OrganizationMember, attrs: Mapping[str, Any], user: Any, **kwargs: Any ) -> OrganizationMemberSCIMSerializerResponse: result: OrganizationMemberSCIMSerializerResponse = { "schemas": [SCIM_SCHEMA_USER], "id": str(obj.id), "userName": obj.get_email(), "name": {"givenName": "N/A", "familyName": "N/A"}, "emails": [{"primary": True, "value": obj.get_email(), "type": "work"}], "meta": {"resourceType": "User"}, } if "active" in self.expand: result["active"] = True return result
def test_legacy_token_generation_unicode_key(self): member = OrganizationMember(id=1, organization_id=1, email="*****@*****.**") with self.settings( SECRET_KEY=("\xfc]C\x8a\xd2\x93\x04\x00\x81\xeak\x94\x02H" "\x1d\xcc&P'q\x12\xa2\xc0\xf2v\x7f\xbb*lX")): assert member.legacy_token == "df41d9dfd4ba25d745321e654e15b5d0"
def get(self, request: Request) -> Response: org = Organization(id=1, slug="default", name="Default") user_to_join = User(name="Rick Swan") pending_member = OrganizationMember( email="*****@*****.**", organization=org, user=user_to_join, invite_status=InviteStatus.REQUESTED_TO_JOIN.value, ) recipient = User(name="James Bond") recipient_member = OrganizationMember(user=recipient, organization=org) notification = JoinRequestNotification(pending_member, user_to_join) # hack to avoid a query notification.role_based_recipient_strategy.set_member_in_cache(recipient_member) return render_preview_email_for_notification(notification, recipient)
def get(self, request): org = Organization( id=1, slug='organization', name='sentry corp', ) member = OrganizationMember( id=1, organization=org, email='*****@*****.**') context = { 'url': member.get_invite_link(), 'organization': org } return MailPreview( html_template='sentry/emails/setup_2fa.html', text_template='sentry/emails/setup_2fa.txt', context=context, ).render(request)
def handle(self, request, organization_slug): try: organization = Organization.objects.get(slug=organization_slug) except Organization.DoesNotExist: messages.add_message( request, messages.ERROR, ERR_LINK_INVALID, ) return self.redirect(reverse('sentry')) try: om = OrganizationMember.objects.get( organization=organization, user=request.user, ) except OrganizationMember.DoesNotExist(): messages.add_message( request, messages.ERROR, ERR_LINK_INVALID, ) return self.redirect(reverse('sentry')) try: auth_provider = AuthProvider.objects.get(organization=organization) except AuthProvider.DoesNotExist: messages.add_message( request, messages.ERROR, ERR_LINK_INVALID, ) return self.redirect( reverse('sentry-organization-home', args=[organization.slug])) if request.method == 'POST': helper = AuthHelper( request=request, organization=organization, auth_provider=auth_provider, flow=AuthHelper.FLOW_LINK_IDENTITY, ) helper.init_pipeline() return helper.next_step() provider = auth_provider.get_provider() context = { 'organization': organization, 'provider_key': provider.key, 'provider_name': provider.name, } return self.respond('sentry/auth-link-identity.html', context)
def _get_member(self, organization, member_id): try: return OrganizationMember.objects.get( Q(invite_status=InviteStatus.REQUESTED_TO_BE_INVITED.value) | Q(invite_status=InviteStatus.REQUESTED_TO_JOIN.value), organization=organization, user__isnull=True, id=member_id, ) except ValueError: raise OrganizationMember.DoesNotExist()
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 get(self, request: Request) -> Response: org = Organization(id=1, slug="petal", name="Petal") project = Project(id=1, slug="nodejs", name="Node.js", organization=org) user = User(name="Nisanthan") OrganizationMember(organization=org, user=user, role="admin") notification = AutoSyncNotification(project) return render_preview_email_for_notification(notification, user)
def _get_member( self, request: Request, organization: Organization, member_id: int | str, invite_status: InviteStatus | None = None, ) -> OrganizationMember: try: return OrganizationMember.objects.get_member_invite_query( member_id).get(organization=organization) except ValueError: raise OrganizationMember.DoesNotExist()
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_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 get(self, request: Request) -> Response: requester_name = request.GET.get("requester_name", "Requester") recipient_name = request.GET.get("recipient_name", "Recipient") org = Organization(id=1, slug="petal", name="Petal") project = Project(id=1, slug="nodejs", name="Node.js", organization=org) user = User(name=recipient_name) member = OrganizationMember(organization=org, user=user, role="admin") preview = MailPreviewAdapter( **get_codeowners_request_builder_args(project, member, requester_name) ) return render_to_response("sentry/debug/mail/preview.html", {"preview": preview})
def call_to_action(self, org: Organization, user: User, member: OrganizationMember): # send invite to setup 2fa email_context = {"url": member.get_invite_link(), "organization": org} subject = "{} {} Mandatory: Enable Two-Factor Authentication".format( options.get("mail.subject-prefix"), org.name.capitalize()) message = MessageBuilder( subject=subject, template="sentry/emails/setup_2fa.txt", html_template="sentry/emails/setup_2fa.html", type="user.setup_2fa", context=email_context, ) message.send_async([member.email])
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
configure() # Create the org, team and project if needed from sentry.models import Team, Project, ProjectKey, User, Organization, OrganizationMember 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()
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)