From 065c2f6dfd4eb3824089809a5c7465a98a2d0f6e Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Tue, 7 Jan 2020 17:44:48 +0100
Subject: [PATCH] forms: force authentication if anonymous use user tracking
 code (#38239)

---
 tests/test_form_pages.py    |  7 ++-----
 tests/test_tracking_code.py | 30 ++++++++++++++++++++++++------
 wcs/forms/root.py           |  8 +++++++-
 3 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index e52537fd..565062b0 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -1582,17 +1582,14 @@ def test_form_tracking_code_as_user(pub, nocache):
     resp = resp.forms[0].submit()
     assert formdef.data_class().get(formdata_id).evolution[-1].comment == 'hello world'
 
-    # and check we can also get back to it as anonymous
+    # check we can't get back to it as anonymous
     app = get_app(pub)
     resp = app.get('/')
     resp.forms[0]['code'] = tracking_code
     resp = resp.forms[0].submit()
     assert resp.location == 'http://example.net/code/%s/load' % tracking_code
     resp = resp.follow()
-    assert resp.location == 'http://example.net/test/%s' % formdata_id
-    resp = resp.follow()
-    resp = resp.follow()
-    assert 'form_comment' in resp.text # makes sure user is treated as submitter
+    assert resp.location == 'http://example.net/login/?ReturnUrl=http://example.net/test/%s' % formdata_id
 
     # and check a bot is not allowed to get it
     app = get_app(pub)
diff --git a/tests/test_tracking_code.py b/tests/test_tracking_code.py
index 2e572ad0..c8323cb6 100644
--- a/tests/test_tracking_code.py
+++ b/tests/test_tracking_code.py
@@ -183,14 +183,22 @@ def test_access_to_formdata(pub, users, nocache):
     | agent1 (submiter)   |  login    | deny  | deny  | deny   | back   | back   |
     | user1               |  login    | allow | deny  | deny   | back   | back   |
 
-    2- New user on prefill fields when accessing using tracking code :
+    2- Access using tracking code :
+
+    | sumitter / accesser | anonymous | user1 | user2 | agent1 | agent2 | admin1 |
+    +---------------------+-----------+-------+-------+--------+--------+--------+
+    | anonymous           |  allow    | allow | allow | allow  | allow  | allow  |
+    | agent1 (submiter))  |  allow    | allow | allow | allow  | allow  | allow  |
+    | user1               |  login    | allow | allow | allow  | allow  | allow  |
+
+    3- New user on prefill fields when accessing using tracking code :
      a-  Drafts
 
     | sumitter / accesser | anonymous | user1 | user2 | agent1 | agent2 | admin1 |
     +---------------------+-----------+-------+-------+--------+--------+--------+
     | anonymous           | anonymous | user1 | user2 | agent1 | agent2 | admin  |
     | agent1 (submiter)   | anonymous | user1 | user2 | agent1 | agent2 | admin  |
-    | user1               | anonymous | user1 | user2 | agent1 | agent2 | admin  |
+    | user1               |           | user1 | user2 | agent1 | agent2 | admin  |
 
      b-  Demands (evolving into Workflows forms)
 
@@ -198,7 +206,7 @@ def test_access_to_formdata(pub, users, nocache):
     +---------------------+-----------+-------+-------+--------+--------+--------+
     | anonymous           | anonymous | user1 | user2 | agent1 | agent2 | admin  |
     | agent1 (submiter)   | anonymous | user1 | user2 | agent1 | agent2 | admin  |
-    | user1               | anonymous | user1 | user2 | agent1 | agent2 | admin  |
+    | user1               |           | user1 | user2 | agent1 | agent2 | admin  |
     """
     (anonymous, user1, user2, agent1, agent2, admin1) = users
     tracking_code = None
@@ -338,7 +346,7 @@ def test_access_to_formdata(pub, users, nocache):
             else:
                 assert expected in ('login', 'deny', 'front',  'back')
 
-    def check_tracking_code_access(user, owner=None, new_owner=None):
+    def check_tracking_code_access(user, owner=None, new_owner=None, expected='allow'):
         """
         load the formdata using the tracking code and prefill user name fields.
         new_owner is used to show that user fields change on drafts.
@@ -353,6 +361,11 @@ def test_access_to_formdata(pub, users, nocache):
         resp.forms[0]['code'] = tracking_code
         resp = resp.forms[0].submit()
         resp = resp.follow()
+        if expected == 'login':
+            assert resp.location == (
+                'http://example.net/login/?ReturnUrl='
+                + 'http://example.net/test/%s') % formdata_id
+            return
         resp = resp.follow()
         resp = resp.follow()
         assert '<title>Forms - test</title>' in resp.text
@@ -434,20 +447,25 @@ def test_access_to_formdata(pub, users, nocache):
             check_direct_access(users[i], expected[i])
 
     # access to formdata using the tracking code
+    expected = ('login', 'allow', 'allow', 'allow', 'allow', 'allow')
     is_draft = True  # drafts
+    i = 0
     for user in users:
         with submit(anonymous, is_front=True) as (tracking_code, formdata_id):
             check_tracking_code_access(user, owner=anonymous, new_owner=user)
         with submit(agent1, is_front=False) as (tracking_code, formdata_id):
             check_tracking_code_access(user, owner=anonymous, new_owner=user)
         with submit(user1, is_front=True) as (tracking_code, formdata_id):
-            check_tracking_code_access(user, owner=user1, new_owner=user)
+            check_tracking_code_access(user, owner=user1, new_owner=user, expected=expected[i])
+        i += 1
 
     is_draft = False  # demands
+    i = 0
     for user in users:
         with submit(anonymous, is_front=True) as (tracking_code, formdata_id):
             check_tracking_code_access(user, owner=anonymous, new_owner=user)
         with submit(agent1, is_front=False) as (tracking_code, formdata_id):
             check_tracking_code_access(user, owner=anonymous, new_owner=user)
         with submit(user1, is_front=True) as (tracking_code, formdata_id):
-            check_tracking_code_access(user, owner=user1, new_owner=user)
+            check_tracking_code_access(user, owner=user1, new_owner=user, expected=expected[i])
+        i += 1
diff --git a/wcs/forms/root.py b/wcs/forms/root.py
index 63d34214..596e49d8 100644
--- a/wcs/forms/root.py
+++ b/wcs/forms/root.py
@@ -174,8 +174,14 @@ class TrackingCodeDirectory(Directory):
             raise errors.TraversalError()
         if BotFilter.is_bot():
             raise errors.AccessForbiddenError()
+
+        formdata_url = formdata.get_url().rstrip('/')
+        if formdata.user_id and not get_request().user:
+            # anonymous user asked to load a tracking code associated with an user,
+            # don't load, ask for authentication instead
+            return redirect('/login/?ReturnUrl=%s' % formdata_url)
         get_session().mark_anonymous_formdata(formdata)
-        return redirect(formdata.get_url().rstrip('/'))
+        return redirect(formdata_url)
 
 
 class TrackingCodesDirectory(Directory):
-- 
2.24.1

