diff --git a/passbook/policies/dummy/tests.py b/passbook/policies/dummy/tests.py new file mode 100644 index 000000000..409596252 --- /dev/null +++ b/passbook/policies/dummy/tests.py @@ -0,0 +1,39 @@ +"""dummy policy tests""" +from django.test import TestCase +from guardian.shortcuts import get_anonymous_user + +from passbook.policies.dummy.forms import DummyPolicyForm +from passbook.policies.dummy.models import DummyPolicy +from passbook.policies.engine import PolicyRequest + + +class TestDummyPolicy(TestCase): + """Test dummy policy""" + + def setUp(self): + super().setUp() + self.request = PolicyRequest(user=get_anonymous_user()) + + def test_policy(self): + """test policy .passes""" + policy: DummyPolicy = DummyPolicy.objects.create( + name="dummy", wait_min=1, wait_max=2 + ) + result = policy.passes(self.request) + self.assertFalse(result.passing) + self.assertEqual(result.messages, ("dummy",)) + + def test_form(self): + """test form""" + form = DummyPolicyForm( + data={ + "name": "dummy", + "negate": False, + "order": 0, + "timeout": 1, + "result": True, + "wait_min": 1, + "wait_max": 2, + } + ) + self.assertTrue(form.is_valid()) diff --git a/passbook/root/settings.py b/passbook/root/settings.py index c671f98b4..4378fdbd8 100644 --- a/passbook/root/settings.py +++ b/passbook/root/settings.py @@ -45,20 +45,15 @@ ALLOWED_HOSTS = ["*"] SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") LOGIN_URL = "passbook_flows:default-authentication" -# CSRF_FAILURE_VIEW = 'passbook.core.views.errors.CSRFErrorView.as_view' # Custom user model AUTH_USER_MODEL = "passbook_core.User" -if DEBUG: - CSRF_COOKIE_NAME = "passbook_csrf_debug" - LANGUAGE_COOKIE_NAME = "passbook_language_debug" - SESSION_COOKIE_NAME = "passbook_session_debug" - SESSION_COOKIE_SAMESITE = None -else: - CSRF_COOKIE_NAME = "passbook_csrf" - LANGUAGE_COOKIE_NAME = "passbook_language" - SESSION_COOKIE_NAME = "passbook_session" +_cookie_suffix = "_debug" if DEBUG else "" +CSRF_COOKIE_NAME = f"passbook_csrf{_cookie_suffix}" +LANGUAGE_COOKIE_NAME = f"passbook_language{_cookie_suffix}" +SESSION_COOKIE_NAME = f"passbook_session{_cookie_suffix}" + SESSION_COOKIE_DOMAIN = CONFIG.y("domain", None) AUTHENTICATION_BACKENDS = [ @@ -396,6 +391,7 @@ for _app in INSTALLED_APPS: pass if DEBUG: + SESSION_COOKIE_SAMESITE = None INSTALLED_APPS.append("debug_toolbar") MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware") diff --git a/passbook/root/tests.py b/passbook/root/tests.py new file mode 100644 index 000000000..e8021c617 --- /dev/null +++ b/passbook/root/tests.py @@ -0,0 +1,28 @@ +"""root tests""" +from base64 import b64encode + +from django.conf import settings +from django.shortcuts import reverse +from django.test import Client, TestCase + + +class TestRoot(TestCase): + """Test root application""" + + def setUp(self): + super().setUp() + self.client = Client() + + def test_monitoring_error(self): + """Test monitoring without any credentials""" + response = self.client.get(reverse("metrics")) + self.assertEqual(response.status_code, 401) + + def test_monitoring_ok(self): + """Test monitoring with credentials""" + creds = "Basic " + b64encode(f"monitor:{settings.SECRET_KEY}".encode()).decode( + "utf-8" + ) + auth_headers = {"HTTP_AUTHORIZATION": creds} + response = self.client.get(reverse("metrics"), **auth_headers) + self.assertEqual(response.status_code, 200) diff --git a/passbook/stages/invitation/tests.py b/passbook/stages/invitation/tests.py index 59b988d2b..5998d26ac 100644 --- a/passbook/stages/invitation/tests.py +++ b/passbook/stages/invitation/tests.py @@ -1,14 +1,18 @@ -"""login tests""" +"""invitation tests""" +from unittest.mock import MagicMock, patch + from django.shortcuts import reverse from django.test import Client, TestCase +from guardian.shortcuts import get_anonymous_user from passbook.core.models import User from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding from passbook.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan from passbook.flows.views import SESSION_KEY_PLAN +from passbook.stages.invitation.forms import InvitationStageForm +from passbook.stages.invitation.models import Invitation, InvitationStage +from passbook.stages.invitation.stage import INVITATION_TOKEN_KEY, PLAN_CONTEXT_PROMPT from passbook.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND -from passbook.stages.user_login.forms import UserLoginStageForm -from passbook.stages.user_login.models import UserLoginStage class TestUserLoginStage(TestCase): @@ -20,15 +24,41 @@ class TestUserLoginStage(TestCase): self.client = Client() self.flow = Flow.objects.create( - name="test-login", - slug="test-login", + name="test-invitation", + slug="test-invitation", designation=FlowDesignation.AUTHENTICATION, ) - self.stage = UserLoginStage.objects.create(name="login") + self.stage = InvitationStage.objects.create(name="invitation") FlowStageBinding.objects.create(flow=self.flow, stage=self.stage, order=2) - def test_valid_password(self): - """Test with a valid pending user and backend""" + def test_form(self): + """Test Form""" + data = {"name": "test"} + self.assertEqual(InvitationStageForm(data).is_valid(), True) + + def test_without_invitation_fail(self): + """Test without any invitation, continue_flow_without_invitation not set.""" + plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage]) + plan.context[PLAN_CONTEXT_PENDING_USER] = self.user + plan.context[ + PLAN_CONTEXT_AUTHENTICATION_BACKEND + ] = "django.contrib.auth.backends.ModelBackend" + session = self.client.session + session[SESSION_KEY_PLAN] = plan + session.save() + + response = self.client.get( + reverse( + "passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug} + ) + ) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, reverse("passbook_flows:denied")) + + def test_without_invitation_continue(self): + """Test without any invitation, continue_flow_without_invitation is set.""" + self.stage.continue_flow_without_invitation = True + self.stage.save() plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage]) plan.context[PLAN_CONTEXT_PENDING_USER] = self.user plan.context[ @@ -45,39 +75,36 @@ class TestUserLoginStage(TestCase): ) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, reverse("passbook_core:overview")) + self.stage.continue_flow_without_invitation = False + self.stage.save() - def test_without_user(self): - """Test a plan without any pending user, resulting in a denied""" - plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage]) - session = self.client.session - session[SESSION_KEY_PLAN] = plan - session.save() - - response = self.client.get( - reverse( - "passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug} - ) - ) - self.assertEqual(response.status_code, 302) - self.assertEqual(response.url, reverse("passbook_flows:denied")) - - def test_without_backend(self): - """Test a plan with pending user, without backend, resulting in a denied""" + def test_with_invitation(self): + """Test with invitation, check data in session""" plan = FlowPlan(flow_pk=self.flow.pk.hex, stages=[self.stage]) plan.context[PLAN_CONTEXT_PENDING_USER] = self.user + plan.context[ + PLAN_CONTEXT_AUTHENTICATION_BACKEND + ] = "django.contrib.auth.backends.ModelBackend" session = self.client.session session[SESSION_KEY_PLAN] = plan session.save() - response = self.client.get( - reverse( + data = {"foo": "bar"} + invite = Invitation.objects.create( + created_by=get_anonymous_user(), fixed_data=data + ) + + with patch("passbook.flows.views.FlowExecutorView.cancel", MagicMock()): + base_url = reverse( "passbook_flows:flow-executor", kwargs={"flow_slug": self.flow.slug} ) - ) - self.assertEqual(response.status_code, 302) - self.assertEqual(response.url, reverse("passbook_flows:denied")) + response = self.client.get( + base_url + f"?{INVITATION_TOKEN_KEY}={invite.pk.hex}" + ) - def test_form(self): - """Test Form""" - data = {"name": "test"} - self.assertEqual(UserLoginStageForm(data).is_valid(), True) + session = self.client.session + plan: FlowPlan = session[SESSION_KEY_PLAN] + self.assertEqual(plan.context[PLAN_CONTEXT_PROMPT], data) + + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, reverse("passbook_core:overview"))