We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Fix sign-in
We seem to have a problem with old cookies from a different account preventing log in.

Goal page is not accessible once connected
"405 Method Not Allowed"
on this page 
https://liberapay.com/unisson/goal.html when i want to change my goal
I'm connected on my account.

Fix sign-in
We seem to have a problem with old cookies from a different account preventing log in.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `liberapay/security/authentication.py`
Content:
```
1 """Defines website authentication helpers.
2 """
3 import binascii
4 
5 from aspen import Response
6 from liberapay.constants import SESSION
7 from liberapay.models.participant import Participant
8 
9 
10 class _ANON(object):
11     ANON = True
12     is_admin = False
13     id = None
14     __bool__ = __nonzero__ = lambda *a: False
15     get_tip_to = lambda self, tippee: Participant._zero_tip_dict(tippee)
16     __repr__ = lambda self: '<ANON>'
17 
18 
19 ANON = _ANON()
20 
21 
22 def sign_in(request, state):
23     try:
24         body = request.body
25     except Response:
26         return
27 
28     p = None
29 
30     if body.get('log-in.username'):
31         p = Participant.authenticate(
32             'username', 'password',
33             body.pop('log-in.username'), body.pop('log-in.password')
34         )
35         if p and p.status == 'closed':
36             p.update_status('active')
37 
38     elif body.get('sign-in.username'):
39         if body.pop('sign-in.terms') != 'agree':
40             raise Response(400, 'you have to agree to the terms')
41         kind = body.pop('sign-in.kind')
42         if kind not in ('individual', 'organization'):
43             raise Response(400, 'bad kind')
44         with state['website'].db.get_cursor() as c:
45             p = Participant.make_active(
46                 body.pop('sign-in.username'), kind, body.pop('sign-in.password'),
47                 cursor=c
48             )
49             p.add_email(body.pop('sign-in.email'), cursor=c)
50         p.authenticated = True
51 
52     if p:
53         response = state.setdefault('response', Response())
54         p.sign_in(response.headers.cookie)
55         if body.pop('form.repost', None) != 'true':
56             response.redirect(request.line.uri)
57         state['user'] = p
58 
59 
60 def start_user_as_anon():
61     """Make sure we always have a user object, regardless of exceptions during authentication.
62     """
63     return {'user': ANON}
64 
65 
66 def authenticate_user_if_possible(request, state, user):
67     """This signs the user in.
68     """
69     if request.line.uri.startswith('/assets/'):
70         return
71     if 'Authorization' in request.headers:
72         header = request.headers['authorization']
73         if not header.startswith('Basic '):
74             raise Response(401, 'Unsupported authentication method')
75         try:
76             creds = binascii.a2b_base64(header[len('Basic '):]).split(':', 1)
77         except binascii.Error:
78             raise Response(400, 'Malformed "Authorization" header')
79         participant = Participant.authenticate('id', 'password', *creds)
80         if not participant:
81             raise Response(401)
82         return {'user': participant}
83     elif SESSION in request.headers.cookie:
84         creds = request.headers.cookie[SESSION].value.split(':', 1)
85         p = Participant.authenticate('id', 'session', *creds)
86         if p:
87             return {'user': p}
88     elif request.method == 'POST':
89         sign_in(request, state)
90 
91 
92 def add_auth_to_response(response, request=None, user=ANON):
93     if request is None:
94         return  # early parsing must've failed
95     if request.line.uri.startswith('/assets/'):
96         return  # assets never get auth headers
97 
98     if SESSION in request.headers.cookie:
99         if not user.ANON:
100             user.keep_signed_in(response.headers.cookie)
101
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/liberapay/security/authentication.py b/liberapay/security/authentication.py
--- a/liberapay/security/authentication.py
+++ b/liberapay/security/authentication.py
@@ -19,12 +19,15 @@
 ANON = _ANON()
 
 
-def sign_in(request, state):
+def sign_in_with_form_data(request, state):
     try:
         body = request.body
     except Response:
         return
 
+    if not isinstance(body, dict):
+        return
+
     p = None
 
     if body.get('log-in.username'):
@@ -49,12 +52,7 @@
             p.add_email(body.pop('sign-in.email'), cursor=c)
         p.authenticated = True
 
-    if p:
-        response = state.setdefault('response', Response())
-        p.sign_in(response.headers.cookie)
-        if body.pop('form.repost', None) != 'true':
-            response.redirect(request.line.uri)
-        state['user'] = p
+    return p
 
 
 def start_user_as_anon():
@@ -68,6 +66,8 @@
     """
     if request.line.uri.startswith('/assets/'):
         return
+
+    # HTTP auth
     if 'Authorization' in request.headers:
         header = request.headers['authorization']
         if not header.startswith('Basic '):
@@ -80,13 +80,26 @@
         if not participant:
             raise Response(401)
         return {'user': participant}
-    elif SESSION in request.headers.cookie:
+
+    # Cookie and form auth
+    # We want to try cookie auth first, but we want form auth to supersede it
+    p = None
+    response = state.setdefault('response', Response())
+    if SESSION in request.headers.cookie:
         creds = request.headers.cookie[SESSION].value.split(':', 1)
         p = Participant.authenticate('id', 'session', *creds)
         if p:
-            return {'user': p}
-    elif request.method == 'POST':
-        sign_in(request, state)
+            state['user'] = p
+    if request.method == 'POST':
+        old_p = p
+        p = sign_in_with_form_data(request, state)
+        if p:
+            if old_p:
+                old_p.sign_out(response.headers.cookie)
+            p.sign_in(response.headers.cookie)
+            state['user'] = p
+            if request.body.pop('form.repost', None) != 'true':
+                response.redirect(request.line.uri)
 
 
 def add_auth_to_response(response, request=None, user=ANON):

{"golden_diff": "diff --git a/liberapay/security/authentication.py b/liberapay/security/authentication.py\n--- a/liberapay/security/authentication.py\n+++ b/liberapay/security/authentication.py\n@@ -19,12 +19,15 @@\n ANON = _ANON()\n \n \n-def sign_in(request, state):\n+def sign_in_with_form_data(request, state):\n     try:\n         body = request.body\n     except Response:\n         return\n \n+    if not isinstance(body, dict):\n+        return\n+\n     p = None\n \n     if body.get('log-in.username'):\n@@ -49,12 +52,7 @@\n             p.add_email(body.pop('sign-in.email'), cursor=c)\n         p.authenticated = True\n \n-    if p:\n-        response = state.setdefault('response', Response())\n-        p.sign_in(response.headers.cookie)\n-        if body.pop('form.repost', None) != 'true':\n-            response.redirect(request.line.uri)\n-        state['user'] = p\n+    return p\n \n \n def start_user_as_anon():\n@@ -68,6 +66,8 @@\n     \"\"\"\n     if request.line.uri.startswith('/assets/'):\n         return\n+\n+    # HTTP auth\n     if 'Authorization' in request.headers:\n         header = request.headers['authorization']\n         if not header.startswith('Basic '):\n@@ -80,13 +80,26 @@\n         if not participant:\n             raise Response(401)\n         return {'user': participant}\n-    elif SESSION in request.headers.cookie:\n+\n+    # Cookie and form auth\n+    # We want to try cookie auth first, but we want form auth to supersede it\n+    p = None\n+    response = state.setdefault('response', Response())\n+    if SESSION in request.headers.cookie:\n         creds = request.headers.cookie[SESSION].value.split(':', 1)\n         p = Participant.authenticate('id', 'session', *creds)\n         if p:\n-            return {'user': p}\n-    elif request.method == 'POST':\n-        sign_in(request, state)\n+            state['user'] = p\n+    if request.method == 'POST':\n+        old_p = p\n+        p = sign_in_with_form_data(request, state)\n+        if p:\n+            if old_p:\n+                old_p.sign_out(response.headers.cookie)\n+            p.sign_in(response.headers.cookie)\n+            state['user'] = p\n+            if request.body.pop('form.repost', None) != 'true':\n+                response.redirect(request.line.uri)\n \n \n def add_auth_to_response(response, request=None, user=ANON):\n", "issue": "Fix sign-in\nWe seem to have a problem with old cookies from a different account preventing log in.\n\nGoal page is not accessible once connected\n\"405 Method Not Allowed\"\non this page \nhttps://liberapay.com/unisson/goal.html when i want to change my goal\nI'm connected on my account.\n\nFix sign-in\nWe seem to have a problem with old cookies from a different account preventing log in.\n\n", "before_files": [{"content": "\"\"\"Defines website authentication helpers.\n\"\"\"\nimport binascii\n\nfrom aspen import Response\nfrom liberapay.constants import SESSION\nfrom liberapay.models.participant import Participant\n\n\nclass _ANON(object):\n    ANON = True\n    is_admin = False\n    id = None\n    __bool__ = __nonzero__ = lambda *a: False\n    get_tip_to = lambda self, tippee: Participant._zero_tip_dict(tippee)\n    __repr__ = lambda self: '<ANON>'\n\n\nANON = _ANON()\n\n\ndef sign_in(request, state):\n    try:\n        body = request.body\n    except Response:\n        return\n\n    p = None\n\n    if body.get('log-in.username'):\n        p = Participant.authenticate(\n            'username', 'password',\n            body.pop('log-in.username'), body.pop('log-in.password')\n        )\n        if p and p.status == 'closed':\n            p.update_status('active')\n\n    elif body.get('sign-in.username'):\n        if body.pop('sign-in.terms') != 'agree':\n            raise Response(400, 'you have to agree to the terms')\n        kind = body.pop('sign-in.kind')\n        if kind not in ('individual', 'organization'):\n            raise Response(400, 'bad kind')\n        with state['website'].db.get_cursor() as c:\n            p = Participant.make_active(\n                body.pop('sign-in.username'), kind, body.pop('sign-in.password'),\n                cursor=c\n            )\n            p.add_email(body.pop('sign-in.email'), cursor=c)\n        p.authenticated = True\n\n    if p:\n        response = state.setdefault('response', Response())\n        p.sign_in(response.headers.cookie)\n        if body.pop('form.repost', None) != 'true':\n            response.redirect(request.line.uri)\n        state['user'] = p\n\n\ndef start_user_as_anon():\n    \"\"\"Make sure we always have a user object, regardless of exceptions during authentication.\n    \"\"\"\n    return {'user': ANON}\n\n\ndef authenticate_user_if_possible(request, state, user):\n    \"\"\"This signs the user in.\n    \"\"\"\n    if request.line.uri.startswith('/assets/'):\n        return\n    if 'Authorization' in request.headers:\n        header = request.headers['authorization']\n        if not header.startswith('Basic '):\n            raise Response(401, 'Unsupported authentication method')\n        try:\n            creds = binascii.a2b_base64(header[len('Basic '):]).split(':', 1)\n        except binascii.Error:\n            raise Response(400, 'Malformed \"Authorization\" header')\n        participant = Participant.authenticate('id', 'password', *creds)\n        if not participant:\n            raise Response(401)\n        return {'user': participant}\n    elif SESSION in request.headers.cookie:\n        creds = request.headers.cookie[SESSION].value.split(':', 1)\n        p = Participant.authenticate('id', 'session', *creds)\n        if p:\n            return {'user': p}\n    elif request.method == 'POST':\n        sign_in(request, state)\n\n\ndef add_auth_to_response(response, request=None, user=ANON):\n    if request is None:\n        return  # early parsing must've failed\n    if request.line.uri.startswith('/assets/'):\n        return  # assets never get auth headers\n\n    if SESSION in request.headers.cookie:\n        if not user.ANON:\n            user.keep_signed_in(response.headers.cookie)\n", "path": "liberapay/security/authentication.py"}], "after_files": [{"content": "\"\"\"Defines website authentication helpers.\n\"\"\"\nimport binascii\n\nfrom aspen import Response\nfrom liberapay.constants import SESSION\nfrom liberapay.models.participant import Participant\n\n\nclass _ANON(object):\n    ANON = True\n    is_admin = False\n    id = None\n    __bool__ = __nonzero__ = lambda *a: False\n    get_tip_to = lambda self, tippee: Participant._zero_tip_dict(tippee)\n    __repr__ = lambda self: '<ANON>'\n\n\nANON = _ANON()\n\n\ndef sign_in_with_form_data(request, state):\n    try:\n        body = request.body\n    except Response:\n        return\n\n    if not isinstance(body, dict):\n        return\n\n    p = None\n\n    if body.get('log-in.username'):\n        p = Participant.authenticate(\n            'username', 'password',\n            body.pop('log-in.username'), body.pop('log-in.password')\n        )\n        if p and p.status == 'closed':\n            p.update_status('active')\n\n    elif body.get('sign-in.username'):\n        if body.pop('sign-in.terms') != 'agree':\n            raise Response(400, 'you have to agree to the terms')\n        kind = body.pop('sign-in.kind')\n        if kind not in ('individual', 'organization'):\n            raise Response(400, 'bad kind')\n        with state['website'].db.get_cursor() as c:\n            p = Participant.make_active(\n                body.pop('sign-in.username'), kind, body.pop('sign-in.password'),\n                cursor=c\n            )\n            p.add_email(body.pop('sign-in.email'), cursor=c)\n        p.authenticated = True\n\n    return p\n\n\ndef start_user_as_anon():\n    \"\"\"Make sure we always have a user object, regardless of exceptions during authentication.\n    \"\"\"\n    return {'user': ANON}\n\n\ndef authenticate_user_if_possible(request, state, user):\n    \"\"\"This signs the user in.\n    \"\"\"\n    if request.line.uri.startswith('/assets/'):\n        return\n\n    # HTTP auth\n    if 'Authorization' in request.headers:\n        header = request.headers['authorization']\n        if not header.startswith('Basic '):\n            raise Response(401, 'Unsupported authentication method')\n        try:\n            creds = binascii.a2b_base64(header[len('Basic '):]).split(':', 1)\n        except binascii.Error:\n            raise Response(400, 'Malformed \"Authorization\" header')\n        participant = Participant.authenticate('id', 'password', *creds)\n        if not participant:\n            raise Response(401)\n        return {'user': participant}\n\n    # Cookie and form auth\n    # We want to try cookie auth first, but we want form auth to supersede it\n    p = None\n    response = state.setdefault('response', Response())\n    if SESSION in request.headers.cookie:\n        creds = request.headers.cookie[SESSION].value.split(':', 1)\n        p = Participant.authenticate('id', 'session', *creds)\n        if p:\n            state['user'] = p\n    if request.method == 'POST':\n        old_p = p\n        p = sign_in_with_form_data(request, state)\n        if p:\n            if old_p:\n                old_p.sign_out(response.headers.cookie)\n            p.sign_in(response.headers.cookie)\n            state['user'] = p\n            if request.body.pop('form.repost', None) != 'true':\n                response.redirect(request.line.uri)\n\n\ndef add_auth_to_response(response, request=None, user=ANON):\n    if request is None:\n        return  # early parsing must've failed\n    if request.line.uri.startswith('/assets/'):\n        return  # assets never get auth headers\n\n    if SESSION in request.headers.cookie:\n        if not user.ANON:\n            user.keep_signed_in(response.headers.cookie)\n", "path": "liberapay/security/authentication.py"}]}