Projet

Général

Profil

0001-use-unicode_literals-34008.patch

Benjamin Dauvergne, 04 juillet 2019 13:15

Télécharger (20,8 ko)

Voir les différences:

Subject: [PATCH] use unicode_literals (#34008)

 mellon/adapters.py            | 31 ++++++++++++-----------
 mellon/backends.py            |  2 ++
 mellon/middleware.py          |  2 ++
 mellon/models.py              |  2 ++
 mellon/urls.py                |  2 ++
 mellon/utils.py               |  4 ++-
 mellon/views.py               | 27 +++++++++++---------
 tests/test_default_adapter.py | 10 +++++---
 tests/test_sso_slo.py         | 46 ++++++++++++++++++++++++++++++-----
 tests/test_utils.py           | 17 +++++++++++--
 tests/test_views.py           |  6 +++--
 11 files changed, 108 insertions(+), 41 deletions(-)
mellon/adapters.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
from xml.etree import ElementTree as ET
17 19
import hashlib
20

  
18 21
import logging
19 22
import os
20 23
import threading
......
230 233
        try:
231 234
            doc = ET.fromstring(metadata)
232 235
        except (TypeError, ET.ParseError):
233
            logger.error(u'METADATA of %d-th idp is invalid', i)
236
            logger.error('METADATA of %d-th idp is invalid', i)
234 237
            return None
235 238
        if doc.tag != '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF:
236
            logger.error(u'METADATA of %d-th idp has no EntityDescriptor root tag', i)
239
            logger.error('METADATA of %d-th idp has no EntityDescriptor root tag', i)
237 240
            return None
238 241

  
239 242
        if 'entityID' not in doc.attrib:
240 243
            logger.error(
241
                u'METADATA of %d-th idp has no entityID attribute on its root tag', i)
244
                'METADATA of %d-th idp has no entityID attribute on its root tag', i)
242 245
            return None
243 246
        return doc.attrib['entityID']
244 247

  
......
264 267
            username = force_text(username_template).format(
265 268
                realm=realm, attributes=saml_attributes, idp=idp)[:30]
266 269
        except ValueError:
267
            logger.error(u'invalid username template %r', username_template)
270
            logger.error('invalid username template %r', username_template)
268 271
        except (AttributeError, KeyError, IndexError) as e:
269 272
            logger.error(
270
                u'invalid reference in username template %r: %s', username_template, e)
273
                'invalid reference in username template %r: %s', username_template, e)
271 274
        except Exception:
272
            logger.exception(u'unknown error when formatting username')
275
            logger.exception('unknown error when formatting username')
273 276
        else:
274 277
            return username
275 278

  
......
380 383
                    logger.debug('looking for users by attribute %r and user field %r with value %r: not found',
381 384
                                 saml_attribute, user_field, value)
382 385
                    continue
383
                logger.info(u'looking for user by attribute %r and user field %r with value %r: found %s',
386
                logger.info('looking for user by attribute %r and user field %r with value %r: found %s',
384 387
                            saml_attribute, user_field, value, display_truncated_list(users_found))
385 388
                users.update(users_found)
386 389
        if len(users) == 1:
387 390
            user = list(users)[0]
388
            logger.info(u'looking for user by attributes %r: found user %s', lookup_by_attributes, user)
391
            logger.info('looking for user by attributes %r: found user %s', lookup_by_attributes, user)
389 392
            return user
390 393
        elif len(users) > 1:
391
            logger.warning(u'looking for user by attributes %r: too many users found(%d), failing',
394
            logger.warning('looking for user by attributes %r: too many users found(%d), failing',
392 395
                           lookup_by_attributes, len(users))
393 396
        return None
394 397

  
......
413 416
            try:
414 417
                value = force_text(tpl).format(realm=realm, attributes=saml_attributes, idp=idp)
415 418
            except ValueError:
416
                logger.warning(u'invalid attribute mapping template %r', tpl)
419
                logger.warning('invalid attribute mapping template %r', tpl)
417 420
            except (AttributeError, KeyError, IndexError, ValueError) as e:
418 421
                logger.warning(
419
                    u'invalid reference in attribute mapping template %r: %s', tpl, e)
422
                    'invalid reference in attribute mapping template %r: %s', tpl, e)
420 423
            else:
421 424
                model_field = user._meta.get_field(field)
422 425
                if hasattr(model_field, 'max_length'):
......
425 428
                    old_value = getattr(user, field)
426 429
                    setattr(user, field, value)
427 430
                    attribute_set = True
428
                    logger.info(u'set field %s of user %s to value %r (old value %r)', field, user, value, old_value)
431
                    logger.info('set field %s of user %s to value %r (old value %r)', field, user, value, old_value)
429 432
        if attribute_set:
430 433
            user.save()
431 434

  
......
478 481
                groups.append(group)
479 482
            for group in Group.objects.filter(pk__in=[g.pk for g in groups]).exclude(user=user):
480 483
                logger.info(
481
                    u'adding group %s (%s) to user %s (%s)', group, group.pk, user, user.pk)
484
                    'adding group %s (%s) to user %s (%s)', group, group.pk, user, user.pk)
482 485
                User.groups.through.objects.get_or_create(group=group, user=user)
483 486
            qs = User.groups.through.objects.exclude(
484 487
                group__pk__in=[g.pk for g in groups]).filter(user=user)
485 488
            for rel in qs:
486
                logger.info(u'removing group %s (%s) from user %s (%s)', rel.group, rel.group.pk, rel.user, rel.user.pk)
489
                logger.info('removing group %s (%s) from user %s (%s)', rel.group, rel.group.pk, rel.user, rel.user.pk)
487 490
            qs.delete()
mellon/backends.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
from django.contrib.auth.backends import ModelBackend
17 19

  
18 20
from . import utils
mellon/middleware.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
from django.utils.http import urlencode
17 19
from django.http import HttpResponseRedirect
18 20
from django.core.urlresolvers import reverse
mellon/models.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
from django.db import models
17 19
from django.utils.translation import ugettext_lazy as _
18 20
from django.conf import settings
mellon/urls.py
1
from __future__ import unicode_literals
2

  
1 3
from django.conf.urls import url
2 4
import django
3 5

  
mellon/utils.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
import logging
17 19
import datetime
18 20
import importlib
......
99 101
                try:
100 102
                    server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, idp['METADATA'])
101 103
                except lasso.Error as e:
102
                    logger.error(u'bad metadata in idp %s, %s', idp['ENTITY_ID'], e)
104
                    logger.error('bad metadata in idp %s, %s', idp['ENTITY_ID'], e)
103 105
        cache[root] = server
104 106
        settings._MELLON_SERVER_CACHE = cache
105 107
    return settings._MELLON_SERVER_CACHE.get(root)
mellon/views.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
import logging
17 19
import requests
18 20
import lasso
......
114 116

  
115 117
    def show_message_status_is_not_success(self, profile, prefix):
116 118
        status_codes, idp_message = utils.get_status_codes_and_message(profile)
117
        args = [u'%s: status is not success codes: %r', prefix, status_codes]
119
        args = ['%s: status is not success codes: %r', prefix, status_codes]
118 120
        if idp_message:
119
            args[0] += u' message: %s'
121
            args[0] += ' message: %s'
120 122
            args.append(idp_message)
121 123
        self.log.warning(*args)
122 124

  
......
196 198
            for at in ats.attribute:
197 199
                values = attributes.setdefault(at.name, [])
198 200
                for value in at.attributeValue:
199
                    content = [any.exportToXml() for any in value.any]
200
                    content = ''.join(content)
201
                    values.append(lasso_decode(content))
201
                    contents = [lasso_decode(any.exportToXml()) for any in value.any]
202
                    content = ''.join(contents)
203
                    values.append(content)
202 204
        attributes['issuer'] = login.remoteProviderId
203 205
        if login.nameIdentifier:
204 206
            name_id = login.nameIdentifier
......
295 297
        try:
296 298
            login.initRequest(message, method)
297 299
        except lasso.ProfileInvalidArtifactError:
298
            self.log.warning(u'artifact is malformed %r', artifact)
299
            return HttpResponseBadRequest(u'artifact is malformed %r' % artifact)
300
            self.log.warning('artifact is malformed %r', artifact)
301
            return HttpResponseBadRequest('artifact is malformed %r' % artifact)
300 302
        except lasso.ServerProviderNotFoundError:
301 303
            self.log.warning('no entity id found for artifact %s', artifact)
302 304
            return HttpResponseBadRequest(
......
425 427
                # lasso>2.5.1 introduced a better API
426 428
                if hasattr(authn_request.extensions, 'any'):
427 429
                    authn_request.extensions.any = (
428
                        '<eo:next_url xmlns:eo="https://www.entrouvert.com/">%s</eo:next_url>' % eo_next_url,)
430
                        str('<eo:next_url xmlns:eo="https://www.entrouvert.com/">%s</eo:next_url>' % eo_next_url),
431
                    )
429 432
                else:
430 433
                    authn_request.extensions.setOriginalXmlnode(
431
                        '''<samlp:Extensions
434
                        str('''<samlp:Extensions
432 435
                                 xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
433 436
                                 xmlns:eo="https://www.entrouvert.com/">
434 437
                               <eo:next_url>%s</eo:next_url>
435
                            </samlp:Extensions>''' % eo_next_url
438
                            </samlp:Extensions>''' % eo_next_url)
436 439
                    )
437 440
            self.set_next_url(next_url)
438 441
            self.add_login_hints(idp, authn_request, request=request, next_url=next_url)
......
502 505
            self.log.warning('error validating logout request: %r' % e)
503 506
        issuer = request.session.get('mellon_session', {}).get('issuer')
504 507
        if issuer == logout.remoteProviderId:
505
            self.log.info(u'user logged out by IdP SLO request')
508
            self.log.info('user logged out by IdP SLO request')
506 509
            auth.logout(request)
507 510
        try:
508 511
            logout.buildResponseMsg()
......
539 542
                    # set next_url after local logout, as the session is wiped by auth.logout
540 543
                    if logout:
541 544
                        self.set_next_url(next_url)
542
                    self.log.info(u'user logged out, SLO request sent to IdP')
545
                    self.log.info('user logged out, SLO request sent to IdP')
543 546
        else:
544 547
            self.log.warning('logout refused referer %r is not of the same origin', referer)
545 548
        return HttpResponseRedirect(next_url)
tests/test_default_adapter.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
import datetime
17 19
import re
18 20
import lasso
......
120 122
def test_provision_user_attributes(settings, django_user_model, idp, saml_attributes, caplog):
121 123
    settings.MELLON_IDENTITY_PROVIDERS = [idp]
122 124
    settings.MELLON_ATTRIBUTE_MAPPING = {
123
        'email': u'{attributes[email][0]}',
124
        'first_name': u'{attributes[first_name][0]}',
125
        'last_name': u'{attributes[last_name][0]}',
125
        'email': '{attributes[email][0]}',
126
        'first_name': '{attributes[first_name][0]}',
127
        'last_name': '{attributes[last_name][0]}',
126 128
    }
127 129
    user = SAMLBackend().authenticate(saml_attributes=saml_attributes)
128 130
    assert user.username == 'x' * 30
......
205 207
    assert len(caplog.records) == 4
206 208
    assert 'created new user' in caplog.text
207 209
    assert 'set field first_name' in caplog.text
208
    assert 'to value %r ' % (u'y' * 30) in caplog.text
210
    assert 'to value %r ' % ('y' * 30) in caplog.text
209 211
    assert 'set field last_name' in caplog.text
210 212
    assert 'set field email' in caplog.text
211 213

  
tests/test_sso_slo.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
18
import datetime
16 19
import re
17 20
import base64
18 21
import zlib
......
25 28
from django.core.urlresolvers import reverse
26 29
from django.utils import six
27 30
from django.utils.six.moves.urllib import parse as urlparse
31
from django.utils.encoding import force_str
28 32

  
29 33
from mellon.utils import create_metadata
30 34

  
......
100 104
            pass
101 105
        else:
102 106
            login.buildAssertion(lasso.SAML_AUTHENTICATION_METHOD_PASSWORD,
103
                                 "FIXME",
104
                                 "FIXME",
105
                                 "FIXME",
106
                                 "FIXME")
107
                                 datetime.datetime.now().isoformat(),
108
                                 None,
109
                                 datetime.datetime.now().isoformat(),
110
                                 datetime.datetime.now().isoformat())
111

  
112
            def add_attribute(name, *values, **kwargs):
113
                fmt = kwargs.get('fmt', lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC)
114
                statements = login.response.assertion[0].attributeStatement or [lasso.Saml2AttributeStatement()]
115
                statement = statements[0]
116
                login.response.assertion[0].attributeStatement = statements
117
                attributes = list(statement.attribute)
118
                for attribute in attributes:
119
                    if attribute.name == name and attribute.nameFormat == fmt:
120
                        break
121
                else:
122
                    attribute = lasso.Saml2Attribute()
123
                    attributes.append(attribute)
124
                    statement.attribute = attributes
125
                attribute_values = list(attribute.attributeValue)
126
                atv = lasso.Saml2AttributeValue()
127
                attribute_values.append(atv)
128
                attribute.attributeValue = attribute_values
129
                value_any = []
130
                for value in values:
131
                    if isinstance(value, lasso.Node):
132
                        value_any.append(value)
133
                    else:
134
                        mtn = lasso.MiscTextNode.newWithString(force_str(value))
135
                        mtn.textChild = True
136
                        value_any.append(mtn)
137
                atv.any = value_any
138
            add_attribute('email', 'john', '.doe@gmail.com')
139
            add_attribute('wtf', 'john', lasso.MiscTextNode.newWithXmlNode('<a>coucou</a>'))
140

  
107 141
        if not auth_result and msg:
108 142
            login.response.status.statusMessage = msg
109 143
        if login.protocolProfile == lasso.LOGIN_PROTOCOL_PROFILE_BRWS_ART:
......
174 208
    url, body, relay_state = idp.process_authn_request_redirect(
175 209
        response['Location'],
176 210
        auth_result=False,
177
        msg=u'User is not allowed to login')
211
        msg='User is not allowed to login')
178 212
    assert not relay_state
179 213
    assert url.endswith(reverse('mellon_login'))
180 214
    response = app.post(reverse('mellon_login'), params={'SAMLResponse': body, 'RelayState': relay_state})
......
195 229
    url, body, relay_state = idp.process_authn_request_redirect(
196 230
        response['Location'],
197 231
        auth_result=False,
198
        msg=u'User is not allowed to login')
232
        msg='User is not allowed to login')
199 233
    assert not relay_state
200 234
    assert body is None
201 235
    assert reverse('mellon_login') in url
tests/test_utils.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
import datetime
17 19

  
18 20
import mock
19 21
import lasso
20 22

  
21 23
from mellon.utils import create_metadata, iso8601_to_datetime, flatten_datetime
24
from mellon.views import check_next_url
22 25
from xml_utils import assert_xml_constraints
23 26

  
24 27

  
......
84 87
    d = {
85 88
        'x': datetime.datetime(2010, 10, 10, 10, 10, 34),
86 89
        'y': 1,
87
        'z': 'uu',
90
        'z': 'u',
88 91
    }
89 92
    assert set(flatten_datetime(d).keys()) == set(['x', 'y', 'z'])
90 93
    assert flatten_datetime(d)['x'] == '2010-10-10T10:10:34'
91 94
    assert flatten_datetime(d)['y'] == 1
92
    assert flatten_datetime(d)['z'] == 'uu'
95
    assert flatten_datetime(d)['z'] == 'u'
96

  
97

  
98
def test_check_next_url(rf):
99
    assert not check_next_url(rf.get('/'), u'')
100
    assert not check_next_url(rf.get('/'), None)
101
    assert not check_next_url(rf.get('/'), u'\x00')
102
    assert not check_next_url(rf.get('/'), u'\u010e')
103
    assert not check_next_url(rf.get('/'), u'https://example.invalid/')
104
    # default hostname is testserver
105
    assert check_next_url(rf.get('/'), u'http://testserver/ok/')
tests/test_views.py
13 13
# You should have received a copy of the GNU Affero General Public License
14 14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 15

  
16
from __future__ import unicode_literals
17

  
16 18
import pytest
17 19
import mock
18 20
import lasso
......
208 210
def test_sp_initiated_login_requested_authn_context(private_settings, client):
209 211
    private_settings.MELLON_IDENTITY_PROVIDERS = [{
210 212
        'METADATA': open('tests/metadata.xml').read(),
211
        'AUTHN_CLASSREF': [u'urn:be:fedict:iam:fas:citizen:eid',
212
                           u'urn:be:fedict:iam:fas:citizen:token'],
213
        'AUTHN_CLASSREF': ['urn:be:fedict:iam:fas:citizen:eid',
214
                           'urn:be:fedict:iam:fas:citizen:token'],
213 215
    }]
214 216
    response = client.get('/login/')
215 217
    assert response.status_code == 302
216
-