Esempio n. 1
0
    def test_totp_can_enroll(self, validate_otp):
        # XXX: Pretend an unbound function exists.
        validate_otp.__func__ = None

        with mock.patch("sentry.auth.authenticators.base.generate_secret_key",
                        return_value="Z" * 32):
            resp = self.get_success_response("me", "totp")

        assert resp.data["secret"] == "Z" * 32
        assert (
            resp.data["qrcode"] ==
            "otpauth://totp/admin%40localhost?issuer=Sentry&secret=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
        )
        assert resp.data["form"]
        assert resp.data["secret"]

        # try to enroll
        with self.tasks():
            self.get_success_response("me",
                                      "totp",
                                      method="post",
                                      **{
                                          "secret": "secret12",
                                          "otp": "1234"
                                      })
        assert validate_otp.call_count == 1
        assert validate_otp.call_args == mock.call("1234")

        interface = Authenticator.objects.get_interface(user=self.user,
                                                        interface_id="totp")
        assert interface
        assert interface.secret == "secret12"
        assert interface.config == {"secret": "secret12"}

        # also enrolls in recovery codes
        recovery = Authenticator.objects.get_interface(user=self.user,
                                                       interface_id="recovery")
        assert recovery.is_enrolled()

        assert_security_email_sent("mfa-added")

        # can rotate in place
        self.get_success_response("me", "totp")
        self.get_success_response("me",
                                  "totp",
                                  method="post",
                                  **{
                                      "secret": "secret56",
                                      "otp": "5678"
                                  })
        assert validate_otp.call_args == mock.call("5678")

        interface = Authenticator.objects.get_interface(user=self.user,
                                                        interface_id="totp")
        assert interface.secret == "secret56"
        assert interface.config == {"secret": "secret56"}
    def test_shutdown(self):
        self.producer.produce(self.topic, json.dumps(self.valid_wrapper))
        valid_wrapper_2 = deepcopy(self.valid_wrapper)
        valid_wrapper_2["payload"]["values"]["hello"] = 25
        valid_wrapper_3 = deepcopy(valid_wrapper_2)
        valid_wrapper_3["payload"]["values"]["hello"] = 5000
        self.producer.produce(self.topic, json.dumps(valid_wrapper_2))
        self.producer.flush()

        counts = [0]

        def mock_callback(*args, **kwargs):
            counts[0] += 1
            if counts[0] > 1:
                raise KeyboardInterrupt()

        mock = Mock()
        mock.side_effect = mock_callback

        register_subscriber(self.registration_key)(mock)
        sub = QuerySubscription.objects.create(
            project=self.project,
            type=self.registration_key,
            subscription_id=self.subscription_id,
            dataset="something",
            query="hello",
            aggregation=0,
            time_window=1,
            resolution=1,
        )
        consumer = QuerySubscriptionConsumer("hi",
                                             topic=self.topic,
                                             commit_batch_size=100)
        consumer.run()
        valid_payload = self.valid_payload
        valid_payload["timestamp"] = parse_date(
            valid_payload["timestamp"]).replace(tzinfo=pytz.utc)
        valid_wrapper_2["payload"]["timestamp"] = parse_date(
            valid_wrapper_2["payload"]["timestamp"]).replace(tzinfo=pytz.utc)
        mock.assert_has_calls(
            [call(valid_payload, sub),
             call(valid_wrapper_2["payload"], sub)])
        # Offset should be committed for the first message, so second run should process
        # the second message again
        self.producer.produce(self.topic, json.dumps(valid_wrapper_3))
        self.producer.flush()
        mock.reset_mock()
        counts[0] = 0
        consumer.run()
        valid_wrapper_3["payload"]["timestamp"] = parse_date(
            valid_wrapper_3["payload"]["timestamp"]).replace(tzinfo=pytz.utc)

        mock.assert_has_calls([
            call(valid_wrapper_2["payload"], sub),
            call(valid_wrapper_3["payload"], sub)
        ])
    def test_prepares_each_component(self, run):
        self.client.get(self.url, format="json")

        calls = [
            call(component=self.component1,
                 install=self.install1,
                 project=self.project),
            call(component=self.component2,
                 install=self.install2,
                 project=self.project),
        ]

        run.assert_has_calls(calls, any_order=True)
Esempio n. 4
0
    def test_shutdown(self):
        valid_wrapper_2 = deepcopy(self.valid_wrapper)
        valid_wrapper_2["payload"]["result"]["hello"] = 25

        valid_wrapper_3 = deepcopy(self.valid_wrapper)
        valid_wrapper_3["payload"]["result"]["hello"] = 5000

        self.producer.produce(self.topic, json.dumps(self.valid_wrapper))
        self.producer.produce(self.topic, json.dumps(valid_wrapper_2))
        self.producer.produce(self.topic, json.dumps(valid_wrapper_3))
        self.producer.flush()

        def normalize_payload(payload):
            return {
                **payload,
                "values":
                payload["result"],
                "timestamp":
                parse_date(payload["timestamp"]).replace(tzinfo=pytz.utc),
            }

        consumer = QuerySubscriptionConsumer("hi",
                                             topic=self.topic,
                                             commit_batch_size=100)

        def mock_callback(*args, **kwargs):
            if mock.call_count >= len(expected_calls):
                consumer.shutdown()

        mock = Mock(side_effect=mock_callback)

        register_subscriber(self.registration_key)(mock)
        sub = self.create_subscription()

        expected_calls = [
            call(normalize_payload(self.valid_payload), sub),
            call(normalize_payload(valid_wrapper_2["payload"]), sub),
        ]

        consumer.run()

        mock.assert_has_calls(expected_calls)

        expected_calls = [
            call(normalize_payload(valid_wrapper_3["payload"]), sub)
        ]
        mock.reset_mock()

        consumer.run()

        mock.assert_has_calls(expected_calls)
    def test_prepares_each_component(self, run):
        self.get_valid_response(self.org.slug,
                                qs_params={"projectId": self.project.id})

        calls = [
            call(component=self.component1,
                 install=self.install1,
                 project=self.project),
            call(component=self.component2,
                 install=self.install2,
                 project=self.project),
        ]

        run.assert_has_calls(calls, any_order=True)
Esempio n. 6
0
    def test_prepares_components_requiring_requests(self, run):
        self.component.schema = {
            "link": {
                "required_fields": [{
                    "type": "select",
                    "name": "foo",
                    "label": "Foo",
                    "uri": "/sentry/foo"
                }],
                "optional_fields": [{
                    "type": "select",
                    "name": "beep",
                    "label": "Beep",
                    "uri": "/sentry/beep"
                }],
            },
            "create": {
                "required_fields": [{
                    "type": "select",
                    "name": "bar",
                    "label": "Bar",
                    "uri": "/sentry/bar"
                }],
                "optional_fields": [{
                    "type": "select",
                    "name": "baz",
                    "label": "Baz",
                    "uri": "/sentry/baz",
                    "skip_load_on_open": True,
                }],
            },
        }

        self.preparer.call()

        assert call(install=self.install,
                    project=self.project,
                    uri="/sentry/foo") in run.mock_calls

        assert (call(install=self.install,
                     project=self.project,
                     uri="/sentry/beep") in run.mock_calls)

        assert call(install=self.install,
                    project=self.project,
                    uri="/sentry/bar") in run.mock_calls

        assert (not call(install=self.install,
                         project=self.project,
                         uri="/sentry/baz") in run.mock_calls)
Esempio n. 7
0
    def test_u2f_can_enroll(self, try_enroll):
        new_options = settings.SENTRY_OPTIONS.copy()
        new_options["system.url-prefix"] = "https://testserver"
        with self.settings(SENTRY_OPTIONS=new_options):
            resp = self.get_success_response("me", "u2f")
            assert resp.data["form"]
            assert "secret" not in resp.data
            assert "qrcode" not in resp.data
            assert resp.data["challenge"]

            with self.tasks():
                self.get_success_response(
                    "me",
                    "u2f",
                    method="post",
                    **{
                        "deviceName": "device name",
                        "challenge": "challenge",
                        "response": "response",
                    },
                )

            assert try_enroll.call_count == 1
            assert try_enroll.call_args == mock.call("challenge", "response",
                                                     "device name")

            assert_security_email_sent("mfa-added")
Esempio n. 8
0
    def test_accept_pending_invite__sms_enroll(self, send_text, validate_otp):
        om = self.get_om_and_init_invite()

        # setup sms
        new_options = settings.SENTRY_OPTIONS.copy()
        new_options["sms.twilio-account"] = "twilio-account"

        with self.settings(SENTRY_OPTIONS=new_options):
            url = reverse(
                "sentry-api-0-user-authenticator-enroll",
                kwargs={"user_id": "me", "interface_id": "sms"},
            )

            resp = self.client.post(url, data={"secret": "secret12", "phone": "1231234"})
            assert resp.status_code == 204

            resp = self.client.post(
                url,
                data={
                    "secret": "secret12",
                    "phone": "1231234",
                    "otp": "123123",
                    "memberId": om.id,
                    "token": om.token,
                },
            )
            assert validate_otp.call_count == 1
            assert validate_otp.call_args == mock.call("123123")

            interface = Authenticator.objects.get_interface(user=self.user, interface_id="sms")
            assert interface.phone_number == "1231234"

        self.assert_invite_accepted(resp, om.id)
    def test_u2f_can_enroll(self, try_enroll, email_log):
        new_options = settings.SENTRY_OPTIONS.copy()
        new_options["system.url-prefix"] = "https://testserver"
        with self.settings(SENTRY_OPTIONS=new_options):
            url = reverse(
                "sentry-api-0-user-authenticator-enroll",
                kwargs={
                    "user_id": "me",
                    "interface_id": "u2f"
                },
            )

            resp = self.client.get(url)
            assert resp.status_code == 200
            assert resp.data["form"]
            assert "secret" not in resp.data
            assert "qrcode" not in resp.data
            assert resp.data["challenge"]

            resp = self.client.post(
                url,
                data={
                    "deviceName": "device name",
                    "challenge": "challenge",
                    "response": "response",
                },
            )
            assert try_enroll.call_count == 1
            assert try_enroll.call_args == mock.call("challenge", "response",
                                                     "device name")
            assert resp.status_code == 204

            self._assert_security_email_sent("mfa-added", email_log)
Esempio n. 10
0
    def test_simple(self, mock_record):
        provider = "dummy"
        request = RequestFactory().post("/auth/sso/")
        request.user = AnonymousUser()

        auth_provider = AuthProvider.objects.create(
            organization=self.organization, provider=provider)
        identity = {"id": "1234", "email": "*****@*****.**", "name": "Morty"}

        auth_identity = handle_new_user(auth_provider, self.organization,
                                        request, identity)
        user = auth_identity.user

        assert user.email == identity["email"]
        assert OrganizationMember.objects.filter(
            organization=self.organization, user=user).exists()

        signup_record = [
            r for r in mock_record.call_args_list if r[0][0] == "user.signup"
        ]
        assert signup_record == [
            mock.call("user.signup",
                      user_id=user.id,
                      source="sso",
                      provider=provider,
                      referrer="in-app")
        ]
Esempio n. 11
0
    def test_should_filter_message(self, mock_is_valid_error_message):
        TestItem = namedtuple("TestItem", "value formatted result")

        items = [
            TestItem({"type": "UnfilteredException"}, "UnfilteredException", True),
            TestItem(
                {"value": "This is an unfiltered exception."},
                "This is an unfiltered exception.",
                True,
            ),
            TestItem(
                {"type": "UnfilteredException", "value": "This is an unfiltered exception."},
                "UnfilteredException: This is an unfiltered exception.",
                True,
            ),
            TestItem(
                {"type": "FilteredException", "value": "This is a filtered exception."},
                "FilteredException: This is a filtered exception.",
                False,
            ),
        ]

        data = {"exception": {"values": [item.value for item in items]}}

        project_config = get_project_config(self.project)
        manager = EventManager(data, project=self.project, project_config=project_config)

        mock_is_valid_error_message.side_effect = [item.result for item in items]

        assert manager.should_filter() == (True, FilterStatKeys.ERROR_MESSAGE)

        assert mock_is_valid_error_message.call_args_list == [
            mock.call(project_config, item.formatted) for item in items
        ]
Esempio n. 12
0
    def test_registration_valid(self, mock_record):
        options.set("auth.allow-registration", True)
        with self.feature("auth:register"):
            resp = self.client.post(
                self.path,
                {
                    "username": "******",
                    "password": "******",
                    "name": "Foo Bar",
                    "op": "register",
                },
            )
        assert resp.status_code == 302, (
            resp.context["register_form"].errors if resp.status_code == 200 else None
        )
        user = User.objects.get(username="******")
        assert user.email == "*****@*****.**"
        assert user.check_password("foobar")
        assert user.name == "Foo Bar"
        assert not OrganizationMember.objects.filter(user=user).exists()

        signup_record = [r for r in mock_record.call_args_list if r[0][0] == "user.signup"]
        assert signup_record == [
            mock.call(
                "user.signup",
                user_id=user.id,
                source="register-form",
                provider=None,
                referrer="in-app",
            )
        ]
Esempio n. 13
0
    def test_sms_can_enroll(self, send_text, validate_otp, email_log):
        new_options = settings.SENTRY_OPTIONS.copy()
        new_options["sms.twilio-account"] = "twilio-account"

        with self.settings(SENTRY_OPTIONS=new_options):
            url = reverse(
                "sentry-api-0-user-authenticator-enroll",
                kwargs={"user_id": "me", "interface_id": "sms"},
            )

            resp = self.client.get(url)
            assert resp.status_code == 200
            assert resp.data["form"]
            assert resp.data["secret"]

            resp = self.client.post(url, data={"secret": "secret12", "phone": "1231234"})
            assert send_text.call_count == 1
            assert validate_otp.call_count == 0
            assert resp.status_code == 204

            resp = self.client.post(
                url, data={"secret": "secret12", "phone": "1231234", "otp": "123123"}
            )
            assert validate_otp.call_count == 1
            assert validate_otp.call_args == mock.call("123123")

            interface = Authenticator.objects.get_interface(user=self.user, interface_id="sms")
            assert interface.phone_number == "1231234"

            self._assert_security_email_sent("mfa-added", email_log)
Esempio n. 14
0
    def test_totp_can_enroll(self, validate_otp, email_log):
        url = reverse(
            "sentry-api-0-user-authenticator-enroll",
            kwargs={"user_id": "me", "interface_id": "totp"},
        )

        resp = self.client.get(url)
        assert resp.status_code == 200
        assert len(resp.data["qrcode"])
        assert resp.data["form"]
        assert resp.data["secret"]

        # try to enroll
        resp = self.client.post(url, data={"secret": "secret12", "otp": "1234"})
        assert validate_otp.call_count == 1
        assert validate_otp.call_args == mock.call("1234")
        assert resp.status_code == 204

        interface = Authenticator.objects.get_interface(user=self.user, interface_id="totp")
        assert interface

        # also enrolls in recovery codes
        recovery = Authenticator.objects.get_interface(user=self.user, interface_id="recovery")
        assert recovery.is_enrolled

        self._assert_security_email_sent("mfa-added", email_log)

        # can't enroll again because no multi enrollment is allowed
        resp = self.client.get(url)
        assert resp.status_code == 400
        resp = self.client.post(url)
        assert resp.status_code == 400
Esempio n. 15
0
def test_future_set_callback_empty():
    future_set = FutureSet([])

    callback = mock.Mock()
    future_set.add_done_callback(callback)

    assert callback.call_count == 1
    assert callback.call_args == mock.call(future_set)
Esempio n. 16
0
    def test_process_pending_partitions_none(self, process_pending,
                                             process_incr):
        self.buf.pending_partitions = 2
        with self.buf.cluster.map() as client:
            client.zadd("b:p:0", {"foo": 1})
            client.zadd("b:p:1", {"bar": 1})
            client.zadd("b:p", {"baz": 1})

        # On first pass, we are expecting to do:
        # * process the buffer that doesn't have a partition (b:p)
        # * queue up 2 jobs, one for each partition to process.
        self.buf.process_pending()
        assert len(process_incr.apply_async.mock_calls) == 1
        process_incr.apply_async.assert_any_call(
            kwargs={"batch_keys": ["baz"]})
        assert len(process_pending.apply_async.mock_calls) == 2
        process_pending.apply_async.mock_calls == [
            mock.call(kwargs={"partition": 0}),
            mock.call(kwargs={"partition": 1}),
        ]

        # Confirm that we've only processed the unpartitioned buffer
        client = self.buf.cluster.get_routing_client()
        assert client.zrange("b:p", 0, -1) == []
        assert client.zrange("b:p:0", 0, -1) != []
        assert client.zrange("b:p:1", 0, -1) != []

        # partition 0
        self.buf.process_pending(partition=0)
        assert len(process_incr.apply_async.mock_calls) == 2
        process_incr.apply_async.assert_any_call(
            kwargs={"batch_keys": ["foo"]})
        assert client.zrange("b:p:0", 0, -1) == []

        # Make sure we didn't queue up more
        assert len(process_pending.apply_async.mock_calls) == 2

        # partition 1
        self.buf.process_pending(partition=1)
        assert len(process_incr.apply_async.mock_calls) == 3
        process_incr.apply_async.assert_any_call(
            kwargs={"batch_keys": ["bar"]})
        assert client.zrange("b:p:1", 0, -1) == []

        # Make sure we didn't queue up more
        assert len(process_pending.apply_async.mock_calls) == 2
Esempio n. 17
0
def test_future_set_callback_error():
    future_set = FutureSet([Future() for i in range(3)])

    callback = mock.Mock()
    future_set.add_done_callback(callback)

    for i, future in enumerate(list(future_set)):
        assert callback.call_count == 0
        future.set_exception(Exception)

    assert callback.call_count == 1
    assert callback.call_args == mock.call(future_set)

    other_callback = mock.Mock()
    future_set.add_done_callback(other_callback)

    assert other_callback.call_count == 1
    assert other_callback.call_args == mock.call(future_set)
Esempio n. 18
0
def test_future_set_callback_success():
    future_set = FutureSet([Future() for i in range(3)])

    callback = mock.Mock()
    future_set.add_done_callback(callback)

    for i, future in enumerate(list(future_set)):
        assert callback.call_count == 0
        future.set_result(True)

    assert callback.call_count == 1
    assert callback.call_args == mock.call(future_set)

    other_callback = mock.Mock()
    future_set.add_done_callback(other_callback)

    assert other_callback.call_count == 1
    assert other_callback.call_args == mock.call(future_set)
Esempio n. 19
0
    def test_invalid_otp(self, validate_otp, email_log):
        url = reverse(
            "sentry-api-0-user-authenticator-enroll",
            kwargs={"user_id": "me", "interface_id": "totp"},
        )

        # try to enroll
        resp = self.client.post(url, data={"secret": "secret12", "otp": "1234"})
        assert validate_otp.call_count == 1
        assert validate_otp.call_args == mock.call("1234")
        assert resp.status_code == 400
        assert email_log.call_count == 0
Esempio n. 20
0
def test_future_broken_callback():
    future_set = FutureSet([])

    callback = mock.Mock(side_effect=Exception("Boom!"))

    try:
        future_set.add_done_callback(callback)
    except Exception:
        assert False, "should not raise"

    assert callback.call_count == 1
    assert callback.call_args == mock.call(future_set)
Esempio n. 21
0
    def assert_action_handler_called_with_actions(self, incident, actions, project=None):
        project = self.project if project is None else project

        if not actions:
            if not incident:
                assert not self.email_action_handler.called
            else:
                for call_args in self.email_action_handler.call_args_list:
                    assert call_args[0][1] != incident
        else:
            self.email_action_handler.assert_has_calls(
                [call(action, incident, project) for action in actions], any_order=True
            )
    def test_totp_can_enroll(self, validate_otp, email_log):
        # XXX: Pretend an unbound function exists.
        validate_otp.__func__ = None

        url = reverse(
            "sentry-api-0-user-authenticator-enroll",
            kwargs={
                "user_id": "me",
                "interface_id": "totp"
            },
        )

        with mock.patch("sentry.auth.authenticators.base.generate_secret_key",
                        return_value="Z" * 32):
            resp = self.client.get(url)

        assert resp.status_code == 200
        assert resp.data["secret"] == "Z" * 32
        assert (
            resp.data["qrcode"] ==
            "otpauth://totp/a%40example.com?issuer=Sentry&secret=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
        )
        assert resp.data["form"]
        assert resp.data["secret"]

        # try to enroll
        resp = self.client.post(url,
                                data={
                                    "secret": "secret12",
                                    "otp": "1234"
                                })
        assert validate_otp.call_count == 1
        assert validate_otp.call_args == mock.call("1234")
        assert resp.status_code == 204

        interface = Authenticator.objects.get_interface(user=self.user,
                                                        interface_id="totp")
        assert interface

        # also enrolls in recovery codes
        recovery = Authenticator.objects.get_interface(user=self.user,
                                                       interface_id="recovery")
        assert recovery.is_enrolled()

        self._assert_security_email_sent("mfa-added", email_log)

        # can't enroll again because no multi enrollment is allowed
        resp = self.client.get(url)
        assert resp.status_code == 400
        resp = self.client.post(url)
        assert resp.status_code == 400
Esempio n. 23
0
    def test_totp_can_enroll(self, validate_otp, email_log):
        # XXX: Pretend an unbound function exists.
        validate_otp.__func__ = None

        url = reverse(
            "sentry-api-0-user-authenticator-enroll",
            kwargs={
                "user_id": "me",
                "interface_id": "totp"
            },
        )

        with mock.patch("sentry.models.authenticator.generate_secret_key",
                        return_value="Z" * 32):
            resp = self.client.get(url)

        assert resp.status_code == 200
        assert resp.data["secret"] == "Z" * 32
        with io.open(get_fixture_path("totp_qrcode.json")) as f:
            assert resp.data["qrcode"] == json.loads(f.read())
        assert resp.data["form"]
        assert resp.data["secret"]

        # try to enroll
        resp = self.client.post(url,
                                data={
                                    "secret": "secret12",
                                    "otp": "1234"
                                })
        assert validate_otp.call_count == 1
        assert validate_otp.call_args == mock.call("1234")
        assert resp.status_code == 204

        interface = Authenticator.objects.get_interface(user=self.user,
                                                        interface_id="totp")
        assert interface

        # also enrolls in recovery codes
        recovery = Authenticator.objects.get_interface(user=self.user,
                                                       interface_id="recovery")
        assert recovery.is_enrolled

        self._assert_security_email_sent("mfa-added", email_log)

        # can't enroll again because no multi enrollment is allowed
        resp = self.client.get(url)
        assert resp.status_code == 400
        resp = self.client.post(url)
        assert resp.status_code == 400
Esempio n. 24
0
    def test_simple(self, mock_record):

        auth_identity = self.handler.handle_new_user(self.identity)
        user = auth_identity.user

        assert user.email == self.identity["email"]
        assert OrganizationMember.objects.filter(organization=self.organization, user=user).exists()

        signup_record = [r for r in mock_record.call_args_list if r[0][0] == "user.signup"]
        assert signup_record == [
            mock.call(
                "user.signup",
                user_id=user.id,
                source="sso",
                provider=self.provider,
                referrer="in-app",
            )
        ]
Esempio n. 25
0
    def test_sms_can_enroll(self, send_text, validate_otp):
        # XXX: Pretend an unbound function exists.
        validate_otp.__func__ = None

        new_options = settings.SENTRY_OPTIONS.copy()
        new_options["sms.twilio-account"] = "twilio-account"

        with self.settings(SENTRY_OPTIONS=new_options):
            resp = self.get_success_response("me", "sms")
            assert resp.data["form"]
            assert resp.data["secret"]

            self.get_success_response("me",
                                      "sms",
                                      method="post",
                                      **{
                                          "secret": "secret12",
                                          "phone": "1231234"
                                      })
            assert send_text.call_count == 1
            assert validate_otp.call_count == 0

            with self.tasks():
                self.get_success_response(
                    "me",
                    "sms",
                    method="post",
                    **{
                        "secret": "secret12",
                        "phone": "1231234",
                        "otp": "123123"
                    },
                )
            assert validate_otp.call_count == 1
            assert validate_otp.call_args == mock.call("123123")

            interface = Authenticator.objects.get_interface(user=self.user,
                                                            interface_id="sms")
            assert interface.phone_number == "1231234"

            assert_security_email_sent("mfa-added")
Esempio n. 26
0
    def test_invalid_otp(self, validate_otp):
        # XXX: Pretend an unbound function exists.
        validate_otp.__func__ = None

        # try to enroll
        with self.tasks():
            self.get_error_response(
                "me",
                "totp",
                method="post",
                status_code=400,
                **{
                    "secret": "secret12",
                    "otp": "1234"
                },
            )

        assert validate_otp.call_count == 1
        assert validate_otp.call_args == mock.call("1234")

        assert len(mail.outbox) == 0
Esempio n. 27
0
    def test_accept_pending_invite__sms_enroll(self, send_text, validate_otp):
        # XXX: Pretend an unbound function exists.
        validate_otp.__func__ = None

        om = self.get_om_and_init_invite()

        # setup sms
        new_options = settings.SENTRY_OPTIONS.copy()
        new_options["sms.twilio-account"] = "twilio-account"

        with self.settings(SENTRY_OPTIONS=new_options):
            self.get_success_response("me",
                                      "sms",
                                      method="post",
                                      **{
                                          "secret": "secret12",
                                          "phone": "1231234"
                                      })
            resp = self.get_success_response(
                "me",
                "sms",
                method="post",
                **{
                    "secret": "secret12",
                    "phone": "1231234",
                    "otp": "123123",
                    "memberId": om.id,
                    "token": om.token,
                },
            )

            assert validate_otp.call_count == 1
            assert validate_otp.call_args == mock.call("123123")

            interface = Authenticator.objects.get_interface(user=self.user,
                                                            interface_id="sms")
            assert interface.phone_number == "1231234"

        self.assert_invite_accepted(resp, om.id)
Esempio n. 28
0
def test_transitions():
    callback = mock.MagicMock()
    state = SynchronizedPartitionStateManager(callback)

    with pytest.raises(InvalidState):
        state.validate_local_message("topic", 0, 0)

    state.set_local_offset("topic", 0, 1)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        0,
        (None, Offsets(None, None)),
        (SynchronizedPartitionState.UNKNOWN, Offsets(1, None)),
    )

    with pytest.raises(InvalidState):
        state.validate_local_message("topic", 0, 0)

    state.set_remote_offset("topic", 0, 1)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        0,
        (SynchronizedPartitionState.UNKNOWN, Offsets(1, None)),
        (SynchronizedPartitionState.SYNCHRONIZED, Offsets(1, 1)),
    )

    with pytest.raises(InvalidStateTransition):
        state.set_local_offset("topic", 0, None)

    with pytest.raises(InvalidStateTransition):
        state.set_remote_offset("topic", 0, None)

    state.set_remote_offset("topic", 0, 2)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        0,
        (SynchronizedPartitionState.SYNCHRONIZED, Offsets(1, 1)),
        (SynchronizedPartitionState.LOCAL_BEHIND, Offsets(1, 2)),
    )

    state.validate_local_message("topic", 0, 1)

    with pytest.raises(MessageNotReady):
        state.validate_local_message("topic", 0, 2)

    state.set_local_offset("topic", 0, 2)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        0,
        (SynchronizedPartitionState.LOCAL_BEHIND, Offsets(1, 2)),
        (SynchronizedPartitionState.SYNCHRONIZED, Offsets(2, 2)),
    )

    state.set_remote_offset("topic", 1, 5)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        1,
        (None, Offsets(None, None)),
        (SynchronizedPartitionState.UNKNOWN, Offsets(None, 5)),
    )

    state.set_local_offset("topic", 1, 0)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        1,
        (SynchronizedPartitionState.UNKNOWN, Offsets(None, 5)),
        (SynchronizedPartitionState.LOCAL_BEHIND, Offsets(0, 5)),
    )

    before_calls = len(callback.mock_calls)
    state.set_local_offset("topic", 1, 1)
    state.set_local_offset("topic", 1, 2)
    state.set_local_offset("topic", 1, 3)
    state.set_local_offset("topic", 1, 4)
    assert len(callback.mock_calls) == before_calls

    state.set_local_offset("topic", 1, 5)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        1,
        (SynchronizedPartitionState.LOCAL_BEHIND, Offsets(4, 5)),
        (SynchronizedPartitionState.SYNCHRONIZED, Offsets(5, 5)),
    )

    state.set_local_offset("topic", 1, 6)
    assert callback.mock_calls[-1] == mock.call(
        "topic",
        1,
        (SynchronizedPartitionState.SYNCHRONIZED, Offsets(5, 5)),
        (SynchronizedPartitionState.REMOTE_BEHIND, Offsets(6, 5)),
    )
Esempio n. 29
0
    def test_compression(self, mock_compress_file):
        """
        For files larger than max memcached payload size we want to avoid
        pointless compression and  caching attempt since it fails silently.

        Tests scenarios:

        - happy path where compressed file is successfully cached
        - compressed payload is too large to cache and we will avoid
          compression and caching while the metadata cache exists

        """
        project = self.project
        release = Release.objects.create(
            organization_id=project.organization_id, version="abc")
        release.add_project(project)

        filename = "file.min.js"
        file = File.objects.create(
            name=filename,
            type="release.file",
            headers={"Content-Type": "application/json; charset=utf-8"},
        )

        binary_body = unicode_body.encode("utf-8")
        file.putfile(BytesIO(binary_body))

        ReleaseFile.objects.create(name="file.min.js",
                                   release=release,
                                   organization_id=project.organization_id,
                                   file=file)

        mock_compress_file.return_value = (binary_body, binary_body)

        releasefile_ident = ReleaseFile.get_ident(filename, None)
        cache_key = get_release_file_cache_key(
            release_id=release.id, releasefile_ident=releasefile_ident)
        cache_key_meta = get_release_file_cache_key_meta(
            release_id=release.id, releasefile_ident=releasefile_ident)

        fetch_release_file(filename, release)

        # Here the ANY is File() retrieved from cache/db
        assert mock_compress_file.mock_calls == [call(ANY)]
        assert cache.get(cache_key_meta)["compressed_size"] == len(binary_body)
        assert cache.get(cache_key)

        # Remove cache and check that calling fetch_release_file will do the
        # compression and caching again

        cache.set(cache_key, None)
        mock_compress_file.reset_mock()

        fetch_release_file(filename, release)

        assert mock_compress_file.mock_calls == [call(ANY)]
        assert cache.get(cache_key_meta)["compressed_size"] == len(binary_body)
        assert cache.get(cache_key)

        # If the file is bigger than the max cache value threshold, avoid
        # compression and caching
        cache.set(cache_key, None)
        mock_compress_file.reset_mock()
        with patch("sentry.lang.javascript.processor.CACHE_MAX_VALUE_SIZE",
                   len(binary_body) - 1):
            result = fetch_release_file(filename, release)

        assert result == http.UrlResult(
            filename,
            {"content-type": "application/json; charset=utf-8"},
            binary_body,
            200,
            "utf-8",
        )

        assert mock_compress_file.mock_calls == []
        assert cache.get(cache_key_meta)["compressed_size"] == len(binary_body)
        assert cache.get(cache_key) is None

        # If the file is bigger than the max cache value threshold, but the
        # metadata cache is empty as well, compress and attempt to cache anyway
        cache.set(cache_key, None)
        cache.set(cache_key_meta, None)
        mock_compress_file.reset_mock()
        with patch("sentry.lang.javascript.processor.CACHE_MAX_VALUE_SIZE",
                   len(binary_body) - 1):
            result = fetch_release_file(filename, release)

        assert result == http.UrlResult(
            filename,
            {"content-type": "application/json; charset=utf-8"},
            binary_body,
            200,
            "utf-8",
        )

        assert mock_compress_file.mock_calls == [call(ANY)]
        assert cache.get(cache_key_meta)["compressed_size"] == len(binary_body)
        assert cache.get(cache_key)

        # If the file is smaller than the max cache value threshold, but the
        # cache is empty, compress and cache
        cache.set(cache_key, None)
        mock_compress_file.reset_mock()
        with patch("sentry.lang.javascript.processor.CACHE_MAX_VALUE_SIZE",
                   len(binary_body) + 1):
            result = fetch_release_file(filename, release)

        assert result == http.UrlResult(
            filename,
            {"content-type": "application/json; charset=utf-8"},
            binary_body,
            200,
            "utf-8",
        )

        assert mock_compress_file.mock_calls == [call(ANY)]
        assert cache.get(cache_key_meta)["compressed_size"] == len(binary_body)
        assert cache.get(cache_key)