Projet

Général

Profil

0001-misc-remove-six-module-usage-52503.patch

Valentin Deniaud, 30 mars 2021 15:08

Télécharger (132 ko)

Voir les différences:

Subject: [PATCH] misc: remove six module usage (#52503)

 debian/control                                |  1 -
 debian/py3dist-overrides                      |  1 -
 doc/installation_modes.rst                    |  1 -
 setup.py                                      |  1 -
 src/authentic2/a2_rbac/admin.py               |  3 +-
 src/authentic2/a2_rbac/management.py          |  7 ++-
 .../migrations/0024_fix_self_admin_perm.py    |  5 +-
 src/authentic2/a2_rbac/models.py              |  5 +-
 src/authentic2/app_settings.py                |  3 +-
 src/authentic2/attribute_kinds.py             |  6 +--
 .../attributes_ng/sources/__init__.py         |  5 +-
 .../attributes_ng/sources/django_user.py      |  3 +-
 .../attributes_ng/sources/format.py           |  3 +-
 src/authentic2/authentication.py              |  5 +-
 src/authentic2/backends/ldap_backend.py       | 20 ++++----
 src/authentic2/backends/models_backend.py     |  5 +-
 src/authentic2/cors.py                        |  5 +-
 src/authentic2/crypto.py                      |  5 +-
 src/authentic2/csv_import.py                  |  9 ++--
 src/authentic2/custom_user/models.py          |  4 +-
 src/authentic2/decorators.py                  |  5 +-
 .../disco_service/disco_responder.py          | 12 ++---
 src/authentic2/exponential_retry_timeout.py   |  3 +-
 src/authentic2/idp/saml/backend.py            |  6 +--
 src/authentic2/idp/saml/saml2_endpoints.py    |  5 +-
 src/authentic2/log_filters.py                 |  4 +-
 .../management/commands/check-and-repair.py   |  1 -
 .../commands/clean-unused-accounts.py         |  4 +-
 .../management/commands/slapd-shell.py        |  6 +--
 src/authentic2/manager/forms.py               |  7 ++-
 src/authentic2/manager/ou_views.py            |  3 +-
 src/authentic2/manager/resources.py           |  5 +-
 src/authentic2/manager/service_views.py       |  3 +-
 src/authentic2/manager/user_import.py         |  3 +-
 src/authentic2/manager/views.py               | 10 ++--
 src/authentic2/manager/widgets.py             |  6 +--
 src/authentic2/middleware.py                  |  7 +--
 src/authentic2/migrations/__init__.py         |  5 +-
 src/authentic2/models.py                      | 12 ++---
 src/authentic2/passwords.py                   |  6 +--
 src/authentic2/saml/admin.py                  |  3 +-
 src/authentic2/saml/common.py                 |  6 +--
 src/authentic2/saml/fields.py                 |  5 +-
 .../saml/management/commands/sync-metadata.py |  6 +--
 src/authentic2/saml/models.py                 |  3 +-
 src/authentic2/saml/saml2utils.py             |  5 +-
 src/authentic2/saml/x509utils.py              |  4 +-
 src/authentic2/serializers.py                 |  6 +--
 src/authentic2/utils/__init__.py              | 34 ++++++-------
 src/authentic2/utils/evaluate.py              | 12 ++---
 src/authentic2/utils/lazy.py                  |  3 +-
 src/authentic2/views.py                       |  6 +--
 src/authentic2_auth_fc/models.py              |  6 +--
 src/authentic2_auth_fc/views.py               |  6 +--
 src/authentic2_auth_oidc/backends.py          |  3 +-
 src/authentic2_auth_oidc/utils.py             | 25 +++++-----
 src/authentic2_auth_saml/adapters.py          | 25 +++++-----
 src/authentic2_idp_cas/managers.py            |  4 +-
 src/authentic2_idp_cas/views.py               |  9 ++--
 src/authentic2_idp_oidc/models.py             | 21 ++++----
 src/authentic2_idp_oidc/utils.py              |  7 ++-
 src/authentic2_idp_oidc/views.py              |  7 ++-
 src/django_rbac/backends.py                   |  8 ++--
 src/django_rbac/managers.py                   |  4 +-
 src/django_rbac/models.py                     |  6 +--
 tests/auth_fc/conftest.py                     |  8 ++--
 tests/auth_fc/test_auth_fc.py                 |  4 +-
 tests/conftest.py                             |  5 +-
 tests/test_admin.py                           |  2 +-
 tests/test_all.py                             |  8 ++--
 tests/test_auth_oidc.py                       | 36 +++++++-------
 tests/test_idp_cas.py                         | 43 +++++++++--------
 tests/test_idp_oidc.py                        | 48 +++++++++----------
 tests/test_idp_saml2.py                       |  8 ++--
 tests/test_import_export_site_cmd.py          |  2 +-
 tests/test_ldap.py                            |  4 +-
 tests/test_login.py                           |  3 +-
 tests/test_manager.py                         |  2 +-
 tests/test_registration.py                    |  2 +-
 tests/test_user_manager.py                    |  9 ++--
 tests/test_views.py                           |  2 +-
 tests/utils.py                                | 19 ++++----
 82 files changed, 296 insertions(+), 343 deletions(-)
debian/control
29 29
    python3-djangorestframework (<< 3.10),
30 30
    python3-markdown (>= 2.1),
31 31
    python3-ldap (>= 2.4),
32
    python3-six (>= 1.0),
33 32
    python3-jwcrypto (>= 0.3.1),
34 33
    python3-cryptography (>= 1.3.4),
35 34
    python3-django-filters (>= 1),
debian/py3dist-overrides
9 9
XStatic_jquery_ui       python3-xstatic-jquery-ui
10 10
django-import-export    python3-django-import-export
11 11
django-sekizai          python3-django-sekizai
12
six                     python3-six
13 12
pycryptodome            python3-pycryptodome
14 13
ldaptools               python3-ldaptools
15 14
django-mellon           python3-django-mellon
doc/installation_modes.rst
23 23
- gadjo>=0.6
24 24
- django-import-export>=0.2.7,<=0.4.5
25 25
- djangorestframework>=3.3
26
- six>=1.9
27 26
- Markdown>=2.5
28 27
- python-ldap
29 28

  
setup.py
129 129
        'gadjo>=0.53',
130 130
        'django-import-export>=1,<2',
131 131
        'djangorestframework>=3.3,<3.10',
132
        'six>=1',
133 132
        'Markdown>=2.1',
134 133
        'python-ldap',
135 134
        'django-filter>1,<2.3',
src/authentic2/a2_rbac/admin.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
from django.contrib import admin
18
from django.utils import six
19 18
from django.utils.translation import ugettext_lazy as _
20 19

  
21 20
from . import models
......
90 89
    list_select_related = True
91 90

  
92 91
    def name(self, obj):
93
        return six.text_type(obj)
92
        return str(obj)
94 93

  
95 94
    name.short_description = _('name')
96 95

  
src/authentic2/a2_rbac/management.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
from django.contrib.contenttypes.models import ContentType
18
from django.utils import six
19 18
from django.utils.text import slugify
20 19
from django.utils.translation import ugettext
21 20
from django.utils.translation import ugettext_lazy as _
......
41 40
        # do not create scoped admin roles if the model is not scopable
42 41
        if not ou_model:
43 42
            continue
44
        name = six.text_type(MANAGED_CT[key]['name'])
43
        name = str(MANAGED_CT[key]['name'])
45 44
        slug = '_a2-' + slugify(name)
46
        scoped_name = six.text_type(MANAGED_CT[key]['scoped_name'])
45
        scoped_name = str(MANAGED_CT[key]['scoped_name'])
47 46
        name = scoped_name.format(ou=ou)
48 47
        ou_slug = slug + '-' + ou.slug
49 48
        if app_settings.MANAGED_CONTENT_TYPES == ():
......
123 122
        if ct_tuple not in MANAGED_CT:
124 123
            continue
125 124
        # General admin role
126
        name = six.text_type(MANAGED_CT[ct_tuple]['name'])
125
        name = str(MANAGED_CT[ct_tuple]['name'])
127 126
        slug = '_a2-' + slugify(name)
128 127
        if (
129 128
            app_settings.MANAGED_CONTENT_TYPES is not None
src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py
3 3
from __future__ import unicode_literals
4 4

  
5 5
from django.db import migrations
6
from django.utils.six import text_type
7 6

  
8 7
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP
9 8
from django_rbac.models import CHANGE_OP
......
14 13
    Permission = apps.get_model('a2_rbac', 'Permission')
15 14
    Operation = apps.get_model('django_rbac', 'Operation')
16 15
    ContentType = apps.get_model('contenttypes', 'ContentType')
17
    change_op, _ = Operation.objects.get_or_create(slug=text_type(CHANGE_OP.slug))
18
    manage_members_op, _ = Operation.objects.get_or_create(slug=text_type(MANAGE_MEMBERS_OP.slug))
16
    change_op, _ = Operation.objects.get_or_create(slug=str(CHANGE_OP.slug))
17
    manage_members_op, _ = Operation.objects.get_or_create(slug=str(MANAGE_MEMBERS_OP.slug))
19 18
    ct = ContentType.objects.get_for_model(Role)
20 19
    perms_to_delete = []
21 20
    for role in Role.objects.all():
src/authentic2/a2_rbac/models.py
20 20
from django.core.exceptions import ValidationError
21 21
from django.core.validators import MinValueValidator
22 22
from django.db import models
23
from django.utils import six
24 23
from django.utils.text import slugify
25 24
from django.utils.translation import pgettext_lazy
26 25
from django.utils.translation import ugettext_lazy as _
......
248 247

  
249 248
        admin_role = self.__class__.objects.get_admin_role(
250 249
            self,
251
            name=_('Managers of role "{role}"').format(role=six.text_type(self)),
252
            slug='_a2-managers-of-role-{role}'.format(role=slugify(six.text_type(self))),
250
            name=_('Managers of role "{role}"').format(role=str(self)),
251
            slug='_a2-managers-of-role-{role}'.format(role=slugify(str(self))),
253 252
            permissions=(view_user_perm,),
254 253
            self_administered=True,
255 254
            update_name=True,
src/authentic2/app_settings.py
16 16

  
17 17
import sys
18 18

  
19
import six
20 19
from django.core.exceptions import ImproperlyConfigured
21 20
from django.utils.translation import ugettext_lazy as _
22 21

  
......
26 25

  
27 26
    def __init__(self, default=SENTINEL, definition='', names=None):
28 27
        self.names = names or []
29
        if isinstance(self.names, six.string_types):
28
        if isinstance(self.names, str):
30 29
            self.names = [self.names]
31 30
        self.names = set(self.names)
32 31
        self.default = default
src/authentic2/attribute_kinds.py
28 28
from django.core.validators import RegexValidator
29 29
from django.db.models import query
30 30
from django.urls import reverse
31
from django.utils import formats, html, six
31
from django.utils import formats, html
32 32
from django.utils.functional import keep_lazy
33 33
from django.utils.translation import pgettext_lazy
34 34
from django.utils.translation import ugettext_lazy as _
......
42 42
from .plugins import collect_from_plugins
43 43

  
44 44

  
45
@keep_lazy(six.text_type)
45
@keep_lazy(str)
46 46
def capfirst(value):
47 47
    return value and value[0].upper() + value[1:]
48 48

  
......
75 75
        # Test for the empty string here so that it does not get validated,
76 76
        # and so that subclasses do not need to handle it explicitly
77 77
        # inside the `to_internal_value()` method.
78
        if data == '' or (self.trim_whitespace and six.text_type(data).strip() == ''):
78
        if data == '' or (self.trim_whitespace and str(data).strip() == ''):
79 79
            if not self.allow_blank:
80 80
                self.fail('blank')
81 81
            return ''
src/authentic2/attributes_ng/sources/__init__.py
16 16

  
17 17
import abc
18 18

  
19
from django.utils import six
20 19

  
21

  
22
@six.add_metaclass(abc.ABCMeta)
23
class BaseAttributeSource(object):
20
class BaseAttributeSource(object, metaclass=abc.ABCMeta):
24 21
    """
25 22
    Base class for attribute sources
26 23
    """
src/authentic2/attributes_ng/sources/django_user.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
from django.contrib.auth import get_user_model
18
from django.utils import six
19 18
from django.utils.translation import ugettext_lazy as _
20 19

  
21 20
from django_rbac.utils import get_role_model
......
91 90
        ctx['django_user_' + str(av.attribute.name)] = serialized
92 91
        ctx['django_user_' + str(av.attribute.name) + ':verified'] = av.verified
93 92
    ctx['django_user_groups'] = [group for group in user.groups.all()]
94
    ctx['django_user_group_names'] = [six.text_type(group) for group in user.groups.all()]
93
    ctx['django_user_group_names'] = [str(group) for group in user.groups.all()]
95 94
    if user.username:
96 95
        splitted = user.username.rsplit('@', 1)
97 96
        ctx['django_user_domain'] = splitted[1] if '@' in user.username else ''
src/authentic2/attributes_ng/sources/format.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import six
18 17
from django.core.exceptions import ImproperlyConfigured
19 18

  
20 19
from ...decorators import to_list
......
62 61
            config_error(UNEXPECTED_KEYS_ERROR, unexpected)
63 62
        if 'name' not in keys or 'template' not in keys:
64 63
            config_error(BAD_CONFIG_ERROR)
65
        if not isinstance(d['template'], six.string_types):
64
        if not isinstance(d['template'], str):
66 65
            config_error(TYPE_ERROR)
67 66
        yield d
68 67

  
src/authentic2/authentication.py
16 16

  
17 17
import inspect
18 18

  
19
from django.utils import six
20

  
21 19
try:
22 20
    from django.utils.deprecation import CallableTrue
23 21
except ImportError:
......
71 69
            pass
72 70
        # try BasicAuthentication
73 71
        if (
74
            six.PY3
75
            and 'request'
72
            'request'
76 73
            in inspect.signature(super(Authentic2Authentication, self).authenticate_credentials).parameters
77 74
        ):
78 75
            # compatibility with DRF 3.4
src/authentic2/backends/ldap_backend.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import hashlib
18
import urllib.parse
18 19

  
19 20
try:
20 21
    import ldap
......
36 37
import os
37 38
import random
38 39
import time
40
import urllib.parse
39 41

  
40 42
from django.conf import settings
41 43
from django.contrib import messages
......
43 45
from django.contrib.auth.models import Group
44 46
from django.core.cache import cache
45 47
from django.core.exceptions import ImproperlyConfigured
46
from django.utils import six
47 48
from django.utils.encoding import force_bytes, force_text
48
from django.utils.six.moves.urllib import parse as urlparse
49 49
from django.utils.translation import ngettext
50 50
from django.utils.translation import ugettext as _
51 51

  
......
290 290
def map_text(d):
291 291
    if d is None:
292 292
        return d
293
    elif isinstance(d, six.string_types):
293
    elif isinstance(d, str):
294 294
        return force_text(d)
295 295
    elif isinstance(d, (list, tuple)):
296 296
        return d.__class__(map_text(x) for x in d)
......
1031 1031
        '''Obtain a Django role'''
1032 1032
        kwargs = {}
1033 1033
        slug = None
1034
        if isinstance(role_id, six.string_types):
1034
        if isinstance(role_id, str):
1035 1035
            slug = role_id
1036 1036
        elif isinstance(role_id, (tuple, list)):
1037 1037
            try:
......
1302 1302
                attribute, param = attribute.split(':')
1303 1303
                quote = 'noquote' not in param.split(',')
1304 1304
            if quote:
1305
                decoded.append((attribute, urlparse.unquote(value)))
1305
                decoded.append((attribute, urllib.parse.unquote(value)))
1306 1306
            else:
1307 1307
                decoded.append((attribute, force_text(value)))
1308 1308
        filters = [filter_format(u'(%s=%s)', (a, b)) for a, b in decoded]
......
1322 1322
            if isinstance(part, list):
1323 1323
                part = part[0]
1324 1324
            if quote:
1325
                part = urlparse.quote(part.encode('utf-8'))
1325
                part = urllib.parse.quote(part.encode('utf-8'))
1326 1326
            parts.append(part)
1327 1327
        return ' '.join(part for part in parts)
1328 1328

  
......
1676 1676

  
1677 1677
        # convert string to list of strings for settings accepting it
1678 1678
        for i in cls._TO_ITERABLE:
1679
            if i in block and isinstance(block[i], six.string_types):
1679
            if i in block and isinstance(block[i], str):
1680 1680
                block[i] = (block[i],)
1681 1681

  
1682 1682
        for d in cls._DEFAULTS:
......
1685 1685
                if d == 'user_filter' and app_settings.A2_ACCEPT_EMAIL_AUTHENTICATION:
1686 1686
                    block[d] = '(|(mail=%s)(uid=%s))'
1687 1687
            else:
1688
                if isinstance(cls._DEFAULTS[d], six.string_types):
1689
                    if not isinstance(block[d], six.string_types):
1688
                if isinstance(cls._DEFAULTS[d], str):
1689
                    if not isinstance(block[d], str):
1690 1690
                        raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: attribute %r must be a string' % d)
1691 1691
                    try:
1692 1692
                        block[d] = force_text(block[d])
......
1710 1710
        for key in cls._TO_LOWERCASE:
1711 1711
            # we handle strings, list of strings and list of list or tuple whose first element is a
1712 1712
            # string
1713
            if isinstance(block[key], six.string_types):
1713
            if isinstance(block[key], str):
1714 1714
                block[key] = force_text(block[key]).lower()
1715 1715
            elif isinstance(block[key], (list, tuple)):
1716 1716
                new_seq = []
src/authentic2/backends/models_backend.py
16 16

  
17 17
from __future__ import unicode_literals
18 18

  
19
import functools
20

  
19 21
from django.contrib.auth import get_user_model
20 22
from django.contrib.auth.backends import ModelBackend
21 23
from django.db import models
22
from django.utils import six
23 24

  
24 25
from authentic2.backends import get_user_queryset
25 26
from authentic2.user_login_failure import user_login_failure, user_login_success
......
58 59
                        queries.append(models.Q(**{username_field: upn(username, realm)}))
59 60
        else:
60 61
            queries.append(models.Q(**{username_field: upn(username, realm)}))
61
        queries = six.moves.reduce(models.Q.__or__, queries)
62
        queries = functools.reduce(models.Q.__or__, queries)
62 63
        if ou:
63 64
            queries &= models.Q(ou=ou)
64 65
        return queries
src/authentic2/cors.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17

  
18
import urllib.parse
19

  
18 20
from django.conf import settings
19
from django.utils.six.moves.urllib import parse as urlparse
20 21

  
21 22
from . import app_settings, plugins
22 23
from .decorators import SessionCache
......
24 25

  
25 26
def make_origin(url):
26 27
    '''Build origin of an URL'''
27
    parsed = urlparse.urlparse(url)
28
    parsed = urllib.parse.urlparse(url)
28 29
    if ':' in parsed.netloc:
29 30
        host, port = parsed.netloc.split(':', 1)
30 31
        if parsed.scheme == 'http' and port == 80:
src/authentic2/crypto.py
26 26
from Cryptodome.Protocol.KDF import PBKDF2
27 27
from django.utils.crypto import constant_time_compare
28 28
from django.utils.encoding import force_bytes
29
from django.utils.six import text_type
30 29

  
31 30

  
32 31
class DecryptionError(Exception):
......
123 122
    key_size = 16
124 123
    hmac_size = key_size
125 124

  
126
    if isinstance(salt, text_type):
125
    if isinstance(salt, str):
127 126
        salt = force_bytes(salt)
128 127
    iv = hashmod.new(salt).digest()
129 128

  
......
174 173
        if not crypted or not hmac or prf(key, crypted)[:hmac_size] != hmac:
175 174
            raise DecryptionError('invalid HMAC')
176 175

  
177
        if isinstance(salt, text_type):
176
        if isinstance(salt, str):
178 177
            salt = force_bytes(salt)
179 178
        iv = hashmod.new(salt).digest()
180 179

  
src/authentic2/csv_import.py
27 27
from django.core.validators import RegexValidator
28 28
from django.db import IntegrityError, models
29 29
from django.db.transaction import atomic
30
from django.utils import six
31 30
from django.utils.encoding import force_bytes, force_text
32 31
from django.utils.translation import ugettext as _
33 32

  
......
109 108
    encoding = None
110 109

  
111 110
    def run(self, fd_or_str, encoding):
112
        if isinstance(fd_or_str, six.binary_type):
111
        if isinstance(fd_or_str, bytes):
113 112
            input_fd = io.BytesIO(fd_or_str)
114
        elif isinstance(fd_or_str, six.text_type):
113
        elif isinstance(fd_or_str, str):
115 114
            input_fd = io.StringIO(fd_or_str)
116 115
        elif not hasattr(fd_or_str, 'read1'):
117 116
            try:
......
122 121
                except Exception:
123 122
                    pass
124 123
                content = fd_or_str.read()
125
                if isinstance(content, six.text_type):
124
                if isinstance(content, str):
126 125
                    input_fd = io.StringIO(content)
127 126
                else:
128 127
                    input_fd = io.BytesIO(content)
......
539 538
        form.is_valid()
540 539

  
541 540
        def get_form_errors(form, name):
542
            return [Error('data-error', six.text_type(value)) for value in form.errors.get(name, [])]
541
            return [Error('data-error', str(value)) for value in form.errors.get(name, [])]
543 542

  
544 543
        cells = [
545 544
            CsvCell(
src/authentic2/custom_user/models.py
24 24
from django.core.exceptions import MultipleObjectsReturned, ValidationError
25 25
from django.core.mail import send_mail
26 26
from django.db import models, transaction
27
from django.utils import six, timezone
27
from django.utils import timezone
28 28
from django.utils.translation import ugettext_lazy as _
29 29

  
30 30
try:
......
233 233
        return '%s (%s)' % (human_name, short_id)
234 234

  
235 235
    def __repr__(self):
236
        return '<User: %r>' % six.text_type(self)
236
        return '<User: %r>' % str(self)
237 237

  
238 238
    def clean(self):
239 239
        if not (self.username or self.email or (self.first_name and self.last_name)):
src/authentic2/decorators.py
25 25
from django.core.cache import cache as django_cache
26 26
from django.core.exceptions import ValidationError
27 27
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
28
from django.utils import six
29 28
from django.views.debug import technical_404_response
30 29

  
31 30
from . import app_settings, middleware
......
195 194
        for i, arg in enumerate(args):
196 195
            if self.args and i not in self.args:
197 196
                continue
198
            parts.append(six.text_type(arg))
197
            parts.append(str(arg))
199 198

  
200 199
        for kw, arg in sorted(kwargs.items(), key=lambda x: x[0]):
201 200
            if kw not in self.kwargs:
202 201
                continue
203
            parts.append(u'%s-%s' % (six.text_type(kw), six.text_type(arg)))
202
            parts.append(u'%s-%s' % (str(kw), str(arg)))
204 203
        return u'|'.join(parts)
205 204

  
206 205

  
src/authentic2/disco_service/disco_responder.py
23 23

  
24 24

  
25 25
import logging
26
import urllib.parse
26 27
from xml.dom.minidom import parseString
27 28

  
28 29
from django.conf.urls import url
29 30
from django.http import HttpResponseRedirect
30 31
from django.urls import reverse
31 32
from django.utils.http import urlquote
32
from django.utils.six.moves.urllib import parse as urlparse
33 33
from django.utils.translation import ugettext as _
34 34

  
35 35
from authentic2 import settings
......
117 117

  
118 118

  
119 119
def is_param_id_in_return_url(return_url, returnIDParam):
120
    url = urlparse.urlparse(return_url)
121
    if url.query and returnIDParam in urlparse.parse_qs(url.query):
120
    url = urllib.parse.urlparse(return_url)
121
    if url.query and returnIDParam in urllib.parse.parse_qs(url.query):
122 122
        return True
123 123
    return False
124 124

  
125 125

  
126 126
def add_param_to_url(url, param_name, value):
127
    scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
127
    scheme, netloc, path, params, query, fragment = urllib.parse.urlparse(url)
128 128
    if query:
129
        qs = urlparse.parse_qs(query)
129
        qs = urllib.parse.parse_qs(query)
130 130
        qs[param_name] = [value]
131 131
        query = urlparse.urlencode(qs)
132 132
    else:
133 133
        query = '%s=%s' % (param_name, value)
134
    return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
134
    return urllib.parse.urlunparse((scheme, netloc, path, params, query, fragment))
135 135

  
136 136

  
137 137
def disco(request):
src/authentic2/exponential_retry_timeout.py
19 19
import time
20 20

  
21 21
from django.core.cache import cache
22
from django.utils import six
23 22

  
24 23

  
25 24
class ExponentialRetryTimeout(object):
......
45 44
        self.key_prefix = key_prefix
46 45

  
47 46
    def key(self, keys):
48
        key = u'-'.join(six.text_type(key) for key in keys)
47
        key = u'-'.join(str(key) for key in keys)
49 48
        key = key.encode('utf-8')
50 49
        return '%s%s' % (self.key_prefix or self.KEY_PREFIX, hashlib.md5(key).hexdigest())
51 50

  
src/authentic2/idp/saml/backend.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import functools
17 18
import logging
18 19
import operator
19 20
import random
21
from urllib.parse import quote
20 22

  
21 23
from django.db.models import Q
22 24
from django.template.loader import render_to_string
23 25
from django.urls import reverse
24
from django.utils import six
25
from django.utils.six.moves.urllib.parse import quote
26 26
from django.utils.translation import ugettext as _
27 27

  
28 28
import authentic2.idp.saml.saml2_endpoints as saml2_endpoints
......
68 68
                queries.append(
69 69
                    q.filter(sp_options_policy__isnull=True, liberty_provider__entity_id__in=sessions_eids)
70 70
                )
71
        qs = six.moves.reduce(operator.__or__, queries)
71
        qs = functools.reduce(operator.__or__, queries)
72 72
        # do some prefetching
73 73
        qs = qs.prefetch_related('liberty_provider')
74 74
        qs = qs.select_related('sp_options_policy')
src/authentic2/idp/saml/saml2_endpoints.py
41 41
import string
42 42
import xml.etree.cElementTree as ctree
43 43
from functools import wraps
44
from urllib.parse import quote, urlencode
44 45

  
45 46
from django.conf import settings
46 47
from django.contrib import messages
......
50 51
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseRedirect
51 52
from django.shortcuts import redirect, render
52 53
from django.urls import reverse
53
from django.utils import six
54 54
from django.utils.encoding import force_bytes, force_str, force_text
55
from django.utils.six.moves.urllib.parse import quote, urlencode
56 55
from django.utils.translation import ugettext as _
57 56
from django.utils.translation import ugettext_noop as N_
58 57
from django.views.decorators.cache import never_cache
......
821 820
    if not access_granted:
822 821
        logger.debug('access denied, return answer to the requester')
823 822
        set_saml2_response_responder_status_code(
824
            login.response, lasso.SAML2_STATUS_CODE_REQUEST_DENIED, msg=six.text_type(dic['message'])
823
            login.response, lasso.SAML2_STATUS_CODE_REQUEST_DENIED, msg=str(dic['message'])
825 824
        )
826 825
        return finish_sso(request, login)
827 826

  
src/authentic2/log_filters.py
16 16

  
17 17
import logging
18 18

  
19
from django.utils import six
20

  
21 19

  
22 20
class RequestContextFilter(logging.Filter):
23 21
    DEFAULT_USERNAME = '-'
......
45 43

  
46 44
        if not hasattr(record, 'user'):
47 45
            if hasattr(request, 'user') and request.user.is_authenticated:
48
                record.user = six.text_type(request.user)
46
                record.user = str(request.user)
49 47
            else:
50 48
                record.user = self.DEFAULT_USERNAME
51 49

  
src/authentic2/management/commands/check-and-repair.py
27 27
from django.db.models import Count, Q
28 28
from django.db.models.functions import Lower
29 29
from django.db.transaction import atomic
30
from django.utils.six.moves import input
31 30
from django.utils.timezone import localtime
32 31

  
33 32
from authentic2 import app_settings
src/authentic2/management/commands/clean-unused-accounts.py
17 17
from __future__ import print_function
18 18

  
19 19
import logging
20
import urllib.parse
20 21
from datetime import timedelta
21 22

  
22 23
from django.conf import settings
......
25 26
from django.db import transaction
26 27
from django.db.models import F
27 28
from django.utils import timezone, translation
28
from django.utils.six.moves.urllib import parse as urlparse
29 29

  
30 30
from authentic2.backends.ldap_backend import LDAPBackend
31 31
from authentic2.utils import send_templated_mail
......
110 110
        ctx = {
111 111
            'user': user,
112 112
            'days_to_deletion': days_to_deletion,
113
            'login_url': urlparse.urljoin(settings.SITE_BASE_URL, settings.LOGIN_URL),
113
            'login_url': urllib.parse.urljoin(settings.SITE_BASE_URL, settings.LOGIN_URL),
114 114
        }
115 115
        with transaction.atomic():
116 116
            if not self.fake:
src/authentic2/management/commands/slapd-shell.py
16 16

  
17 17
from __future__ import print_function
18 18

  
19
import io
19 20
import logging
20 21
import re
21 22
import sys
22 23

  
23 24
from django.contrib.auth import get_user_model
24 25
from django.core.management.base import BaseCommand
25
from django.utils import six
26 26
from ldap.dn import escape_dn_chars
27 27
from ldif import LDIFWriter
28 28

  
......
48 48
    def ldap(self, command, attrs):
49 49
        self.logger.debug('received command %s %s', command, attrs)
50 50
        if command == 'SEARCH':
51
            out = six.BytesIO()
51
            out = io.BytesIO()
52 52
            ldif_writer = LDIFWriter(out)
53 53
            qs = get_user_model().objects.all()
54 54
            if attrs['filter'] != '(objectClass=*)':
......
85 85
            for user in qs:
86 86
                o = {}
87 87
                for user_attribute, ldap_attribute in MAPPING.items():
88
                    o[ldap_attribute] = [six.text_type(getattr(user, user_attribute)).encode('utf-8')]
88
                    o[ldap_attribute] = [str(getattr(user, user_attribute)).encode('utf-8')]
89 89
                o['objectClass'] = ['inetOrgPerson']
90 90
                dn = 'uid=%s,%s' % (escape_dn_chars(o['uid'][0]), attrs['suffix'])
91 91
                self.logger.debug(u'sending entry %s %s', dn, o)
src/authentic2/manager/forms.py
23 23
from django.contrib.auth import get_user_model
24 24
from django.contrib.contenttypes.models import ContentType
25 25
from django.core.exceptions import ValidationError
26
from django.utils import six
27 26
from django.utils.text import slugify
28 27
from django.utils.translation import pgettext, ugettext
29 28
from django.utils.translation import ugettext_lazy as _
......
67 66
    def save(self, commit=True):
68 67
        instance = self.instance
69 68
        if not instance.slug:
70
            instance.slug = slugify(six.text_type(instance.name)).lstrip('_')
69
            instance.slug = slugify(str(instance.name)).lstrip('_')
71 70
            qs = instance.__class__.objects.all()
72 71
            if instance.pk:
73 72
                qs = qs.exclude(pk=instance.pk)
......
441 440
            if self.show_all_ou and (len(self.ou_qs) > 1 or self.search_all_ous):
442 441
                choices.append(('all', all_ou_label))
443 442
            for ou in self.ou_qs:
444
                choices.append((str(ou.pk), six.text_type(ou)))
443
                choices.append((str(ou.pk), str(ou)))
445 444
            if self.show_none_ou and self.search_all_ous:
446 445
                choices.append(('none', pgettext('organizational unit', 'None')))
447 446

  
......
703 702
    @staticmethod
704 703
    def raise_validation_error(error_message):
705 704
        message_prefix = ugettext('Invalid import file')
706
        raise forms.ValidationError('%s : %s' % (message_prefix, six.text_type(error_message)))
705
        raise forms.ValidationError('%s : %s' % (message_prefix, str(error_message)))
707 706

  
708 707

  
709 708
class UserNewImportForm(UserImportForm):
src/authentic2/manager/ou_views.py
21 21
from django.db import transaction
22 22
from django.http import HttpResponseRedirect
23 23
from django.urls import reverse
24
from django.utils import six
25 24
from django.utils.translation import ugettext as _
26 25
from django.views.generic import FormView
27 26

  
......
68 67

  
69 68
    @property
70 69
    def title(self):
71
        return six.text_type(self.object)
70
        return str(self.object)
72 71

  
73 72
    def authorize(self, request, *args, **kwargs):
74 73
        super(OrganizationalUnitDetailView, self).authorize(request, *args, **kwargs)
src/authentic2/manager/resources.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
from django.contrib.auth import get_user_model
18
from django.utils import six
19 18
from import_export.fields import Field
20 19
from import_export.resources import ModelResource
21 20
from import_export.widgets import Widget
......
30 29
        raise NotImplementedError
31 30

  
32 31
    def render(self, value, object):
33
        return u', '.join(six.text_type(v) for v in value.all())
32
        return u', '.join(str(v) for v in value.all())
34 33

  
35 34

  
36 35
class UserResource(ModelResource):
......
42 41
            result.add(role)
43 42
            for pr in role.parent_relation.all():
44 43
                result.add(pr.parent)
45
        return ', '.join(six.text_type(x) for x in result)
44
        return ', '.join(str(x) for x in result)
46 45

  
47 46
    class Meta:
48 47
        model = User
src/authentic2/manager/service_views.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
from django.contrib import messages
18
from django.utils import six
19 18
from django.utils.translation import ugettext as _
20 19

  
21 20
from authentic2.models import Service
......
53 52

  
54 53
    @property
55 54
    def title(self):
56
        return six.text_type(self.object)
55
        return str(self.object)
57 56

  
58 57
    def get_table_queryset(self):
59 58
        return self.object.authorized_roles.all()
src/authentic2/manager/user_import.py
30 30
from django.conf import settings
31 31
from django.core.files.storage import default_storage
32 32
from django.db import connection
33
from django.utils import six
34 33
from django.utils.functional import cached_property
35 34
from django.utils.timezone import utc
36 35
from django.utils.translation import ugettext_lazy as _
......
225 224
                    logger.exception('error during report %s:%s run', self.user_import.uuid, self.uuid)
226 225
                    state = self.STATE_ERROR
227 226
                    try:
228
                        exception = six.text_type(e)
227
                        exception = str(e)
229 228
                    except Exception:
230 229
                        exception = repr(repr(e))
231 230
                else:
src/authentic2/manager/views.py
26 26
from django.forms import MediaDefiningClass
27 27
from django.http import Http404, HttpResponse
28 28
from django.urls import reverse, reverse_lazy
29
from django.utils import six
30 29
from django.utils.encoding import force_text
31 30
from django.utils.functional import cached_property
32 31
from django.utils.timezone import now
......
62 61
        return super(MultipleOUMixin, self).get_context_data(**kwargs)
63 62

  
64 63

  
65
@six.add_metaclass(MediaMixinBase)
66
class MediaMixin(object):
64
class MediaMixin(object, metaclass=MediaMixinBase):
67 65
    '''Expose needed CSS and JS files as a media object'''
68 66

  
69 67
    class Media:
......
401 399

  
402 400
    def get_instance_name(self):
403 401
        if hasattr(self, 'get_object'):
404
            return six.text_type(self.get_object())
402
            return str(self.get_object())
405 403
        return u''
406 404

  
407 405
    def get_context_data(self, **kwargs):
......
674 672
                continue
675 673
            menu_entries.append(
676 674
                {
677
                    'label': six.text_type(entry['label']),
675
                    'label': str(entry['label']),
678 676
                    'slug': entry.get('slug', ''),
679
                    'url': request.build_absolute_uri(six.text_type(entry['href'])),
677
                    'url': request.build_absolute_uri(str(entry['href'])),
680 678
                }
681 679
            )
682 680
        return menu_entries
src/authentic2/manager/widgets.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import base64
18
import functools
18 19
import operator
19 20
import pickle
20 21

  
21 22
from django.contrib.auth import get_user_model
22 23
from django.core import signing
23
from django.utils import six
24 24
from django.utils.encoding import force_text
25 25
from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget
26 26

  
......
43 43
        queries = []
44 44
        for term in term.split():
45 45
            queries.append(super(SplitTermMixin, self).filter_queryset(term, queryset=qs))
46
        qs = six.moves.reduce(self.split_term_operator, queries)
46
        qs = functools.reduce(self.split_term_operator, queries)
47 47
        return qs
48 48

  
49 49

  
......
101 101
    ]
102 102

  
103 103
    def label_from_instance(self, obj):
104
        label = six.text_type(obj)
104
        label = str(obj)
105 105
        if obj.ou and utils.get_ou_count() > 1:
106 106
            label = u'{ou} - {obj}'.format(ou=obj.ou, obj=obj)
107 107
        return label
src/authentic2/middleware.py
21 21
except ImportError:
22 22
    threading = None
23 23

  
24
import urllib.parse
25

  
24 26
from django import http
25 27
from django.conf import settings
26 28
from django.contrib import messages
27 29
from django.utils.deprecation import MiddlewareMixin
28 30
from django.utils.functional import SimpleLazyObject
29
from django.utils.six.moves.urllib import parse as urlparse
30 31
from django.utils.translation import ugettext as _
31 32

  
32 33
from . import app_settings, plugins, utils
......
162 163
            return response
163 164
        if not getattr(response, 'display_message', True):
164 165
            return response
165
        parsed_url = urlparse.urlparse(url)
166
        parsed_url = urllib.parse.urlparse(url)
166 167
        if not parsed_url.scheme and not parsed_url.netloc:
167 168
            return response
168
        parsed_request_url = urlparse.urlparse(request.build_absolute_uri())
169
        parsed_request_url = urllib.parse.urlparse(request.build_absolute_uri())
169 170
        if (parsed_request_url.scheme == parsed_url.scheme or not parsed_url.scheme) and (
170 171
            parsed_request_url.netloc == parsed_url.netloc
171 172
        ):
src/authentic2/migrations/__init__.py
1 1
import itertools
2 2

  
3 3
from django.db.migrations.operations.base import Operation
4
from django.utils import six
5 4

  
6 5

  
7 6
class CreatePartialIndexes(Operation):
......
64 63
                for clause in where:
65 64
                    if isinstance(clause, tuple):
66 65
                        clause, params = clause
67
                        assert isinstance(clause, six.string_types)
66
                        assert isinstance(clause, str)
68 67
                        assert isinstance(params, tuple)
69 68
                        clause = clause % tuple(schema_editor.quote_value(param) for param in params)
70
                    assert isinstance(clause, six.string_types)
69
                    assert isinstance(clause, str)
71 70
                    clauses.append(clause)
72 71
                where_clause = ' AND '.join(clauses)
73 72
                # SQLite does not accept parameters in partial index creations, don't ask why :/
src/authentic2/models.py
16 16

  
17 17
import datetime
18 18
import time
19
import urllib.parse
19 20
import uuid
20 21

  
21 22
import django
......
27 28
from django.core.exceptions import ValidationError
28 29
from django.db import models, transaction
29 30
from django.db.models.query import Q
30
from django.utils import six, timezone
31
from django.utils import timezone
31 32
from django.utils.http import urlquote
32
from django.utils.six.moves.urllib import parse as urlparse
33 33
from django.utils.translation import ugettext_lazy as _
34 34
from model_utils.managers import QueryManager
35 35

  
......
117 117

  
118 118
    def get_logout_url(self, request):
119 119
        ok_icon_url = (
120
            request.build_absolute_uri(urlparse.urljoin(settings.STATIC_URL, 'authentic2/images/ok.png'))
120
            request.build_absolute_uri(urllib.parse.urljoin(settings.STATIC_URL, 'authentic2/images/ok.png'))
121 121
            + '?nonce=%s' % time.time()
122 122
        )
123 123
        return self.logout_url.format(urlquote(ok_icon_url))
......
363 363
        verbose_name_plural = _('password reset')
364 364

  
365 365
    def __str__(self):
366
        return six.text_type(self.user)
366
        return str(self.user)
367 367

  
368 368

  
369 369
class Service(models.Model):
......
418 418
        return self.name
419 419

  
420 420
    def __repr__(self):
421
        return '<%s %r>' % (self.__class__.__name__, six.text_type(self))
421
        return '<%s %r>' % (self.__class__.__name__, str(self))
422 422

  
423 423
    def authorize(self, user):
424 424
        if not self.authorized_roles.exists():
......
492 492
        else:
493 493
            return _uuid
494 494

  
495
        if isinstance(_uuid, six.text_type):
495
        if isinstance(_uuid, str):
496 496
            _uuid = _uuid.encode('ascii')
497 497
            _uuid = base64url_decode(_uuid)
498 498
        return uuid.UUID(bytes=_uuid)
src/authentic2/passwords.py
20 20
import string
21 21

  
22 22
from django.core.exceptions import ValidationError
23
from django.utils import six
24 23
from django.utils.functional import lazy
25 24
from django.utils.module_loading import import_string
26 25
from django.utils.translation import ugettext as _
......
50 49
    return ''.join(new_password)
51 50

  
52 51

  
53
@six.add_metaclass(abc.ABCMeta)
54
class PasswordChecker(object):
52
class PasswordChecker(object, metaclass=abc.ABCMeta):
55 53
    class Check(object):
56 54
        def __init__(self, label, result):
57 55
            self.label = label
......
134 132
        return ''
135 133

  
136 134

  
137
password_help_text = lazy(password_help_text, six.text_type)
135
password_help_text = lazy(password_help_text, str)
src/authentic2/saml/admin.py
22 22
from django.contrib import admin, messages
23 23
from django.core.exceptions import ValidationError
24 24
from django.forms import ModelForm
25
from django.utils import six
26 25
from django.utils.translation import ugettext as _
27 26

  
28 27
try:
......
72 71
    def render(self, name, value, attrs=None, **kwargs):
73 72
        if attrs is None:
74 73
            attrs = {}
75
        if isinstance(value, (str, six.text_type)):
74
        if isinstance(value, (str, str)):
76 75
            attrs['rows'] = value.count('\n') + 5
77 76
            attrs['cols'] = min(max((len(x) for x in value.split('\n'))), 150)
78 77
        return super(TextAndFileWidget, self).render(name, value, attrs, **kwargs)
src/authentic2/saml/common.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import datetime
18
import functools
18 19
import logging
19 20
import os.path
20 21
import re
......
25 26
from django.http import Http404, HttpResponse, HttpResponseRedirect
26 27
from django.shortcuts import render
27 28
from django.urls import reverse
28
from django.utils import six
29 29
from django.utils.encoding import force_text
30 30

  
31 31
from authentic2.compat_lasso import lasso
......
337 337
        return None
338 338
    logger.debug('loaded %d bytes', len(metadata))
339 339
    try:
340
        metadata = six.text_type(metadata, 'utf-8')
340
        metadata = str(metadata, 'utf-8')
341 341
    except UnicodeDecodeError:
342 342
        logging.error('SAML metadata autoload: retrieved metadata for entity id %s is not UTF-8', provider_id)
343 343
        return None
......
586 586
                        value,
587 587
                    )
588 588
    if session_not_on_or_afters:
589
        return six.moves.reduce(min, session_not_on_or_afters)
589
        return functools.reduce(min, session_not_on_or_afters)
590 590
    return None
src/authentic2/saml/fields.py
27 27
from django.core.exceptions import ValidationError
28 28
from django.db import models
29 29
from django.template.defaultfilters import pluralize
30
from django.utils import six
31 30
from django.utils.encoding import force_bytes, force_text
32 31
from django.utils.text import capfirst
33 32

  
......
56 55
# Initial author: Oliver Beattie
57 56

  
58 57

  
59
class PickledObject(six.text_type):
58
class PickledObject(str):
60 59
    """A subclass of string so it can be told whether a string is
61 60
    a pickled object or not (if the object is an instance of this class
62 61
    then it must [well, should] be a pickled one)."""
......
161 160
        return MultiSelectFormField(**defaults)
162 161

  
163 162
    def get_db_prep_value(self, value, connection, prepared=False):
164
        if isinstance(value, six.string_types):
163
        if isinstance(value, str):
165 164
            return value
166 165
        elif isinstance(value, list):
167 166
            return ",".join(value)
src/authentic2/saml/management/commands/sync-metadata.py
16 16

  
17 17
from __future__ import print_function
18 18

  
19
import io
19 20
import os
20 21
import sys
21 22
import warnings
......
26 27
from django.core.management.base import BaseCommand, CommandError
27 28
from django.db.transaction import atomic
28 29
from django.template.defaultfilters import slugify
29
from django.utils import six
30 30
from django.utils.translation import gettext as _
31 31

  
32 32
from authentic2.compat_lasso import lasso
......
340 340
            response = requests.get(metadata_file_path)
341 341
            if not response.ok:
342 342
                raise CommandError('Unable to open url %s' % metadata_file_path)
343
            metadata_file = six.BytesIO(response.content)
343
            metadata_file = io.BytesIO(response.content)
344 344
        else:
345 345
            try:
346 346
                with open(metadata_file_path, 'rb') as fd:
347
                    metadata_file = six.BytesIO(fd.read())
347
                    metadata_file = io.BytesIO(fd.read())
348 348
            except IOError:
349 349
                raise CommandError('Unable to open file %s' % metadata_file_path)
350 350

  
src/authentic2/saml/models.py
25 25
from django.db import models
26 26
from django.db.models import Q
27 27
from django.db.models.query import QuerySet
28
from django.utils import six
29 28
from django.utils.encoding import force_str, force_text
30 29
from django.utils.translation import ugettext_lazy as _
31 30

  
......
484 483
        return (self.liberty_provider.slug,)
485 484

  
486 485
    def __str__(self):
487
        return six.text_type(self.liberty_provider)
486
        return str(self.liberty_provider)
488 487

  
489 488
    class Meta:
490 489
        verbose_name = _('SAML service provider')
src/authentic2/saml/saml2utils.py
22 22
import time
23 23
import xml.etree.ElementTree as etree
24 24

  
25
from django.utils import six
26 25
from django.utils.encoding import force_text
27 26

  
28 27
from authentic2.compat_lasso import lasso
......
30 29

  
31 30

  
32 31
def filter_attribute_private_key(message):
33
    if isinstance(message, six.string_types):
32
    if isinstance(message, str):
34 33
        return re.sub(r' (\w+:)?(PrivateKey=")([&#;\w/ +-=])+(")', '', message)
35 34
    else:
36 35
        return message
37 36

  
38 37

  
39 38
def filter_element_private_key(message):
40
    if isinstance(message, six.string_types):
39
    if isinstance(message, str):
41 40
        return re.sub(
42 41
            r'(<saml)(p)?(:PrivateKeyFile>-----BEGIN RSA PRIVATE KEY-----)'
43 42
            r'([&#;\w/+=\s])+'
src/authentic2/saml/x509utils.py
19 19
import subprocess
20 20
import tempfile
21 21

  
22
import six
23

  
24 22
_openssl = 'openssl'
25 23

  
26 24

  
27 25
def decapsulate_pem_file(file_or_string):
28 26
    '''Remove PEM header lines'''
29
    if not isinstance(file_or_string, six.string_types):
27
    if not isinstance(file_or_string, str):
30 28
        content = file_or_string.read()
31 29
    else:
32 30
        content = file_or_string
src/authentic2/serializers.py
23 23
from django.core.serializers.json import Serializer as JSONSerializer
24 24
from django.core.serializers.python import _get_model
25 25
from django.db import DEFAULT_DB_ALIAS
26
from django.utils import six
27 26

  
28 27

  
29 28
class Serializer(JSONSerializer):
......
73 72
    """
74 73
    from django.core.serializers.python import Deserializer as PythonDeserializer
75 74

  
76
    if not isinstance(stream_or_string, (bytes, six.string_types)):
75
    if not isinstance(stream_or_string, (bytes, str)):
77 76
        stream_or_string = stream_or_string.read()
78 77
    if isinstance(stream_or_string, bytes):
79 78
        stream_or_string = stream_or_string.decode('utf-8')
......
85 84
    except GeneratorExit:
86 85
        raise
87 86
    except Exception as e:
88
        # Map to deserializer error
89
        six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])
87
        raise DeserializationError(e)
src/authentic2/utils/__init__.py
19 19
import logging
20 20
import random
21 21
import time
22
import urllib.parse
22 23
import uuid
23 24
from functools import wraps
24 25
from importlib import import_module
......
40 41
from django.template.context import make_context
41 42
from django.template.loader import TemplateDoesNotExist, render_to_string, select_template
42 43
from django.urls import reverse
43
from django.utils import html, six, timezone
44
from django.utils import html, timezone
44 45
from django.utils.encoding import iri_to_uri, uri_to_iri
45 46
from django.utils.formats import localize
46
from django.utils.six.moves.urllib import parse as urlparse
47 47
from django.utils.translation import ungettext
48 48

  
49 49
try:
......
171 171
    backends = []
172 172
    for backend_path in getattr(app_settings, setting_name):
173 173
        kwargs = {}
174
        if not isinstance(backend_path, six.string_types):
174
        if not isinstance(backend_path, str):
175 175
            backend_path, kwargs = backend_path
176 176
        kwargs_settings = getattr(app_settings, setting_name + '_KWARGS', {})
177 177
        backend = load_backend(backend_path, kwargs_settings)
......
232 232

  
233 233
def add_arg(url, key, value=None):
234 234
    '''Add a parameter to an URL'''
235
    key = urlparse.quote(key)
235
    key = urllib.parse.quote(key)
236 236
    if value is not None:
237
        add = '%s=%s' % (key, urlparse.quote(value))
237
        add = '%s=%s' % (key, urllib.parse.quote(value))
238 238
    else:
239 239
        add = key
240 240
    if '?' in url:
......
262 262

  
263 263
def field_names(list_of_field_name_and_titles):
264 264
    for t in list_of_field_name_and_titles:
265
        if isinstance(t, six.string_types):
265
        if isinstance(t, str):
266 266
            yield t
267 267
        else:
268 268
            yield t[0]
......
270 270

  
271 271
def is_valid_url(url):
272 272
    try:
273
        parsed = urlparse.urlparse(url)
273
        parsed = urllib.parse.urlparse(url)
274 274
        if parsed.scheme in ('http', 'https', ''):
275 275
            return True
276 276
    except Exception:
......
307 307
    else:
308 308
        url = to
309 309
    url = iri_to_uri(url)
310
    scheme, netloc, path, query_string, o_fragment = urlparse.urlsplit(url)
311
    url = uri_to_iri(urlparse.urlunsplit((scheme, netloc, path, '', '')))
310
    scheme, netloc, path, query_string, o_fragment = urllib.parse.urlsplit(url)
311
    url = uri_to_iri(urllib.parse.urlunsplit((scheme, netloc, path, '', '')))
312 312
    fragment = fragment or o_fragment
313 313
    # Django < 1.6 compat, query_string is not optional
314 314
    url_params = QueryDict(query_string=query_string, mutable=True)
......
348 348
        if request:
349 349
            url = request.build_absolute_uri(url)
350 350
        elif hasattr(settings, 'SITE_BASE_URL'):
351
            url = urlparse.urljoin(settings.SITE_BASE_URL, url)
351
            url = urllib.parse.urljoin(settings.SITE_BASE_URL, url)
352 352
        else:
353 353
            raise TypeError('make_url() absolute cannot be used without request')
354 354
    # keep using unicode
......
426 426
    # explicitly state that the session has been modified
427 427
    request.session.modified = True
428 428
    event = {
429
        'who': six.text_type(request.user),
429
        'who': str(request.user),
430 430
        'who_id': getattr(request.user, 'pk', None),
431 431
        'how': how,
432 432
        'when': int(time.time()),
433 433
    }
434 434
    kwargs = {
435
        'who': six.text_type(request.user)[:80],
435
        'who': str(request.user)[:80],
436 436
        'how': how,
437 437
    }
438 438
    nonce = nonce or get_nonce(request)
......
621 621
def normalize_attribute_values(values):
622 622
    '''Take a list of values or a single one and normalize it'''
623 623
    values_set = set()
624
    if isinstance(values, six.string_types) or not hasattr(values, '__iter__'):
624
    if isinstance(values, str) or not hasattr(values, '__iter__'):
625 625
        values = [values]
626 626
    for value in values:
627 627
        if isinstance(value, bool):
628 628
            value = str(value).lower()
629
        values_set.add(six.text_type(value))
629
        values_set.add(str(value))
630 630
    return values_set
631 631

  
632 632

  
......
682 682
    """
683 683
    from .. import middleware
684 684

  
685
    if isinstance(template_names, six.string_types):
685
    if isinstance(template_names, str):
686 686
        template_names = [template_names]
687 687
    if per_ou_templates and getattr(user_or_email, 'ou', None):
688 688
        new_template_names = []
......
1055 1055
    if good_next_url(request, next_url):
1056 1056
        if replace:
1057 1057
            for key, value in replace.items():
1058
                next_url = next_url.replace(key, urlparse.quote(value))
1058
                next_url = next_url.replace(key, urllib.parse.quote(value))
1059 1059
        return next_url
1060 1060
    return default
1061 1061

  
......
1127 1127
    If not scheme and not port are given, port compare is skipped.
1128 1128
    The last two rules allow authorizing complete domains easily.
1129 1129
    """
1130
    p1, p2 = urlparse.urlparse(url1), urlparse.urlparse(url2)
1130
    p1, p2 = urllib.parse.urlparse(url1), urllib.parse.urlparse(url2)
1131 1131
    p1_host, p1_port = netloc_to_host_port(p1.netloc)
1132 1132
    p2_host, p2_port = netloc_to_host_port(p2.netloc)
1133 1133

  
src/authentic2/utils/evaluate.py
25 25

  
26 26
import ast
27 27

  
28
from django.utils import six
29 28
from django.utils.translation import ugettext as _
30 29

  
31 30

  
......
110 109
            # set the nearer expr node as the node of the error
111 110
            if e.node is None and hasattr(node, 'col_offset'):
112 111
                e.set_node(node)
113
            six.reraise(*sys.exc_info())
112
            raise e
114 113

  
115 114
    @lru_cache(maxsize=1024)
116 115
    def __call__(self, expression):
......
126 125
            if e.text is None:
127 126
                e.text = expression
128 127
            e.params = {'expression': expression}
129
            six.reraise(*sys.exc_info())
128
            raise e
130 129
        return compile(tree, expression, mode='eval')
131 130

  
132 131

  
......
179 178
        super(ConditionValidator, self).__init__(
180 179
            authorized_nodes=authorized_nodes, forbidden_nodes=forbidden_nodes
181 180
        )
182
        if six.PY3:
183
            self.authorized_nodes.append(ast.NameConstant)
181
        self.authorized_nodes.append(ast.NameConstant)
184 182

  
185 183
    def check_Name(self, node):
186 184
        if node.id.startswith('_'):
......
225 223
            raise ExpressionError(
226 224
                _('variable is not defined: %s') % e, code='undefined-variable', text=expression, column=0
227 225
            )
228
    except Exception:
226
    except Exception as e:
229 227
        if on_raise is not None:
230 228
            return on_raise
231
        six.reraise(*sys.exc_info())
229
        raise e
src/authentic2/utils/lazy.py
16 16

  
17 17
from __future__ import unicode_literals
18 18

  
19
from django.utils import six
20 19
from django.utils.encoding import force_text
21 20
from django.utils.functional import keep_lazy
22 21
from django.utils.text import format_lazy
......
30 29
    return format_lazy(fstring, *args)
31 30

  
32 31

  
33
@keep_lazy(six.text_type)
32
@keep_lazy(str)
34 33
def lazy_label(default, func):
35 34
    """Allow using a getter for a label, with late binding.
36 35

  
src/authentic2/views.py
42 42
from django.template import loader
43 43
from django.template.loader import render_to_string
44 44
from django.urls import reverse
45
from django.utils import six, timezone
45
from django.utils import timezone
46 46
from django.utils.translation import ugettext as _
47 47
from django.views.decorators.cache import never_cache
48 48
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
......
452 452
                value = filter(None, value)
453 453
                value = [html_value(attribute, at_value) for at_value in value]
454 454
                if not title:
455
                    title = six.text_type(attribute)
455
                    title = str(attribute)
456 456
            else:
457 457
                # fallback to model attributes
458 458
                try:
......
471 471
                if not isinstance(value, (list, tuple)):
472 472
                    value = (value,)
473 473
                raw_value = value
474
                value = [six.text_type(v) for v in value]
474
                value = [str(v) for v in value]
475 475
            if value or app_settings.A2_PROFILE_DISPLAY_EMPTY_FIELDS:
476 476
                profile.append((title, value))
477 477
                attributes.append({'attribute': attribute, 'values': raw_value})
src/authentic2_auth_fc/models.py
18 18
import hashlib
19 19
import hmac
20 20
import json
21
import urllib.parse
21 22

  
22 23
from django.conf import settings
23 24
from django.db import models
24 25
from django.utils.encoding import force_bytes, force_text
25
from django.utils.six.moves.urllib import parse as urlparse
26 26
from django.utils.timezone import now
27 27
from django.utils.translation import ugettext_lazy as _
28 28

  
......
66 66
        return None, 'id_token is expired'
67 67

  
68 68
    def check_issuer():
69
        parsed = urlparse.urlparse(app_settings.authorize_url)
69
        parsed = urllib.parse.urlparse(app_settings.authorize_url)
70 70
        if 'iss' not in payload:
71 71
            return False
72 72
        try:
73
            parsed_issuer = urlparse.urlparse(payload['iss'])
73
            parsed_issuer = urllib.parse.urlparse(payload['iss'])
74 74
        except Exception:
75 75
            return False
76 76
        return parsed_issuer.scheme == parsed.scheme and parsed_issuer.netloc == parsed.netloc
src/authentic2_auth_fc/views.py
16 16

  
17 17
import json
18 18
import logging
19
import urllib.parse
19 20
import uuid
20 21

  
21 22
import requests
......
31 32
from django.shortcuts import render, resolve_url
32 33
from django.urls import reverse
33 34
from django.utils.http import is_safe_url, urlencode
34
from django.utils.six.moves.urllib import parse as urlparse
35 35
from django.utils.translation import ugettext as _
36 36
from django.views.generic import FormView, View
37 37
from requests_oauthlib import OAuth2Session
......
509 509
            redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
510 510

  
511 511
        # Prevent errors when redirect_to does not contain fc-login-or-link view
512
        parsed_redirect_to = urlparse.urlparse(redirect_to)
512
        parsed_redirect_to = urllib.parse.urlparse(redirect_to)
513 513
        if parsed_redirect_to.path == reverse('fc-login-or-link'):
514
            redirect_to = urlparse.parse_qs(parsed_redirect_to.query).get(
514
            redirect_to = urllib.parse.parse_qs(parsed_redirect_to.query).get(
515 515
                REDIRECT_FIELD_NAME, [a2_utils.make_url('auth_homepage')]
516 516
            )[0]
517 517
        params = {
src/authentic2_auth_oidc/backends.py
20 20
import requests
21 21
from django.contrib.auth import get_user_model
22 22
from django.contrib.auth.backends import ModelBackend
23
from django.utils import six
24 23
from django.utils.timezone import now
25 24
from jwcrypto.jwk import JWK
26 25
from jwcrypto.jwt import JWT
......
88 87
            jwt = JWT(jwt=original_id_token, key=key_or_keyset, check_claims={}, algs=algs)
89 88
            jwt.claims
90 89

  
91
        if isinstance(id_token.aud, six.text_type) and provider.client_id != id_token.aud:
90
        if isinstance(id_token.aud, str) and provider.client_id != id_token.aud:
92 91
            logger.warning(
93 92
                'auth_oidc: invalid id_token audience %s != provider client_id %s',
94 93
                id_token.aud,
src/authentic2_auth_oidc/utils.py
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17 17
import datetime
18
import urllib.parse
18 19

  
19 20
import requests
20 21
from django.shortcuts import get_object_or_404
21
from django.utils import six
22
from django.utils.six.moves.urllib import parse as urlparse
23 22
from django.utils.timezone import utc
24 23
from django.utils.translation import ugettext as _
25 24
from jwcrypto.common import JWException, base64url_encode, json_decode
......
93 92

  
94 93
REQUIRED_ID_TOKEN_KEYS = set(['iss', 'sub', 'aud', 'exp', 'iat'])
95 94
KEY_TYPES = {
96
    'iss': six.text_type,
97
    'sub': six.text_type,
95
    'iss': str,
96
    'sub': str,
98 97
    'exp': int,
99 98
    'iat': int,
100 99
    'auth_time': int,
101
    'nonce': six.text_type,
102
    'acr': six.text_type,
103
    'azp': six.text_type,
100
    'nonce': str,
101
    'acr': str,
102
    'azp': str,
104 103
    # aud and amr havec specific checks
105 104
}
106 105

  
......
120 119
    nonce = None
121 120

  
122 121
    def __init__(self, encoded):
123
        if not isinstance(encoded, (six.binary_type, six.string_types)):
122
        if not isinstance(encoded, (bytes, str)):
124 123
            raise IDTokenError(_('Encoded ID Token must be either binary or string data'))
125 124
        self._encoded = encoded
126 125

  
......
139 138
            if key == 'amr':
140 139
                if not isinstance(decoded['amr'], list):
141 140
                    raise IDTokenError(_('invalid amr value: %s') % decoded['amr'])
142
                if not all(isinstance(v, six.text_type) for v in decoded['amr']):
141
                if not all(isinstance(v, str) for v in decoded['amr']):
143 142
                    raise IDTokenError(_('invalid amr value: %s') % decoded['amr'])
144 143
            elif key in KEY_TYPES:
145 144
                if not isinstance(decoded[key], KEY_TYPES[key]):
......
197 196

  
198 197

  
199 198
def check_https(url):
200
    return urlparse.urlparse(url).scheme == 'https'
199
    return urllib.parse.urlparse(url).scheme == 'https'
201 200

  
202 201

  
203 202
def register_issuer(name, issuer=None, openid_configuration=None, verify=True, timeout=None, ou=None):
......
293 292

  
294 293

  
295 294
def get_openid_configuration_url(issuer):
296
    parsed = urlparse.urlparse(issuer)
295
    parsed = urllib.parse.urlparse(issuer)
297 296
    if parsed.query or parsed.fragment or parsed.scheme != 'https':
298 297
        raise ValueError(
299 298
            _('invalid issuer URL, it must use the https:// scheme and not have a ' 'query or fragment')
300 299
        )
301
    issuer = urlparse.urlunparse((parsed.scheme, parsed.netloc, parsed.path.rstrip('/'), None, None, None))
300
    issuer = urllib.parse.urlunparse(
301
        (parsed.scheme, parsed.netloc, parsed.path.rstrip('/'), None, None, None)
302
    )
302 303
    return issuer + '/.well-known/openid-configuration'
src/authentic2_auth_saml/adapters.py
21 21
from django.contrib import messages
22 22
from django.core.exceptions import MultipleObjectsReturned
23 23
from django.db.transaction import atomic
24
from django.utils import six
25 24
from django.utils.translation import ugettext as _
26 25
from mellon.adapters import DefaultAdapter, UserCreationError
27 26
from mellon.utils import get_setting
......
44 43
        super(MappingError, self).__init__(message)
45 44

  
46 45
    def __str__(self):
47
        s = six.text_type(self.args[0])
46
        s = str(self.args[0])
48 47
        if self.details:
49 48
            s += ' ' + repr(self.details)
50 49
        return s
......
127 126
            action = mapping.get('action', 'set-attribute')
128 127
            mandatory = mapping.get('mandatory', False) is True
129 128
            method = None
130
            if isinstance(action, six.string_types):
129
            if isinstance(action, str):
131 130
                try:
132 131
                    method = getattr(self, 'action_' + action.replace('-', '_'))
133 132
                except AttributeError:
......
149 148

  
150 149
    def action_rename(self, user, idp, saml_attributes, mapping):
151 150
        from_name = mapping.get('from')
152
        if not from_name or not isinstance(from_name, six.string_types):
151
        if not from_name or not isinstance(from_name, str):
153 152
            raise MappingError('missing from in rename')
154 153
        to_name = mapping.get('to')
155
        if not to_name or not isinstance(to_name, six.string_types):
154
        if not to_name or not isinstance(to_name, str):
156 155
            raise MappingError('missing to in rename')
157 156
        if from_name in saml_attributes:
158 157
            saml_attributes[to_name] = saml_attributes[from_name]
159 158

  
160 159
    def action_set_attribute(self, user, idp, saml_attributes, mapping):
161 160
        attribute = mapping.get('attribute')
162
        if not attribute or not isinstance(attribute, six.string_types):
161
        if not attribute or not isinstance(attribute, str):
163 162
            raise MappingError('missing attribute key')
164 163

  
165 164
        saml_attribute = mapping.get('saml_attribute')
166
        if not saml_attribute or not isinstance(saml_attribute, six.string_types):
165
        if not saml_attribute or not isinstance(saml_attribute, str):
167 166
            raise MappingError('missing saml_attribute key')
168 167

  
169 168
        if saml_attribute not in saml_attributes:
......
199 198
        slug = ou_desc.get('slug')
200 199
        name = ou_desc.get('name')
201 200
        if slug:
202
            if not isinstance(slug, six.string_types):
201
            if not isinstance(slug, str):
203 202
                raise MappingError('invalid ou.slug in ou description')
204 203
            try:
205 204
                return OU.objects.get(slug=slug)
206 205
            except OU.DoesNotExist:
207 206
                raise MappingError('unknown ou', details={'slug': slug})
208 207
        elif name:
209
            if not isinstance(name, six.string_types):
208
            if not isinstance(name, str):
210 209
                raise MappingError('invalid ou.slug in ou description')
211 210
            try:
212 211
                return OU.objects.get(name=name)
......
228 227
            kwargs['ou'] = ou
229 228

  
230 229
        if slug:
231
            if not isinstance(slug, six.string_types):
230
            if not isinstance(slug, str):
232 231
                raise MappingError('invalid role slug', details={'slug': slug})
233 232
            kwargs['slug'] = slug
234 233
        elif name:
235
            if not isinstance(name, six.string_types):
234
            if not isinstance(name, str):
236 235
                raise MappingError('invalid role name', details={'name': name})
237 236
            kwargs['name'] = name
238 237
        else:
......
249 248
        condition = mapping.get('condition')
250 249
        if condition is None:
251 250
            return True
252
        if not isinstance(condition, six.string_types):
251
        if not isinstance(condition, str):
253 252
            raise MappingError('invalid condition')
254 253
        try:
255 254
            # use a proxy to simplify condition expressions as subscript is forbidden
......
258 257
            logger.debug('auth_saml: condition %r is %s', condition, value, extra={'user': user})
259 258
            return value
260 259
        except Exception as e:
261
            raise MappingError('condition evaluation failed', details={'error': six.text_type(e)})
260
            raise MappingError('condition evaluation failed', details={'error': str(e)})
262 261

  
263 262
    def action_add_role(self, user, idp, saml_attributes, mapping):
264 263
        role = self.get_role(mapping)
src/authentic2_idp_cas/managers.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import urllib.parse
17 18
from datetime import timedelta
18 19

  
19 20
from django.db import models
20 21
from django.db.models import query
21
from django.utils.six.moves.urllib import parse as urlparse
22 22
from django.utils.timezone import now
23 23

  
24 24

  
......
37 37
class ServiceQuerySet(query.QuerySet):
38 38
    def for_service(self, service):
39 39
        '''Find service with the longest match'''
40
        parsed = urlparse.urlparse(service)
40
        parsed = urllib.parse.urlparse(service)
41 41
        matches = []
42 42
        for match in self.filter(urls__contains=parsed.netloc):
43 43
            urls = match.get_urls()
src/authentic2_idp_cas/views.py
21 21

  
22 22
import requests
23 23
from django.http import HttpResponse, HttpResponseBadRequest
24
from django.utils import six
25 24
from django.utils.timezone import now
26 25
from django.views.generic.base import View
27 26

  
......
262 261
            if st.service.identifier_attribute not in attributes:
263 262
                self.logger.error(
264 263
                    'unable to compute an identifier for user %r and service %s',
265
                    six.text_type(st.user),
264
                    str(st.user),
266 265
                    st.service_url,
267 266
                )
268 267
                return self.validation_failure(request, service, INTERNAL_ERROR)
......
299 298
            'validation success service: %r ticket: %s user: %r identifier: %r',
300 299
            st.service_url,
301 300
            st.ticket_id,
302
            six.text_type(st.user),
301
            str(st.user),
303 302
            identifier,
304 303
        )
305 304
        return self.real_validation_success(request, st, identifier)
......
327 326
        root = ET.Element(SERVICE_RESPONSE_ELT)
328 327
        success = ET.SubElement(root, AUTHENTICATION_SUCCESS_ELT)
329 328
        user = ET.SubElement(success, USER_ELT)
330
        user.text = six.text_type(identifier)
329
        user.text = str(identifier)
331 330
        self.provision_pgt(request, st, success)
332 331
        self.provision_attributes(request, st, success)
333 332
        return HttpResponse(ET.tostring(root, encoding='utf-8'), content_type='text/xml')
......
349 348
        for key, values in values.items():
350 349
            for value in values:
351 350
                attribute_elt = ET.SubElement(attributes_elt, '{%s}%s' % (CAS_NAMESPACE, key))
352
                attribute_elt.text = six.text_type(value)
351
                attribute_elt.text = str(value)
353 352

  
354 353
    def provision_pgt(self, request, st, success):
355 354
        """Provision a PGT ticket if requested"""
src/authentic2_idp_oidc/models.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import urllib.parse
17 18
import uuid
18 19
from importlib import import_module
19 20

  
......
22 23
from django.core.exceptions import ImproperlyConfigured, ValidationError
23 24
from django.core.validators import URLValidator
24 25
from django.db import models
25
from django.utils import six
26
from django.utils.six.moves.urllib import parse as urlparse
27 26
from django.utils.timezone import now
28 27
from django.utils.translation import ugettext_lazy as _
29 28

  
......
34 33

  
35 34

  
36 35
def generate_uuid():
37
    return six.text_type(uuid.uuid4())
36
    return str(uuid.uuid4())
38 37

  
39 38

  
40 39
def validate_https_url(data):
......
173 172
        if len(redirect_uri) > app_settings.REDIRECT_URI_MAX_LENGTH:
174 173
            raise ValueError('redirect_uri length > %s' % app_settings.REDIRECT_URI_MAX_LENGTH)
175 174

  
176
        parsed_uri = urlparse.urlparse(redirect_uri)
175
        parsed_uri = urllib.parse.urlparse(redirect_uri)
177 176
        for valid_redirect_uri in self.redirect_uris.split():
178
            parsed_valid_uri = urlparse.urlparse(valid_redirect_uri)
177
            parsed_valid_uri = urllib.parse.urlparse(valid_redirect_uri)
179 178
            if parsed_uri.scheme != parsed_valid_uri.scheme:
180 179
                continue
181 180
            if parsed_valid_uri.netloc.startswith('*'):
......
257 256

  
258 257
    def __repr__(self):
259 258
        return '<OIDCAuthorization client:%r user:%r scopes:%r>' % (
260
            self.client_id and six.text_type(self.client),
261
            self.user_id and six.text_type(self.user),
259
            self.client_id and str(self.client),
260
            self.user_id and str(self.user),
262 261
            self.scopes,
263 262
        )
264 263

  
......
324 323
    def __repr__(self):
325 324
        return '<OIDCCode uuid:%s client:%s user:%s expired:%s scopes:%s>' % (
326 325
            self.uuid,
327
            self.client_id and six.text_type(self.client),
328
            self.user_id and six.text_type(self.user),
326
            self.client_id and str(self.client),
327
            self.user_id and str(self.user),
329 328
            self.expired,
330 329
            self.scopes,
331 330
        )
......
362 361
    def __repr__(self):
363 362
        return '<OIDCAccessToken uuid:%s client:%s user:%s expired:%s scopes:%s>' % (
364 363
            self.uuid,
365
            self.client_id and six.text_type(self.client),
366
            self.user_id and six.text_type(self.user),
364
            self.client_id and str(self.client),
365
            self.user_id and str(self.user),
367 366
            self.expired,
368 367
            self.scopes,
369 368
        )
src/authentic2_idp_oidc/utils.py
17 17
import base64
18 18
import hashlib
19 19
import json
20
import urllib.parse
20 21
import uuid
21 22

  
22 23
from django.conf import settings
23 24
from django.core.exceptions import ImproperlyConfigured
24
from django.utils import six
25 25
from django.utils.encoding import force_bytes, force_text
26
from django.utils.six.moves.urllib import parse as urlparse
27 26
from jwcrypto.jwk import JWK, InvalidJWKValue, JWKSet
28 27
from jwcrypto.jwt import JWT
29 28

  
......
107 106

  
108 107

  
109 108
def url_domain(url):
110
    return urlparse.urlparse(url).netloc.split(':')[0]
109
    return urllib.parse.urlparse(url).netloc.split(':')[0]
111 110

  
112 111

  
113 112
def make_sub(client, user):
......
165 164

  
166 165
def normalize_claim_values(values):
167 166
    values_list = []
168
    if isinstance(values, six.string_types) or not hasattr(values, '__iter__'):
167
    if isinstance(values, str) or not hasattr(values, '__iter__'):
169 168
        return values
170 169
    for value in values:
171 170
        if isinstance(value, bool):
src/authentic2_idp_oidc/views.py
36 36
from django.http import HttpResponse, HttpResponseNotAllowed, JsonResponse
37 37
from django.shortcuts import render
38 38
from django.urls import reverse
39
from django.utils import six
40 39
from django.utils.encoding import force_text
41 40
from django.utils.http import urlencode
42 41
from django.utils.timezone import now, utc
......
423 422
            'idp_oidc: sending code %s for scopes %s for service %s', code.uuid, ' '.join(scopes), client
424 423
        )
425 424
        params = {
426
            'code': six.text_type(code.uuid),
425
            'code': str(code.uuid),
427 426
        }
428 427
        if state is not None:
429 428
            params['state'] = state
......
664 663
    )
665 664
    return JsonResponse(
666 665
        {
667
            'access_token': six.text_type(access_token.uuid),
666
            'access_token': str(access_token.uuid),
668 667
            'token_type': 'Bearer',
669 668
            'expires_in': int(expires_in.total_seconds()),
670 669
            'id_token': utils.make_idtoken(client, id_token),
......
726 725
        id_token['nonce'] = oidc_code.nonce
727 726
    return JsonResponse(
728 727
        {
729
            'access_token': six.text_type(access_token.uuid),
728
            'access_token': str(access_token.uuid),
730 729
            'token_type': 'Bearer',
731 730
            'expires_in': int(expires_in.total_seconds()),
732 731
            'id_token': utils.make_idtoken(client, id_token),
src/django_rbac/backends.py
1 1
import copy
2
import functools
2 3

  
3 4
from django.conf import settings
4 5
from django.contrib.contenttypes.models import ContentType
5 6
from django.db.models.query import Q
6
from django.utils import six
7 7

  
8 8
try:
9 9
    from django.core.exceptions import FieldDoesNotExist
......
145 145
            return False
146 146
        if user_obj.is_superuser:
147 147
            return True
148
        if isinstance(perm_or_perms, six.string_types):
148
        if isinstance(perm_or_perms, str):
149 149
            perm_or_perms = [perm_or_perms]
150 150
        perm_or_perms = set(perm_or_perms)
151 151
        cache = self.get_permission_cache(user_obj)
......
174 174
            return False
175 175
        if user_obj.is_superuser:
176 176
            return True
177
        if isinstance(perm_or_perms, six.string_types):
177
        if isinstance(perm_or_perms, str):
178 178
            perm_or_perms = [perm_or_perms]
179 179
        perm_or_perms = set(perm_or_perms)
180 180
        cache = self.get_permission_cache(user_obj)
......
197 197
                ct_id, fk = key.split('.')
198 198
                q.append(Q(pk=int(fk)))
199 199
        if q:
200
            return six.moves.reduce(Q.__or__, q)
200
            return functools.reduce(Q.__or__, q)
201 201
        return False
202 202

  
203 203
    def filter_by_perm(self, user_obj, perm_or_perms, qs):
src/django_rbac/managers.py
1 1
import contextlib
2
import functools
2 3
import threading
3 4

  
4 5
from django.contrib.auth import get_user_model
......
6 7
from django.db import models
7 8
from django.db.models import query
8 9
from django.db.models.query import Prefetch, Q
9
from django.utils import six
10 10

  
11 11
from . import utils
12 12

  
......
210 210
        obsolete = old - add
211 211
        if obsolete:
212 212
            queries = (query.Q(parent_id=a, child_id=b, direct=False) for a, b in obsolete)
213
            self.model.objects.filter(six.moves.reduce(query.Q.__or__, queries)).delete()
213
            self.model.objects.filter(functools.reduce(query.Q.__or__, queries)).delete()
214 214

  
215 215

  
216 216
@contextlib.contextmanager
src/django_rbac/models.py
1
import functools
1 2
import hashlib
2 3
import operator
3 4

  
4 5
from django.conf import settings
5 6
from django.db import models
6 7
from django.db.models.query import Prefetch, Q
7
from django.utils import six
8 8
from django.utils.text import slugify
9 9
from django.utils.translation import ugettext_lazy as _
10 10

  
......
45 45
    def save(self, *args, **kwargs):
46 46
        # truncate slug and add a hash if it's too long
47 47
        if not self.slug:
48
            self.slug = slugify(six.text_type(self.name)).lstrip('_')
48
            self.slug = slugify(str(self.name)).lstrip('_')
49 49
        if len(self.slug) > 256:
50 50
            self.slug = self.slug[:252] + hashlib.md5(self.slug).hexdigest()[:4]
51 51
        if not self.uuid:
......
373 373
            if hasattr(backend, "filter_by_perm"):
374 374
                results.append(backend.filter_by_perm(self, perm_or_perms, qs))
375 375
        if results:
376
            return six.moves.reduce(operator.__or__, results)
376
            return functools.reduce(operator.__or__, results)
377 377
        else:
378 378
            return qs
379 379

  
tests/auth_fc/conftest.py
18 18
import contextlib
19 19
import datetime
20 20
import json
21
import urllib.parse as urlparse
21
import urllib.parse
22 22
import uuid
23 23

  
24 24
import httmock
......
60 60

  
61 61
    def handle_authorization(self, app, url, **kwargs):
62 62
        assert url.startswith('https://fcp.integ01')
63
        parsed_url = urlparse.urlparse(url)
63
        parsed_url = urllib.parse.urlparse(url)
64 64
        query = QueryDict(parsed_url.query)
65 65
        assert_equals_url(query['redirect_uri'], self.callback_url)
66 66
        assert query['client_id'] == self.client_id
......
90 90
            app.session.flush()
91 91
        response = app.get(path)
92 92
        self.callback_params = {
93
            k: v for k, v in QueryDict(urlparse.urlparse(response.location).query).items()
93
            k: v for k, v in QueryDict(urllib.parse.urlparse(response.location).query).items()
94 94
        }
95 95
        response = response.follow()
96 96
        response = response.click(href='callback')
......
142 142

  
143 143
    def handle_logout(self, app, url):
144 144
        assert url.startswith('https://fcp.integ01.dev-franceconnect.fr/api/v1/logout')
145
        parsed_url = urlparse.urlparse(url)
145
        parsed_url = urllib.parse.urlparse(url)
146 146
        query = QueryDict(parsed_url.query)
147 147
        assert_equals_url(query['post_logout_redirect_uri'], 'http://testserver' + reverse('fc-logout'))
148 148
        assert query['state']
tests/auth_fc/test_auth_fc.py
16 16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 17

  
18 18
import datetime
19
import urllib.parse
19 20

  
20 21
import mock
21 22
import requests
22 23
from django.contrib.auth import get_user_model
23 24
from django.urls import reverse
24
from django.utils.six.moves.urllib import parse as urlparse
25 25
from django.utils.timezone import now
26 26

  
27 27
from authentic2.custom_user.models import DeletedUser
......
34 34

  
35 35

  
36 36
def path(url):
37
    return urlparse.urlparse(url).path
37
    return urllib.parse.urlparse(url).path
38 38

  
39 39

  
40 40
def test_login_redirect(app, franceconnect):
tests/conftest.py
16 16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 17

  
18 18

  
19
import urllib.parse
20

  
19 21
import django
20 22
import django_webtest
21 23
import mock
......
25 27
from django.core.management import call_command
26 28
from django.db import connection
27 29
from django.db.migrations.executor import MigrationExecutor
28
from django.utils.six.moves.urllib import parse as urlparse
29 30
from pytest_django.migrations import DisableMigrations
30 31

  
31 32
from authentic2 import hooks as a2_hooks
......
458 459
    else:
459 460

  
460 461
        def check_location(response, default_return):
461
            assert urlparse.urljoin('http://testserver/', default_return).endswith(response['Location'])
462
            assert urllib.parse.urljoin('http://testserver/', default_return).endswith(response['Location'])
462 463

  
463 464
    return check_location
464 465

  
tests/test_admin.py
17 17

  
18 18
from __future__ import unicode_literals
19 19

  
20
from django.utils.six.moves.urllib.parse import urlparse
20
from urllib.parse import urlparse
21 21

  
22 22
from authentic2.custom_user.models import User
23 23
from authentic2.models import Attribute
tests/test_all.py
17 17

  
18 18
import base64
19 19
import json
20
import urllib.parse
20 21

  
21 22
import pytest
22 23
from django.contrib.auth import get_user_model
......
29 30
from django.test.utils import override_settings
30 31
from django.urls import reverse
31 32
from django.utils.encoding import force_text
32
from django.utils.six import text_type
33
from django.utils.six.moves.urllib import parse as urlparse
34 33
from django.utils.translation import ugettext as _
35 34
from rest_framework import status, test
36 35

  
......
203 202
        response = login_require(request, login_hint=['backoffice'])
204 203
        self.assertEqualsURL(response['Location'].split('?', 1)[0], '/login/')
205 204
        self.assertEqualsURL(
206
            urlparse.parse_qs(response['Location'].split('?', 1)[1])['next'][0], '/coin?nonce=xxx&next=/zob/'
205
            urllib.parse.parse_qs(response['Location'].split('?', 1)[1])['next'][0],
206
            '/coin?nonce=xxx&next=/zob/',
207 207
        )
208 208
        self.assertEqual(request.session['login-hint'], ['backoffice'])
209 209

  
......
385 385
        for i, name in enumerate(attribute_kinds.get_attribute_kinds()):
386 386
            fields['field_%d' % i] = attribute_kinds.get_form_field(name)
387 387
        AttributeKindForm = type('AttributeKindForm', (forms.Form,), fields)
388
        text_type(AttributeKindForm().as_p())
388
        str(AttributeKindForm().as_p())
389 389

  
390 390

  
391 391
class APITest(TestCase):
tests/test_auth_oidc.py
21 21
import random
22 22
import re
23 23
import time
24
import urllib.parse
24 25

  
25 26
import pytest
26 27
from django.contrib.auth import get_user_model
......
28 29
from django.http import QueryDict
29 30
from django.urls import reverse
30 31
from django.utils.encoding import force_str, force_text
31
from django.utils.six.moves.urllib import parse as urlparse
32 32
from django.utils.timezone import now, utc
33 33
from httmock import HTTMock, urlmatch
34 34
from jwcrypto.common import base64url_decode, base64url_encode, json_encode
......
248 248
    provides_kid_header=False,
249 249
    kid=None,
250 250
):
251
    token_endpoint = urlparse.urlparse(oidc_provider.token_endpoint)
252
    userinfo_endpoint = urlparse.urlparse(oidc_provider.userinfo_endpoint)
253
    token_revocation_endpoint = urlparse.urlparse(oidc_provider.token_revocation_endpoint)
251
    token_endpoint = urllib.parse.urlparse(oidc_provider.token_endpoint)
252
    userinfo_endpoint = urllib.parse.urlparse(oidc_provider.userinfo_endpoint)
253
    token_revocation_endpoint = urllib.parse.urlparse(oidc_provider.token_revocation_endpoint)
254 254

  
255 255
    @urlmatch(netloc=token_endpoint.netloc, path=token_endpoint.path)
256 256
    def token_endpoint_mock(url, request):
257
        if urlparse.parse_qs(request.body).get('code') == [code]:
257
        if urllib.parse.parse_qs(request.body).get('code') == [code]:
258 258
            exp = now() + datetime.timedelta(seconds=10)
259 259
            id_token = {
260 260
                'iss': oidc_provider.issuer,
......
341 341

  
342 342
    @urlmatch(netloc=token_revocation_endpoint.netloc, path=token_revocation_endpoint.path)
343 343
    def token_revocation_endpoint_mock(url, request):
344
        query = urlparse.parse_qs(request.body)
344
        query = urllib.parse.parse_qs(request.body)
345 345
        assert 'token' in query
346 346
        return {
347 347
            'status_code': 200,
......
458 458
    response = app.get('/admin/').maybe_follow()
459 459
    assert oidc_provider.name in response.text
460 460
    response = response.click(oidc_provider.name)
461
    location = urlparse.urlparse(response.location)
462
    endpoint = urlparse.urlparse(oidc_provider.authorization_endpoint)
461
    location = urllib.parse.urlparse(response.location)
462
    endpoint = urllib.parse.urlparse(oidc_provider.authorization_endpoint)
463 463
    assert location.scheme == endpoint.scheme
464 464
    assert location.netloc == endpoint.netloc
465 465
    assert location.path == endpoint.path
......
510 510
    assert set(hooks.auth_oidc_backend_modify_user[0]['kwargs']) >= set(
511 511
        ['user', 'provider', 'user_info', 'id_token', 'access_token']
512 512
    )
513
    assert urlparse.urlparse(response['Location']).path == '/admin/'
513
    assert urllib.parse.urlparse(response['Location']).path == '/admin/'
514 514
    assert User.objects.count() == 1
515 515
    user = User.objects.get()
516 516
    assert user.ou == get_default_ou()
......
588 588
    response = app.get('/').maybe_follow()
589 589
    assert oidc_provider.name in response.text
590 590
    response = response.click(oidc_provider.name)
591
    location = urlparse.urlparse(response.location)
591
    location = urllib.parse.urlparse(response.location)
592 592
    query = QueryDict(location.query)
593 593
    state = query['state']
594 594
    nonce = query['nonce']
......
603 603
        with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, sub=simple_user.uuid, nonce=nonce):
604 604
            response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state})
605 605

  
606
    assert urlparse.urlparse(response['Location']).path == '/'
606
    assert urllib.parse.urlparse(response['Location']).path == '/'
607 607
    assert User.objects.count() == 1
608 608
    user = User.objects.get()
609 609
    # verify user was not modified
......
630 630
    response = app.get('/').maybe_follow()
631 631
    assert oidc_provider.name in response.text
632 632
    response = response.click(oidc_provider.name)
633
    location = urlparse.urlparse(response.location)
633
    location = urllib.parse.urlparse(response.location)
634 634
    query = QueryDict(location.query)
635 635
    state = query['state']
636 636
    nonce = query['nonce']
......
658 658
    config_file = os.path.join(config_dir, 'openid_configuration.json')
659 659
    with open(config_file) as f:
660 660
        oidc_conf = json.load(f)
661
    jwks_uri = urlparse.urlparse(oidc_conf['jwks_uri'])
661
    jwks_uri = urllib.parse.urlparse(oidc_conf['jwks_uri'])
662 662

  
663 663
    @urlmatch(netloc=jwks_uri.netloc, path=jwks_uri.path)
664 664
    def jwks_mock(url, request):
......
705 705
    response = app.get('/').maybe_follow()
706 706
    assert oidc_provider_rsa.name in response.text
707 707
    response = response.click(oidc_provider_rsa.name)
708
    location = urlparse.urlparse(response.location)
708
    location = urllib.parse.urlparse(response.location)
709 709
    query = QueryDict(location.query)
710 710
    state = query['state']
711 711
    nonce = query['nonce']
......
771 771

  
772 772
    response = app.get('/').maybe_follow()
773 773
    response = response.click(oidc_provider.name)
774
    location = urlparse.urlparse(response.location)
774
    location = urllib.parse.urlparse(response.location)
775 775
    query = QueryDict(location.query)
776 776
    state = query['state']
777 777
    nonce = query['nonce']
......
799 799
    # As the oidc-state is used during a redirect from a third-party, we need
800 800
    # it to be lax.
801 801
    assert re.search('Set-Cookie.* oidc-state=.*SameSite=Lax', str(response))
802
    qs = urlparse.parse_qs(urlparse.urlparse(response.location).query)
802
    qs = urllib.parse.parse_qs(urllib.parse.urlparse(response.location).query)
803 803
    state = qs['state']
804 804

  
805 805
    # reset the session to forget the state
......
858 858
    response = app.get('/').maybe_follow()
859 859
    assert oidc_provider.name in response.text
860 860
    response = response.click(oidc_provider.name)
861
    location = urlparse.urlparse(response.location)
861
    location = urllib.parse.urlparse(response.location)
862 862
    query = QueryDict(location.query)
863 863
    state = query['state']
864 864
    nonce = query['nonce']
......
877 877
    response = app.get('/').maybe_follow()
878 878
    assert oidc_provider.name in response.text
879 879
    response = response.click(oidc_provider.name)
880
    location = urlparse.urlparse(response.location)
880
    location = urllib.parse.urlparse(response.location)
881 881
    query = QueryDict(location.query)
882 882
    state = query['state']
883 883
    nonce = query['nonce']
tests/test_idp_cas.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import urllib.parse
18

  
17 19
from django.contrib.auth import get_user_model
18 20
from django.test.client import Client, RequestFactory
19 21
from django.test.utils import override_settings
20 22
from django.utils.encoding import force_text
21
from django.utils.six.moves.urllib import parse as urlparse
22 23

  
23 24
from authentic2.a2_rbac.utils import get_default_ou
24 25
from authentic2.constants import AUTHENTICATION_EVENTS_SESSION_KEY, NONCE_FIELD_NAME
......
132 133
        assert service.authorized_roles.exists() is True
133 134
        response = client.get('/idp/cas/login', {constants.SERVICE_PARAM: self.URL})
134 135
        location = response['Location']
135
        query = urlparse.parse_qs(location.split('?')[1])
136
        query = urllib.parse.parse_qs(location.split('?')[1])
136 137
        next_url, next_url_query = query['next'][0].split('?')
137
        next_url_query = urlparse.parse_qs(next_url_query)
138
        next_url_query = urllib.parse.parse_qs(next_url_query)
138 139
        response = client.get(location)
139 140
        response = client.post(
140 141
            location,
......
152 153
        assert service.authorized_roles.exists() is True
153 154
        response = client.get('/idp/cas/login', {constants.SERVICE_PARAM: self.URL})
154 155
        location = response['Location']
155
        query = urlparse.parse_qs(location.split('?')[1])
156
        query = urllib.parse.parse_qs(location.split('?')[1])
156 157
        next_url, next_url_query = query['next'][0].split('?')
157
        next_url_query = urlparse.parse_qs(next_url_query)
158
        next_url_query = urllib.parse.parse_qs(next_url_query)
158 159
        response = client.get(location)
159 160
        response = client.post(
160 161
            location,
......
163 164
        )
164 165
        response = client.get(response.url)
165 166
        client = Client()
166
        ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
167
        ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
167 168
        response = client.get(
168 169
            '/idp/cas/validate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
169 170
        )
......
174 175
        ticket = Ticket.objects.get()
175 176
        location = response['Location']
176 177
        url = location.split('?')[0]
177
        query = urlparse.parse_qs(location.split('?')[1])
178
        query = urllib.parse.parse_qs(location.split('?')[1])
178 179
        self.assertTrue(url.endswith('/login/'))
179 180
        self.assertIn('nonce', query)
180 181
        self.assertIn('next', query)
181 182
        self.assertEqual(query['nonce'], [ticket.ticket_id])
182 183
        next_url, next_url_query = query['next'][0].split('?')
183
        next_url_query = urlparse.parse_qs(next_url_query)
184
        next_url_query = urllib.parse.parse_qs(next_url_query)
184 185
        self.assertEqual(next_url, '/idp/cas/continue/')
185 186
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
186 187
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
......
214 215
        # Do not the same client for direct calls from the CAS service provider
215 216
        # to prevent use of the user session
216 217
        client = Client()
217
        ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
218
        ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
218 219
        response = client.get(
219 220
            '/idp/cas/validate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
220 221
        )
......
231 232
        ticket = Ticket.objects.get()
232 233
        location = response['Location']
233 234
        url = location.split('?')[0]
234
        query = urlparse.parse_qs(location.split('?')[1])
235
        query = urllib.parse.parse_qs(location.split('?')[1])
235 236
        self.assertTrue(url.endswith('/login/'))
236 237
        self.assertIn('nonce', query)
237 238
        self.assertIn('next', query)
238 239
        self.assertEqual(query['nonce'], [ticket.ticket_id])
239 240
        next_url, next_url_query = query['next'][0].split('?')
240
        next_url_query = urlparse.parse_qs(next_url_query)
241
        next_url_query = urllib.parse.parse_qs(next_url_query)
241 242
        self.assertEqual(next_url, '/idp/cas/continue/')
242 243
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
243 244
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
......
271 272
        # Do not the same client for direct calls from the CAS service provider
272 273
        # to prevent use of the user session
273 274
        client = Client()
274
        ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
275
        ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
275 276
        response = client.get(
276 277
            '/idp/cas/serviceValidate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
277 278
        )
......
292 293
        ticket = Ticket.objects.get()
293 294
        location = response['Location']
294 295
        url = location.split('?')[0]
295
        query = urlparse.parse_qs(location.split('?')[1])
296
        query = urllib.parse.parse_qs(location.split('?')[1])
296 297
        self.assertTrue(url.endswith('/login/'))
297 298
        self.assertIn('nonce', query)
298 299
        self.assertIn('next', query)
299 300
        self.assertEqual(query['nonce'], [ticket.ticket_id])
300 301
        next_url, next_url_query = query['next'][0].split('?')
301
        next_url_query = urlparse.parse_qs(next_url_query)
302
        next_url_query = urllib.parse.parse_qs(next_url_query)
302 303
        self.assertEqual(next_url, '/idp/cas/continue/')
303 304
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
304 305
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
......
332 333
        # Do not the same client for direct calls from the CAS service provider
333 334
        # to prevent use of the user session
334 335
        client = Client()
335
        ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
336
        ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
336 337
        response = client.get(
337 338
            '/idp/cas/serviceValidate',
338 339
            {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL, constants.RENEW_PARAM: ''},
......
351 352
        ticket = Ticket.objects.get()
352 353
        location = response['Location']
353 354
        url = location.split('?')[0]
354
        query = urlparse.parse_qs(location.split('?')[1])
355
        query = urllib.parse.parse_qs(location.split('?')[1])
355 356
        self.assertTrue(url.endswith('/login/'))
356 357
        self.assertIn('nonce', query)
357 358
        self.assertIn('next', query)
358 359
        self.assertEqual(query['nonce'], [ticket.ticket_id])
359 360
        next_url, next_url_query = query['next'][0].split('?')
360
        next_url_query = urlparse.parse_qs(next_url_query)
361
        next_url_query = urllib.parse.parse_qs(next_url_query)
361 362
        self.assertEqual(next_url, '/idp/cas/continue/')
362 363
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
363 364
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
......
391 392
        # Do not the same client for direct calls from the CAS service provider
392 393
        # to prevent use of the user session
393 394
        client = Client()
394
        ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
395
        ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
395 396
        response = client.get(
396 397
            '/idp/cas/proxyValidate', {constants.TICKET_PARAM: ticket_id, constants.SERVICE_PARAM: self.URL}
397 398
        )
......
413 414
        ticket = Ticket.objects.get()
414 415
        location = response['Location']
415 416
        url = location.split('?')[0]
416
        query = urlparse.parse_qs(location.split('?')[1])
417
        query = urllib.parse.parse_qs(location.split('?')[1])
417 418
        self.assertTrue(url.endswith('/login/'))
418 419
        self.assertIn('nonce', query)
419 420
        self.assertIn('next', query)
420 421
        self.assertEqual(query['nonce'], [ticket.ticket_id])
421 422
        next_url, next_url_query = query['next'][0].split('?')
422
        next_url_query = urlparse.parse_qs(next_url_query)
423
        next_url_query = urllib.parse.parse_qs(next_url_query)
423 424
        self.assertEqual(next_url, '/idp/cas/continue/')
424 425
        self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
425 426
        self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL])
......
453 454
        # Do not the same client for direct calls from the CAS service provider
454 455
        # to prevent use of the user session
455 456
        client = Client()
456
        ticket_id = urlparse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
457
        ticket_id = urllib.parse.parse_qs(response.url.split('?')[1])[constants.TICKET_PARAM][0]
457 458
        response = client.get(
458 459
            '/idp/cas/serviceValidate',
459 460
            {
tests/test_idp_oidc.py
18 18
import datetime
19 19
import functools
20 20
import json
21
import urllib.parse
21 22
from importlib import import_module
22 23

  
23 24
import pytest
......
28 29
from django.test.utils import override_settings
29 30
from django.urls import reverse
30 31
from django.utils.encoding import force_text
31
from django.utils.six.moves.urllib import parse as urlparse
32 32
from django.utils.timezone import now
33 33
from jwcrypto.jwk import JWK, JWKSet
34 34
from jwcrypto.jwt import JWT
......
301 301
        assert code.auth_time <= now()
302 302
        assert code.expired >= now()
303 303
    assert response['Location'].startswith(redirect_uri)
304
    location = urlparse.urlparse(response['Location'])
304
    location = urllib.parse.urlparse(response['Location'])
305 305
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
306
        query = urlparse.parse_qs(location.query)
306
        query = urllib.parse.parse_qs(location.query)
307 307
        assert set(query.keys()) == set(['code', 'state'])
308 308
        assert query['code'] == [code.uuid]
309 309
        code = query['code'][0]
......
328 328
        id_token = response.json['id_token']
329 329
    elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
330 330
        assert location.fragment
331
        query = urlparse.parse_qs(location.fragment)
331
        query = urllib.parse.parse_qs(location.fragment)
332 332
        assert OIDCAccessToken.objects.count() == 1
333 333
        access_token = OIDCAccessToken.objects.get()
334 334
        assert set(query.keys()) == set(['access_token', 'token_type', 'expires_in', 'id_token', 'state'])
......
434 434
):
435 435
    # check next_url qs
436 436
    if message:
437
        location = urlparse.urlparse(response.location)
437
        location = urllib.parse.urlparse(response.location)
438 438
        assert location.path == '/continue/'
439 439
        if check_next:
440 440
            location_qs = QueryDict(location.query or '')
441 441
            assert 'next' in location_qs
442 442
            assert location_qs['next'].startswith(redirect_uri)
443
            next_url = urlparse.urlparse(location_qs['next'])
443
            next_url = urllib.parse.urlparse(location_qs['next'])
444 444
            next_url_qs = QueryDict(next_url.fragment if fragment else next_url.query)
445 445
            assert next_url_qs['error'] == error
446 446
            assert next_url_qs['error_description'] == error_description
......
449 449
        assert error_description in continue_response.pyquery('.error').text()
450 450
    elif check_next:
451 451
        assert response.location.startswith(redirect_uri)
452
        location = urlparse.urlparse(response.location)
452
        location = urllib.parse.urlparse(response.location)
453 453
        location_qs = QueryDict(location.fragment if fragment else location.query)
454 454
        assert location_qs['error'] == error
455 455
        assert location_qs['error_description'] == error_description
......
466 466

  
467 467

  
468 468
def assert_authorization_response(response, fragment=False, **kwargs):
469
    location = urlparse.urlparse(response.location)
469
    location = urllib.parse.urlparse(response.location)
470 470
    location_qs = QueryDict(location.fragment if fragment else location.query)
471 471
    assert set(location_qs) == set(kwargs)
472 472
    for key, value in kwargs.items():
......
769 769
        },
770 770
    )
771 771
    response = app.get(authorize_url)
772
    assert urlparse.urlparse(response['Location']).path == reverse('auth_login')
772
    assert urllib.parse.urlparse(response['Location']).path == reverse('auth_login')
773 773

  
774 774
    if oidc_client.authorization_mode != oidc_client.AUTHORIZATION_MODE_NONE:
775 775
        # prompt is none, but consent is required
......
873 873
        code.expired = now() - datetime.timedelta(seconds=120)
874 874
        assert not code.is_valid()
875 875
        code.save()
876
        location = urlparse.urlparse(response['Location'])
877
        query = urlparse.parse_qs(location.query)
876
        location = urllib.parse.urlparse(response['Location'])
877
        query = urllib.parse.parse_qs(location.query)
878 878
        assert set(query.keys()) == set(['code'])
879 879
        assert query['code'] == [code.uuid]
880 880
        code = query['code'][0]
......
1000 1000
    authorize_url = make_url('oidc-authorize', params=params)
1001 1001
    response = app.get(authorize_url)
1002 1002
    response = response.form.submit('accept')
1003
    location = urlparse.urlparse(response['Location'])
1004
    query = urlparse.parse_qs(location.query)
1003
    location = urllib.parse.urlparse(response['Location'])
1004
    query = urllib.parse.parse_qs(location.query)
1005 1005
    code = query['code'][0]
1006 1006
    token_url = make_url('oidc-token')
1007 1007
    response = app.post(
......
1067 1067
        assert OIDCAuthorization.objects.get()
1068 1068
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
1069 1069
        code = OIDCCode.objects.get()
1070
    location = urlparse.urlparse(response['Location'])
1070
    location = urllib.parse.urlparse(response['Location'])
1071 1071
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
1072
        query = urlparse.parse_qs(location.query)
1072
        query = urllib.parse.parse_qs(location.query)
1073 1073
        code = query['code'][0]
1074 1074
        token_url = make_url('oidc-token')
1075 1075
        response = app.post(
......
1083 1083
        )
1084 1084
        id_token = response.json['id_token']
1085 1085
    elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
1086
        query = urlparse.parse_qs(location.fragment)
1086
        query = urllib.parse.parse_qs(location.fragment)
1087 1087
        id_token = query['id_token'][0]
1088 1088

  
1089 1089
    if oidc_client.idtoken_algo in (oidc_client.ALGO_RSA, oidc_client.ALGO_EC):
......
1118 1118
    authorize_url = make_url('oidc-authorize', params=params)
1119 1119
    response = app.get(authorize_url)
1120 1120

  
1121
    location = urlparse.urlparse(response['Location'])
1122
    query = urlparse.parse_qs(location.query)
1121
    location = urllib.parse.urlparse(response['Location'])
1122
    query = urllib.parse.parse_qs(location.query)
1123 1123
    assert query['service'] == ['default client']
1124 1124
    response = response.follow().click('Register')
1125
    location = urlparse.urlparse(response.request.url)
1126
    query = urlparse.parse_qs(location.query)
1125
    location = urllib.parse.urlparse(response.request.url)
1126
    query = urllib.parse.parse_qs(location.query)
1127 1127
    assert query['service'] == ['default client']
1128 1128

  
1129 1129
    response.form.set('email', 'john.doe@example.com')
......
1317 1317
        authorize_url = make_url('oidc-authorize', params=params)
1318 1318

  
1319 1319
        response = app.get(authorize_url)
1320
        location = urlparse.urlparse(response['Location'])
1321
        query = urlparse.parse_qs(location.query)
1320
        location = urllib.parse.urlparse(response['Location'])
1321
        query = urllib.parse.parse_qs(location.query)
1322 1322
        code = query['code'][0]
1323 1323

  
1324 1324
        token_url = make_url('oidc-token')
......
1420 1420
        authorize_url = make_url('oidc-authorize', params=params)
1421 1421

  
1422 1422
        response = app.get(authorize_url)
1423
        location = urlparse.urlparse(response['Location'])
1424
        query = urlparse.parse_qs(location.query)
1423
        location = urllib.parse.urlparse(response['Location'])
1424
        query = urllib.parse.parse_qs(location.query)
1425 1425
        code = query['code'][0]
1426 1426

  
1427 1427
        token_url = make_url('oidc-token')
tests/test_idp_saml2.py
21 21
import datetime
22 22
import hashlib
23 23
import re
24
import urllib.parse
24 25
import xml.etree.ElementTree as ET
25 26

  
26 27
import lasso
......
31 32
from django.template import Context, Template
32 33
from django.urls import reverse
33 34
from django.utils.encoding import force_bytes, force_str, force_text
34
from django.utils.six.moves.urllib import parse as urlparse
35 35
from django.utils.translation import gettext as _
36 36

  
37 37
from authentic2.a2_rbac.models import OrganizationalUnit, Role
......
272 272
                ),
273 273
            )
274 274
        login.buildAuthnRequestMsg()
275
        url_parsed = urlparse.urlparse(login.msgUrl)
275
        url_parsed = urllib.parse.urlparse(login.msgUrl)
276 276
        assert url_parsed.path == reverse('a2-idp-saml-sso'), 'msgUrl should target the sso endpoint'
277 277
        if self.keys:
278 278
            assert 'rsa-sha256' in login.msgUrl
......
288 288
        if response.location:
289 289
            method = lasso.HTTP_METHOD_ARTIFACT_GET
290 290
            query_string = response.location.split('?', 1)[1]
291
            parsed_query_string = urlparse.parse_qs(query_string)
291
            parsed_query_string = urllib.parse.parse_qs(query_string)
292 292
            self.relay_state = parsed_query_string.get('RelayState')
293 293
            login.msgRelayState = force_str(self.relay_state)
294 294
        else:  # lasso.HTTP_METHOD_ARTIFACT_POST, never happens
......
334 334
                REDIRECT_FIELD_NAME: make_url('a2-idp-saml-continue', params={NONCE_FIELD_NAME: request_id}),
335 335
            },
336 336
        )
337
        self.nonce = urlparse.parse_qs(urlparse.urlparse(response['Location']).query)['nonce'][0]
337
        self.nonce = urllib.parse.parse_qs(urllib.parse.urlparse(response['Location']).query)['nonce'][0]
338 338
        url = response['Location']
339 339
        response = self.app.get(url)
340 340
        assert response.status_code == 200
tests/test_import_export_site_cmd.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import builtins as __builtin__
17 18
import json
18 19
import random
19 20

  
......
21 22
from django import VERSION
22 23
from django.core import management
23 24
from django.core.exceptions import ValidationError
24
from django.utils.six.moves import builtins as __builtin__
25 25

  
26 26
from django_rbac.utils import get_role_model
27 27

  
tests/test_ldap.py
18 18
import json
19 19
import os
20 20
import time
21
import urllib.parse
21 22

  
22 23
import ldap
23 24
import mock
......
27 28
from django.core.exceptions import ImproperlyConfigured
28 29
from django.utils import timezone
29 30
from django.utils.encoding import force_bytes, force_text
30
from django.utils.six.moves.urllib import parse as urlparse
31 31
from ldap.dn import escape_dn_chars
32 32
from ldaptools.slapd import Slapd, has_slapd
33 33

  
......
1479 1479
    assert all(
1480 1480
        [
1481 1481
            user.userexternalid_set.first().external_id
1482
            == urlparse.quote(user.username.split('@')[0].encode('utf-8'))
1482
            == urllib.parse.quote(user.username.split('@')[0].encode('utf-8'))
1483 1483
            for user in User.objects.all()
1484 1484
        ]
1485 1485
    )
tests/test_login.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from urllib.parse import quote
18

  
17 19
import pytest
18 20
from django.contrib.auth import get_user_model
19
from django.utils.six.moves.urllib.parse import quote
20 21

  
21 22
from authentic2 import models
22 23

  
tests/test_manager.py
18 18
from __future__ import unicode_literals
19 19

  
20 20
import json
21
from urllib.parse import urlparse
21 22

  
22 23
import pytest
23 24
from django.contrib.auth import get_user_model
......
25 26
from django.core import mail
26 27
from django.urls import reverse
27 28
from django.utils.encoding import force_bytes, force_str
28
from django.utils.six.moves.urllib.parse import urlparse
29 29
from webtest import Upload
30 30

  
31 31
from authentic2.a2_rbac.models import MANAGE_MEMBERS_OP
tests/test_registration.py
16 16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 17

  
18 18
from datetime import date
19
from urllib.parse import urlparse
19 20

  
20 21
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
21 22
from django.urls import reverse
22 23
from django.utils.http import urlquote
23
from django.utils.six.moves.urllib.parse import urlparse
24 24

  
25 25
from authentic2 import models, utils
26 26
from authentic2.apps.journal.models import Event
tests/test_user_manager.py
27 27
from django.contrib.auth import get_user_model
28 28
from django.contrib.contenttypes.models import ContentType
29 29
from django.urls import reverse
30
from django.utils.six import text_type
31 30
from webtest import Upload
32 31

  
33 32
from authentic2.a2_rbac.utils import get_default_ou, get_view_user_perm
......
230 229
    response = login(
231 230
        app,
232 231
        superuser_or_admin,
233
        reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': text_type(simple_user.uuid)}),
232
        reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': str(simple_user.uuid)}),
234 233
    )
235 234
    assert 'Change user email' in response.text
236 235
    # cannot click it's a submit button :/
237 236
    response = app.get(
238
        reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': text_type(simple_user.uuid)})
237
        reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': str(simple_user.uuid)})
239 238
    )
240 239
    assert response.form['new_email'].value == simple_user.email
241 240
    response.form.set('new_email', NEW_EMAIL)
......
270 269
    response = login(
271 270
        app,
272 271
        superuser_or_admin,
273
        reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': text_type(simple_user.uuid)}),
272
        reverse('a2-manager-user-by-uuid-detail', kwargs={'slug': str(simple_user.uuid)}),
274 273
    )
275 274
    assert 'Change user email' in response.text
276 275
    # cannot click it's a submit button :/
277 276
    response = app.get(
278
        reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': text_type(simple_user.uuid)})
277
        reverse('a2-manager-user-by-uuid-change-email', kwargs={'slug': str(simple_user.uuid)})
279 278
    )
280 279
    assert response.form['new_email'].value == simple_user.email
281 280
    assert len(mailoutbox) == 0
tests/test_views.py
16 16
# authentic2
17 17

  
18 18
import datetime
19
from urllib.parse import urlparse
19 20

  
20 21
import pytest
21 22
from django.urls import reverse
22 23
from django.utils.html import escape
23
from django.utils.six.moves.urllib.parse import urlparse
24 24

  
25 25
from authentic2.custom_user.models import DeletedUser, User
26 26

  
tests/utils.py
18 18
import base64
19 19
import re
20 20
import socket
21
import urllib.parse
21 22
from contextlib import closing, contextmanager
22 23

  
23 24
import httmock
......
25 26
from django.shortcuts import resolve_url
26 27
from django.test import TestCase
27 28
from django.urls import reverse
28
from django.utils import six
29 29
from django.utils.encoding import force_text, iri_to_uri
30
from django.utils.six.moves.urllib import parse as urlparse
31 30
from lxml import etree
32 31

  
33 32
from authentic2 import models, utils
......
98 97
    value.
99 98
    """
100 99
    url1 = iri_to_uri(utils.make_url(url1, params=None))
101
    splitted1 = urlparse.urlsplit(url1)
100
    splitted1 = urllib.parse.urlsplit(url1)
102 101
    url2 = iri_to_uri(utils.make_url(url2, params=kwargs))
103
    splitted2 = urlparse.urlsplit(url2)
102
    splitted2 = urllib.parse.urlsplit(url2)
104 103
    for i, (elt1, elt2) in enumerate(zip(splitted1, splitted2)):
105 104
        if i == 3:
106
            elt1 = urlparse.parse_qs(elt1, True)
107
            elt2 = urlparse.parse_qs(elt2, True)
105
            elt1 = urllib.parse.parse_qs(elt1, True)
106
            elt2 = urllib.parse.parse_qs(elt2, True)
108 107
            for k, v in elt1.items():
109 108
                elt1[k] = set(v)
110 109
            for k, v in elt2.items():
......
117 116

  
118 117
def assert_redirects_complex(response, expected_url, **kwargs):
119 118
    assert response.status_code == 302, 'code should be 302'
120
    scheme, netloc, path, query, fragment = urlparse.urlsplit(response.url)
121
    e_scheme, e_netloc, e_path, e_query, e_fragment = urlparse.urlsplit(expected_url)
119
    scheme, netloc, path, query, fragment = urllib.parse.urlsplit(response.url)
120
    e_scheme, e_netloc, e_path, e_query, e_fragment = urllib.parse.urlsplit(expected_url)
122 121
    e_scheme = e_scheme if e_scheme else scheme
123 122
    e_netloc = e_netloc if e_netloc else netloc
124
    expected_url = urlparse.urlunsplit((e_scheme, e_netloc, e_path, e_query, e_fragment))
123
    expected_url = urllib.parse.urlunsplit((e_scheme, e_netloc, e_path, e_query, e_fragment))
125 124
    assert_equals_url(response['Location'], expected_url, **kwargs)
126 125

  
127 126

  
......
132 131
    for xpath, content in constraints:
133 132
        nodes = doc.xpath(xpath, namespaces=namespaces)
134 133
        assert len(nodes) > 0, 'xpath %s not found' % xpath
135
        if isinstance(content, six.string_types):
134
        if isinstance(content, str):
136 135
            for node in nodes:
137 136
                if hasattr(node, 'text'):
138 137
                    assert node.text == content, 'xpath %s does not contain %s but %s' % (
139
-