mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
from time import time
|
|
from unittest import mock
|
|
|
|
from django.core import mail
|
|
from django.urls import reverse
|
|
|
|
from sentry.auth.authenticators.totp import TotpInterface
|
|
from sentry.testutils.cases import TestCase
|
|
from sentry.testutils.helpers.datetime import freeze_time
|
|
from sentry.testutils.outbox import outbox_runner
|
|
from sentry.testutils.silo import control_silo_test
|
|
from sentry.utils.http import absolute_uri
|
|
|
|
|
|
@control_silo_test
|
|
class TwoFactorTest(TestCase):
|
|
def test_not_pending_2fa(self):
|
|
resp = self.client.get("/auth/2fa/")
|
|
assert resp.status_code == 302
|
|
assert resp["Location"] == "/auth/login/"
|
|
|
|
def test_no_2fa_configured(self):
|
|
user = self.create_user()
|
|
self.login_as(user)
|
|
|
|
self.session["_pending_2fa"] = [user.id, time() - 2]
|
|
self.save_session()
|
|
|
|
resp = self.client.get("/auth/2fa/", follow=True)
|
|
assert resp.redirect_chain == [
|
|
("/auth/login/", 302),
|
|
("/organizations/new/", 302),
|
|
]
|
|
|
|
def test_otp_challenge(self):
|
|
user = self.create_user()
|
|
interface = TotpInterface()
|
|
interface.enroll(user)
|
|
|
|
self.login_as(user)
|
|
self.session["_pending_2fa"] = [user.id, time() - 2]
|
|
self.save_session()
|
|
|
|
resp = self.client.get("/auth/2fa/")
|
|
assert resp.status_code == 200
|
|
self.assertTemplateUsed("sentry/twofactor.html")
|
|
assert "provide the access code" in resp.content.decode("utf8")
|
|
|
|
@mock.patch("sentry.auth.authenticators.TotpInterface.validate_otp", return_value=None)
|
|
@mock.patch("time.sleep")
|
|
def test_otp_submit_error(self, mock_sleep, mock_validate):
|
|
user = self.create_user()
|
|
interface = TotpInterface()
|
|
interface.enroll(user)
|
|
|
|
self.login_as(user)
|
|
self.session["_pending_2fa"] = [user.id, time() - 2]
|
|
self.save_session()
|
|
|
|
resp = self.client.post("/auth/2fa/", data={"otp": "123456"}, follow=True)
|
|
assert mock_validate.called
|
|
assert resp.status_code == 200
|
|
assert "Invalid confirmation code" in resp.content.decode("utf8")
|
|
|
|
@mock.patch("sentry.auth.authenticators.TotpInterface.validate_otp", return_value=True)
|
|
def test_otp_submit_success(self, mock_validate):
|
|
user = self.create_user()
|
|
interface = TotpInterface()
|
|
interface.enroll(user)
|
|
|
|
self.login_as(user)
|
|
self.session["_pending_2fa"] = [user.id, time() - 2]
|
|
self.save_session()
|
|
|
|
resp = self.client.post("/auth/2fa/", data={"otp": "123456"}, follow=True)
|
|
assert mock_validate.called
|
|
assert resp.redirect_chain == [
|
|
("/auth/login/", 302),
|
|
("/organizations/new/", 302),
|
|
]
|
|
|
|
@mock.patch("sentry.auth.authenticators.TotpInterface.validate_otp", return_value=False)
|
|
@mock.patch("time.sleep")
|
|
def test_rate_limit(self, mock_validate, mock_sleep):
|
|
user = self.create_user()
|
|
interface = TotpInterface()
|
|
interface.enroll(user)
|
|
|
|
self.login_as(user)
|
|
self.session["_pending_2fa"] = [user.id, time() - 2]
|
|
self.save_session()
|
|
with freeze_time("2000-01-01"):
|
|
for _ in range(5 + 2):
|
|
with self.tasks(), outbox_runner():
|
|
resp = self.client.post("/auth/2fa/", data={"otp": "123456"}, follow=False)
|
|
assert resp.status_code == 429
|
|
assert mock_validate.called
|
|
|
|
# make sure that we sent 1 and only 1 email
|
|
assert len(mail.outbox) == 1
|
|
msg = mail.outbox[0]
|
|
|
|
assert msg.to == [user.email]
|
|
assert msg.subject == "[Sentry]Suspicious Activity Detected"
|
|
url = absolute_uri(reverse("sentry-account-settings-security"))
|
|
assert url in msg.body
|
|
assert "IP address: 127.0.0.1" in msg.body
|