From 9fe346cf594ce07728a34d39cf98857bf44e128d Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Fri, 22 Nov 2019 14:34:31 +0100
Subject: [PATCH] forms: forbidden direct anonymous acces to anonymous formdata
 on frontoffice (#37808)

---
 tests/test_form_pages.py    | 12 ++++++------
 tests/test_tracking_code.py | 12 ++++++------
 wcs/forms/common.py         |  5 ++++-
 wcs/forms/root.py           |  4 +++-
 4 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index 767511fb..c285a58b 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -1283,8 +1283,8 @@ def test_form_visit_existing(pub):
     formdata_user.user_id = user.id
     formdata_user.store()
 
-    resp = get_app(pub).get('/test/%s/' % formdata.id)
-    assert resp.location.startswith('http://example.net/login/?next=')
+    resp = get_app(pub).get('/test/%s/' % formdata.id, status=403)
+    assert 'Access Forbidden' in resp.text
 
     resp = get_app(pub).get('/test/%s/' % formdata_user.id)
     assert resp.location.startswith('http://example.net/login/?next=')
@@ -1408,8 +1408,8 @@ def test_form_tracking_code(pub, nocache):
 
     # check anonymous user can't get to it from the URL
     pub.session_manager.session_class.wipe()
-    resp = get_app(pub).get('http://example.net/test/%s' % formdata_id)
-    assert resp.location.startswith('http://example.net/login')
+    resp = get_app(pub).get('http://example.net/test/%s' % formdata_id, status=403)
+    assert 'Access Forbidden' in resp.text
 
     # or logged users that didn't enter the code:
     user = create_user(pub)
@@ -1984,8 +1984,8 @@ def test_form_direct_draft_access(pub, tracking_code):
     formdata.status = 'draft'
     formdata.store()
 
-    resp = get_app(pub).get('/test/%s' % formdata.id, status=302)
-    assert resp.location.startswith('http://example.net/login')
+    resp = get_app(pub).get('/test/%s' % formdata.id, status=403)
+    assert 'Access Forbidden' in resp.text
 
     formdata.user_id = user.id
     formdata.store()
diff --git a/tests/test_tracking_code.py b/tests/test_tracking_code.py
index b4e3006c..9e40a2fd 100644
--- a/tests/test_tracking_code.py
+++ b/tests/test_tracking_code.py
@@ -150,8 +150,8 @@ def test_acces_to_formdata(pub, nocache):
 
     | sumitter / accesser | anonymous | user1 | user2 | agent1 | agent2 | admin1 |
     +---------------------+-----------+-------+-------+--------+--------+--------+
-    | anonymous           |  login    | deny  | deny  | deny   | (*)    | (*)    |
-    | agent1 (submiter))  |  login    | deny  | deny  | deny   | (*)    | (*)    |
+    | anonymous           |  deny     | deny  | deny  | deny   | (*)    | (*)    |
+    | agent1 (submiter))  |  deny     | deny  | deny  | deny   | (*)    | (*)    |
     | user1               |  login    | allow | deny  | deny   | (*)    | (*)    |
 
     (*) Agent2 is the receiver.
@@ -313,11 +313,11 @@ def test_acces_to_formdata(pub, nocache):
     # direct access to formdata
     is_draft = False  # demands
     with submission(anonymous, is_frontoffice=True) as (tracking_code, formdata_id):
-        expected = ('login', 'forbidden', 'forbidden', 'forbidden', 'backoffice', 'backoffice')
+        expected = ('forbidden', 'forbidden', 'forbidden', 'forbidden', 'backoffice', 'backoffice')
         for i in range(len(users)):
             check_direct_access(users[i], expected[i])
     with submission(agent1, is_frontoffice=False) as (tracking_code, formdata_id):
-        expected = ('login', 'forbidden', 'forbidden', 'forbidden', 'backoffice', 'backoffice')
+        expected = ('forbidden', 'forbidden', 'forbidden', 'forbidden', 'backoffice', 'backoffice')
         for i in range(len(users)):
             check_direct_access(users[i], expected[i])
     with submission(user1, is_frontoffice=True) as (tracking_code, formdata_id):
@@ -327,11 +327,11 @@ def test_acces_to_formdata(pub, nocache):
 
     is_draft = True  # drafts
     with submission(anonymous, is_frontoffice=True) as (tracking_code, formdata_id):
-        expected = ('login', 'forbidden', 'forbidden', 'forbidden', 'forbidden', 'forbidden')
+        expected = ('forbidden', 'forbidden', 'forbidden', 'forbidden', 'forbidden', 'forbidden')
         for i in range(len(users)):
             check_direct_access(users[i], expected[i])
     with submission(agent1, is_frontoffice=False) as (tracking_code, formdata_id):
-        expected = ('login', 'forbidden', 'forbidden', 'forbidden', 'forbidden', 'forbidden')
+        expected = ('forbidden', 'forbidden', 'forbidden', 'forbidden', 'forbidden', 'forbidden')
         for i in range(len(users)):
             check_direct_access(users[i], expected[i])
     with submission(user1, is_frontoffice=True) as (tracking_code, formdata_id):
diff --git a/wcs/forms/common.py b/wcs/forms/common.py
index ea1ca2c6..e6189aa8 100644
--- a/wcs/forms/common.py
+++ b/wcs/forms/common.py
@@ -322,7 +322,10 @@ class FormStatusPage(Directory, FormTemplateMixin):
         session = get_session()
         if not session or not session.user:
             if not self.filled.formdef.is_user_allowed_read(None, self.filled):
-                raise errors.AccessUnauthorizedError()
+                if self.filled.user_id:
+                    raise errors.AccessUnauthorizedError()
+                else:
+                    raise errors.AccessForbiddenError()
         user = get_request().user
         if self.filled.formdef is None:
             raise errors.AccessForbiddenError()
diff --git a/wcs/forms/root.py b/wcs/forms/root.py
index 63d34214..1d5f0cb1 100644
--- a/wcs/forms/root.py
+++ b/wcs/forms/root.py
@@ -1301,8 +1301,10 @@ class FormPage(Directory, FormTemplateMixin):
             elif session.user:
                 if str(session.user) != str(filled.user_id):
                     raise errors.AccessUnauthorizedError()
-            else:
+            elif filled.user_id:
                 raise errors.AccessUnauthorizedError()
+            else:
+                raise errors.AccessForbiddenError()
 
         if get_request().get_query() == 'remove-draft':
             filled.remove_self()
-- 
2.24.0

