Projet

Général

Profil

0001-auth_oidc-enforce-SameSite-Lax-on-the-state-cookie-4.patch

Benjamin Dauvergne, 16 novembre 2020 11:50

Télécharger (4,48 ko)

Voir les différences:

Subject: [PATCH] auth_oidc: enforce SameSite=Lax on the state cookie (#48347)

SameSite=Lax is needed for the cookie to be sent by the browser during
redirection chain from the provider. We could just depend on the fact
that cookie without SameSite are Lax by default, but it's better to be
explicit.
 src/authentic2/compat/cookies.py  | 22 ++++++++++++++++++++++
 src/authentic2_auth_oidc/views.py | 21 ++++++++++++++++++---
 tests/test_auth_oidc.py           |  3 +++
 3 files changed, 43 insertions(+), 3 deletions(-)
 create mode 100644 src/authentic2/compat/cookies.py
src/authentic2/compat/cookies.py
1
# authentic2 - versatile identity manager
2
# Copyright (C) 2010-2019 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
import django
18

  
19
if django.VERSION < (2, 1):
20
    # Copied from Django >=2.1 / django.http.cookies
21
    from http import cookies
22
    cookies.Morsel._reserved.setdefault('samesite', 'SameSite')
src/authentic2_auth_oidc/views.py
21 21

  
22 22
import requests
23 23

  
24
import django
24 25
from django.conf import settings
25 26
from django.core import signing
26 27
from django.urls import reverse
......
31 32
from django.views.generic.base import View
32 33
from django.http import HttpResponseBadRequest
33 34

  
35
import authentic2.compat.cookies  # F401
34 36
from authentic2.decorators import setting_enabled
35 37
from authentic2.utils import redirect, login, good_next_url, authenticate
36 38

  
......
90 92
    logger.debug('auth_oidc: sent request %s to authorization endpoint "%s"',
91 93
                 params, provider.authorization_endpoint)
92 94
    response = redirect(request, provider.authorization_endpoint, params=params, resolve=False)
93
    response.set_cookie(
94
        'oidc-state', value=state_id, path=reverse('oidc-login-callback'),
95
        httponly=True, secure=request.is_secure())
95

  
96
    # As the oidc-state is used during a redirect from a third-party, we need
97
    # it to user SameSite=Lax. See
98
    # https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Set-Cookie/SameSite
99
    # for more explanations.
100
    if django.VERSION < (2, 1):
101
        response.set_cookie(
102
            'oidc-state', value=state_id, path=reverse('oidc-login-callback'),
103
            httponly=True, secure=request.is_secure())
104
        # work around lack of samesite parameter to set_cookie() in Django 1.11
105
        # it also needs monkeypatch from authentic2.compat.cookies.
106
        response.cookies['oidc-state']['samesite'] = 'Lax'
107
    else:
108
        response.set_cookie(
109
            'oidc-state', value=state_id, path=reverse('oidc-login-callback'),
110
            httponly=True, secure=request.is_secure(), samesite='lax')
96 111
    return response
97 112

  
98 113

  
tests/test_auth_oidc.py
818 818
    response = app.get('/login/?next=/whatever/')
819 819
    assert oidc_provider.name in response.text
820 820
    response = response.click(oidc_provider.name)
821
    # As the oidc-state is used during a redirect from a third-party, we need
822
    # it to be lax.
823
    assert re.search('Set-Cookie.* oidc-state=.*SameSite=Lax', str(response))
821 824
    qs = urlparse.parse_qs(urlparse.urlparse(response.location).query)
822 825
    state = qs['state']
823 826

  
824
-