Пример #1
0
    def test_otp_totp_check_context(self):
        # given user have confirmed is totp device
        self.totp_device.confirmed = True
        self.totp_device.save()
        response = self.client.get("/accounts/2fa/totp/check/")

        self.assertEqual(response.context["have_totp"], True)
        self.assertEqual(response.context["have_fido2"], False)
        self.assertEqual(response.context["have_static"], False)

        # given user setup totp + fido2 devices
        setup_2fa_fido2_device(self.user)

        response = self.client.get("/accounts/2fa/totp/check/")

        self.assertEqual(response.context["have_totp"], True)
        self.assertEqual(response.context["have_fido2"], True)
        self.assertEqual(response.context["have_static"], False)
        # given user setup static + fido2 + totp devices
        setup_2fa_static_device(self.user,
                                codes_list=tv.STATIC_DEVICE_CODES_LIST)

        response = self.client.get("/accounts/2fa/totp/check/")

        self.assertEqual(response.context["have_totp"], True)
        self.assertEqual(response.context["have_fido2"], True)
        self.assertEqual(response.context["have_static"], True)
Пример #2
0
    def test_security_key_added(self):
        # User has already added a security key
        key_name = "O Key"
        setup_2fa_fido2_device(self.user, name=key_name)
        self.visit(AccountPages.two_factors_authentication_url)  # refresh page

        # User can see the security key in the list
        self.assertIn(key_name, self.get_elem_text(self.security_key_divs))

        # User logout
        self.visit(LoginPage.logout_url)

        # Remove middleware mock, to restore check pages
        self.middleware_patcher.stop()

        # User login again, the 2fa check page appears.
        self.log_user()

        # Check page appears ask for fido2
        self.assertIn("security key",
                      self.get_elem_text(self.confirm_button).lower())

        # No alternative 2FA are shown
        with self.assertRaises(NoSuchElementException):
            self.get_elem(self.check_pages_alternatives_list)
Пример #3
0
    def test_delete_security_key_with_emergency_code(self):
        # User has already added a security key and a emergency codes set
        setup_2fa_fido2_device(self.user)
        setup_2fa_static_device(self.user)
        self.visit(AccountPages.two_factors_authentication_url)  # refresh page

        # User delete existing security key
        self.get_elems(self.delete_security_key_buttons)[0].click()

        # A warning message appears to inform user 2FA will be completely disable as emergency code are only available
        # when another 2fa device type is set
        self.assertIn("last 2FA device",
                      self.get_elem_text(self.delete_warning))
Пример #4
0
    def test_rename_security_key(self):
        # User has already added a security key
        old_key_name = "MO Key"
        setup_2fa_fido2_device(self.user, name=old_key_name)
        self.visit(AccountPages.two_factors_authentication_url)  # refresh page

        # User rename existing security key
        new_key_name = "O Key"
        self.rename_security_key(new_name=new_key_name)

        # User see the key name have been updated in the device list
        self.wait_for_elem_to_show(self.security_key_divs)
        self.assertNotIn(old_key_name,
                         self.get_elem_text(self.security_key_divs))
        self.assertIn(new_key_name, self.get_elem_text(self.security_key_divs))
    def test_user_setup_all_2fa(self):
        # Make TOTP.time setter set a hard coded secret_time to always be able to confirm app with the same valid_token
        totp_time_setter.side_effect = mocked_totp_time_setter

        # User add an auth app (can't be really added in this test)
        setup_2fa_totp_device(self.user, secret_key=TOTP_DEVICE_SECRET_KEY)
        self.visit(AccountPages.two_factors_authentication_url)  # refresh page

        # User add emergency code too
        self.add_emergency_codes_set("My emergency codes")

        # Finally, user add a security key (can't be really added in this test)
        setup_2fa_fido2_device(self.user)
        self.visit(AccountPages.two_factors_authentication_url)  # refresh page

        # The 3 2FA devices appears in the list
        self.assertEqual(1, len(self.get_elems(self.auth_app_divs)))
        self.assertEqual(1, len(self.get_elems(self.emergency_codes_divs)))
        self.assertEqual(1, len(self.get_elems(self.security_key_divs)))

        # User logout and login
        self.visit(LoginPage.logout_url)
        self.middleware_patcher.stop(
        )  # Remove middleware mock, to restore check pages
        self.log_user()

        # The 2FA check page appears with all device available
        self.assertEqual(
            2, len(self.get_elems(self.check_pages_alternatives_list)))

        # Login using totp
        for i, item_text in enumerate(
                self.get_elems_text(self.check_pages_alternatives_list)):
            if "authentication app" in item_text:
                self.get_elems(self.check_pages_alternatives_list)[i].click()
        self.enter_2fa_code(TOTP_DEVICE_VALID_TOKEN)
        self.assertIn("home", self.head_title)

        # user delete its security key 2FA
        self.visit(self.two_factors_authentication_url)
        # User delete existing security key
        self.get_elems(self.delete_security_key_buttons)[0].click()

        # There is no special warning about it, as there is auth app 2fa left
        with self.assertRaises(NoSuchElementException):
            self.get_elem(self.delete_warning)
Пример #6
0
    def test_otp_fido2_api_login_begin(self, acd_mock, cbor2_mock, pkcre_mock,
                                       fido2_server_mock):
        # given user setup another fido2_device
        setup_2fa_fido2_device(self.user, name="second fido device")

        authenticate_begin_return_value = ["fake_auth_data", "fake_state"]
        fido2_server_mock().authenticate_begin.return_value = (
            authenticate_begin_return_value)
        fido2_server_mock.reset_mock(
        )  # previous assignment count as a call so we need to reset mock counter
        fake_credentials_list = ["fake_credential_1", "fake_credential_2"]
        acd_mock.side_effect = fake_credentials_list
        fake_cbor2_loaded_list = ["fake_cbor2_loaded_1", "fake_cbor2_loaded_2"]
        cbor2_mock.loads.side_effect = fake_cbor2_loaded_list
        cbor2_mock.dumps.return_value = b"fakeAuthData"

        response = self.client.get("/accounts/2fa/fido2/api/login_begin")

        self.assertEqual(acd_mock.call_count, 2)
        acd_mock.assert_any_call(fake_cbor2_loaded_list[0])
        acd_mock.assert_any_call(fake_cbor2_loaded_list[1])

        pkcre_mock.assert_called_once_with("testserver",
                                           settings.FIDO2_RP_NAME)
        fido2_server_mock.assert_called_once_with(pkcre_mock())

        fido2_server_mock().authenticate_begin.assert_called_once_with(
            fake_credentials_list,
            user_verification="discouraged",
        )

        self.assertEqual(
            response.wsgi_request.session.get("fido2_state"),
            authenticate_begin_return_value[1],
        )
        self.assertEqual(response.wsgi_request.session.get("fido2_domain"),
                         "testserver")

        cbor2_mock.dumps.assert_called_once_with(
            authenticate_begin_return_value[0])

        self.assertEqual(response.content, cbor2_mock.dumps.return_value)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response["Content-Type"], "application/cbor")
Пример #7
0
    def test_otp_fido2_api_register_begin(self, fido2_server_mock, pkcre_mock,
                                          cbor2_mock, acd_mock):
        # given user setup another fido2_device
        fido2_device_2 = setup_2fa_fido2_device(self.user,
                                                name="second fido device")

        register_begin_return_value = ["fake_registration_data", "fake_state"]
        fido2_server_mock(
        ).register_begin.return_value = register_begin_return_value
        fido2_server_mock.reset_mock(
        )  # previous assignment count as a call so we need to reset mock counter
        fake_credentials_list = ["fake_credential_1", "fake_credential_2°"]
        acd_mock.side_effect = fake_credentials_list
        fake_cbor2_loaded_list = ["fake_cbor2_loaded_1", "fake_cbor2_loaded_2"]
        cbor2_mock.loads.side_effect = fake_cbor2_loaded_list
        cbor2_mock.dumps.return_value = b"fake_registration_data"

        response = self.client.get("/accounts/2fa/fido2/api/register_begin")

        pkcre_mock.assert_called_once_with("testserver",
                                           settings.FIDO2_RP_NAME)
        fido2_server_mock.assert_called_once_with(pkcre_mock())

        self.assertEqual(cbor2_mock.loads.call_count, 2)
        _, loads_mock_first_call_args, _ = cbor2_mock.loads.mock_calls[0]
        _, loads_mock_second_call_args, _ = cbor2_mock.loads.mock_calls[1]
        self.assertEqual(
            loads_mock_first_call_args[0].tobytes(),
            self.fido2_device.authenticator_data,
        )
        self.assertEqual(loads_mock_second_call_args[0].tobytes(),
                         fido2_device_2.authenticator_data)

        fido2_server_mock().register_begin.assert_called_once_with(
            {
                "id": self.user.email.encode(),
                "name": self.user.email,
                "displayName": self.user.email,
                "icon": "",
            },
            credentials=fake_credentials_list,
            user_verification="discouraged",
            authenticator_attachment="cross-platform",
        )

        cbor2_mock.dumps.assert_called_once_with(
            register_begin_return_value[0])

        self.assertEqual(
            response.wsgi_request.session.get("fido2_register_state"),
            register_begin_return_value[1],
        )

        self.assertEqual(response.content, cbor2_mock.dumps.return_value)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response["Content-Type"], "application/octet-stream")
Пример #8
0
    def test_otp_list_returns_correct_html(self):
        # Make TOTP.time setter set a hard coded secret_time to always be able to confirm app with the same valid_token
        totp_time_setter.side_effect = mocked_totp_time_setter

        # Given no 2fa devices are setup
        response = self.client.get("/accounts/2fa/")
        self.assertContains(response, "Protect your Paper Matter account")
        self.assertTemplateUsed(response, "otp_ftl/device_list.html")

        # Given 2fa devices are setup
        setup_2fa_static_device(self.user,
                                codes_list=tv.STATIC_DEVICE_CODES_LIST)
        setup_2fa_fido2_device(self.user)
        setup_2fa_totp_device(self.user)

        response = self.client.get("/accounts/2fa/")
        self.assertContains(response, "Emergency codes")
        self.assertContains(response, "Security keys (U2F/FIDO2)")
        self.assertContains(response, "Authenticator apps")
Пример #9
0
    def test_delete_security_key(self):
        # User has already added a security key
        setup_2fa_fido2_device(self.user)
        self.visit(AccountPages.two_factors_authentication_url)  # refresh page

        # User delete existing security key
        self.delete_security_key()

        # User see the set have been remove from the device list
        with self.assertRaises(NoSuchElementException):
            self.get_elem(self.security_key_divs)

        # User logout
        self.visit(LoginPage.logout_url)

        # Remove middleware mock, to restore check pages
        self.middleware_patcher.stop()

        # When user login again there is no 2FA check page as there is no 2fa devices set
        self.log_user()
        self.assertIn("home", self.head_title)
Пример #10
0
    def test_otp_static_delete_context(self):
        response = self.client.get(
            f"/accounts/2fa/totp/{self.totp_device.id}/delete/")

        self.assertEqual(response.context["last_otp"], True)

        # given user add a totp device
        totp_device_2 = setup_2fa_totp_device(self.user)

        response = self.client.get(
            f"/accounts/2fa/totp/{self.totp_device.id}/delete/")

        self.assertEqual(response.context["last_otp"], False)

        # given delete second totp device and add a fido2 device
        totp_device_2.delete()
        setup_2fa_fido2_device(self.user)

        response = self.client.get(
            f"/accounts/2fa/totp/{self.totp_device.id}/delete/")

        self.assertEqual(response.context["last_otp"], False)
Пример #11
0
    def test_otp_list_context(self):
        # Make TOTP.time setter set a hard coded secret_time to always be able to confirm app with the same valid_token
        totp_time_setter.side_effect = mocked_totp_time_setter

        # Given 2fa devices are setup
        static_device_1 = setup_2fa_static_device(
            self.user, "SD1", codes_list=tv.STATIC_DEVICE_CODES_LIST)
        static_device_2 = setup_2fa_static_device(
            self.user, "SD2", codes_list=tv.STATIC_DEVICE_CODES_LIST)
        totp_device_1 = setup_2fa_totp_device(self.user, "TD1")
        totp_device_2 = setup_2fa_totp_device(self.user, "TD2")
        fido2_device_1 = setup_2fa_fido2_device(self.user, "FD1")
        fido2_device_2 = setup_2fa_fido2_device(self.user, "FD2")

        response = self.client.get("/accounts/2fa/")

        self.assertCountEqual(response.context["static_devices"],
                              [static_device_1, static_device_2])
        self.assertCountEqual(response.context["totp_devices"],
                              [totp_device_1, totp_device_2])
        self.assertCountEqual(response.context["fido2_devices"],
                              [fido2_device_1, fido2_device_2])
Пример #12
0
 def setUp(self):
     # Setup org, user, a fido2 device and the user is logged
     self.org = setup_org()
     self.user = setup_user(self.org)
     self.fido2_device = setup_2fa_fido2_device(self.user)
     setup_authenticated_session(self.client, self.org, self.user)
     # mock OTPMiddleware._verify_user() to skip check page
     self.middleware_patcher = patch.object(OTPMiddleware, "_verify_user",
                                            mocked_verify_user)
     self.middleware_patcher.start()
     self.addCleanup(
         patch.stopall
     )  # ensure mock is remove after each test, even if the test crash
     self.addCleanup(totp_time_setter.reset_mock, side_effect=True)
Пример #13
0
    def test_otp_static_check_context(self):
        response = self.client.get("/accounts/2fa/static/check/")

        self.assertEqual(response.context["have_static"], True)
        self.assertEqual(response.context["have_fido2"], False)
        self.assertEqual(response.context["have_totp"], False)

        # given user setup static + fido2 devices
        setup_2fa_fido2_device(self.user)

        response = self.client.get("/accounts/2fa/static/check/")

        self.assertEqual(response.context["have_static"], True)
        self.assertEqual(response.context["have_fido2"], True)
        self.assertEqual(response.context["have_totp"], False)
        # given user setup static + fido2 + totp devices
        setup_2fa_totp_device(self.user)

        response = self.client.get("/accounts/2fa/static/check/")

        self.assertEqual(response.context["have_static"], True)
        self.assertEqual(response.context["have_fido2"], True)
        self.assertEqual(response.context["have_totp"], True)
Пример #14
0
    def test_otp_check_redirect_to_proper_view(self):
        # Given no 2fa devices are setup
        response = self.client.get("/app/")
        # Home page is displayed
        self.assertTemplateUsed(response, "core/home.html")

        # Given a static device is setup
        setup_2fa_static_device(self.user,
                                codes_list=tv.STATIC_DEVICE_CODES_LIST)
        response = self.client.get("/app/", follow=True)
        # User is redirect to otp_static_check
        self.assertRedirects(response, reverse_lazy("otp_static_check"))

        # Given static + totp device are setup
        setup_2fa_totp_device(self.user)
        response = self.client.get("/app/", follow=True)
        # User is redirect to otp_static_check
        self.assertRedirects(response, reverse_lazy("otp_totp_check"))

        # Given static + totp + 2fa device are setup
        setup_2fa_fido2_device(self.user)
        response = self.client.get("/app/", follow=True)
        # User is redirect to otp_static_check
        self.assertRedirects(response, reverse_lazy("otp_fido2_check"))
Пример #15
0
 def setUp(self):
     self.org_1 = setup_org()
     self.org_2 = setup_org(name=tv.ORG_NAME_2, slug=tv.ORG_SLUG_2)
     self.user_1 = setup_user(org=self.org_1)
     self.user_2 = setup_user(org=self.org_1,
                              email=tv.USER2_EMAIL,
                              password=tv.USER2_PASS)
     self.user_1_codes_1 = ["AA1222", "AA1223"]
     self.user_1_static_device_1 = setup_2fa_static_device(
         self.user_1,
         "user1 valid token set 1",
         codes_list=self.user_1_codes_1)
     self.user_1_fido2_device_1 = setup_2fa_fido2_device(
         self.user_1, "user1 fido2 device 1")
     self.user_1_totp_device_1 = setup_2fa_totp_device(
         self.user_1, "user1 totp 1")
     self.user_1_totp_device_2 = setup_2fa_totp_device(
         self.user_1, "user1 totp 2")
     self.user_2_totp_device_2 = setup_2fa_totp_device(
         self.user_2, "user2 totp 1")
    def setUp(self, **kwargs):
        # orgs, admin, users are already created
        super().setUp()
        self.admin_org = setup_org(name="admin-org", slug="admin-org")
        self.admin = setup_admin(self.admin_org)
        self.user1_org = setup_org(name=tv.ORG_NAME_1, slug=tv.ORG_SLUG_1)
        self.user1 = setup_user(self.user1_org,
                                email=tv.USER1_EMAIL,
                                password=tv.USER1_PASS)
        self.user2_org = setup_org(name=tv.ORG_NAME_2, slug=tv.ORG_SLUG_2)
        self.user2 = setup_user(self.user2_org,
                                email=tv.USER2_EMAIL,
                                password=tv.USER2_PASS)

        # mock OTPMiddleware._verify_user() to skip check page
        self.middleware_patcher = patch.object(OTPMiddleware, "_verify_user",
                                               mocked_verify_user)
        self.middleware_patcher.start()
        self.addCleanup(
            patch.stopall
        )  # ensure mock is remove after each test, even if the test crash
        self.addCleanup(totp_time_setter.reset_mock, side_effect=True)

        # admin, user1 and user2 have added documents, folders, otp devices
        self.admin_resources = {}
        self.admin_resources["folder1"] = setup_folder(self.admin_org)
        self.admin_resources["sub_folder1"] = setup_folder(
            self.admin_org, parent=self.admin_resources["folder1"])
        self.admin_resources["doc1"] = setup_document(
            self.admin_org,
            ftl_user=self.admin,
            binary=setup_temporary_file().name)
        self.admin_resources["doc2"] = setup_document(
            self.admin_org,
            ftl_user=self.admin,
            ftl_folder=self.admin_resources["folder1"],
            binary=setup_temporary_file().name,
        )
        self.admin_resources["doc3"] = setup_document(
            self.admin_org,
            ftl_user=self.admin,
            ftl_folder=self.admin_resources["sub_folder1"],
            binary=setup_temporary_file().name,
        )
        self.admin_resources["totp_device"] = setup_2fa_totp_device(
            self.admin, secret_key=TOTP_DEVICE_SECRET_KEY)
        self.admin_resources["fido2_device"] = setup_2fa_fido2_device(
            self.admin)
        self.admin_resources["static_device"] = setup_2fa_static_device(
            self.admin, codes_list=["AAA"])

        self.user1_resources = {}
        self.user1_resources["folder1"] = setup_folder(self.user1_org)
        self.user1_resources["sub_folder1"] = setup_folder(
            self.user1_org, parent=self.user1_resources["folder1"])
        self.user1_resources["doc1"] = setup_document(
            self.user1_org,
            ftl_user=self.user1,
            binary=setup_temporary_file().name)
        self.user1_resources["doc2"] = setup_document(
            self.user1_org,
            ftl_user=self.user1,
            ftl_folder=self.user1_resources["folder1"],
            binary=setup_temporary_file().name,
        )
        self.user1_resources["doc3"] = setup_document(
            self.user1_org,
            ftl_user=self.user1,
            ftl_folder=self.user1_resources["sub_folder1"],
            binary=setup_temporary_file().name,
        )
        self.user1_resources["totp_device"] = setup_2fa_totp_device(
            self.user1, secret_key=TOTP_DEVICE_SECRET_KEY)
        self.user1_resources["fido2_device"] = setup_2fa_fido2_device(
            self.user1)
        self.user1_resources["static_device"] = setup_2fa_static_device(
            self.user1, codes_list=["AAA"])

        self.user2_resources = {}
        self.user2_resources["folder1"] = setup_folder(self.user2_org)
        self.user2_resources["sub_folder1"] = setup_folder(
            self.user2_org, parent=self.user2_resources["folder1"])
        self.user2_resources["doc1"] = setup_document(self.user2_org,
                                                      ftl_user=self.user2)
        self.user2_resources["doc2"] = setup_document(
            self.user2_org,
            ftl_user=self.user2,
            ftl_folder=self.user2_resources["folder1"],
        )
        self.user2_resources["doc3"] = setup_document(
            self.user2_org,
            ftl_user=self.user2,
            ftl_folder=self.user2_resources["sub_folder1"],
        )
        self.user2_resources["totp_device"] = setup_2fa_totp_device(
            self.user2, secret_key=TOTP_DEVICE_SECRET_KEY)
        self.user2_resources["fido2_device"] = setup_2fa_fido2_device(
            self.user2)
        self.user2_resources["static_device"] = setup_2fa_static_device(
            self.user2, codes_list=["AAA"])