0001-use-unicode_literals-34008.patch
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 |
... | ... | |
229 | 232 |
try: |
230 | 233 |
doc = ET.fromstring(metadata) |
231 | 234 |
except (TypeError, ET.ParseError): |
232 |
logger.error(u'METADATA of %d-th idp is invalid', i)
|
|
235 |
logger.error('METADATA of %d-th idp is invalid', i) |
|
233 | 236 |
return None |
234 | 237 |
if doc.tag != '{%s}EntityDescriptor' % lasso.SAML2_METADATA_HREF: |
235 |
logger.error(u'METADATA of %d-th idp has no EntityDescriptor root tag', i)
|
|
238 |
logger.error('METADATA of %d-th idp has no EntityDescriptor root tag', i) |
|
236 | 239 |
return None |
237 | 240 | |
238 | 241 |
if 'entityID' not in doc.attrib: |
239 | 242 |
logger.error( |
240 |
u'METADATA of %d-th idp has no entityID attribute on its root tag', i)
|
|
243 |
'METADATA of %d-th idp has no entityID attribute on its root tag', i) |
|
241 | 244 |
return None |
242 | 245 |
return doc.attrib['entityID'] |
243 | 246 | |
... | ... | |
263 | 266 |
username = force_text(username_template).format( |
264 | 267 |
realm=realm, attributes=saml_attributes, idp=idp)[:30] |
265 | 268 |
except ValueError: |
266 |
logger.error(u'invalid username template %r', username_template)
|
|
269 |
logger.error('invalid username template %r', username_template) |
|
267 | 270 |
except (AttributeError, KeyError, IndexError) as e: |
268 | 271 |
logger.error( |
269 |
u'invalid reference in username template %r: %s', username_template, e)
|
|
272 |
'invalid reference in username template %r: %s', username_template, e) |
|
270 | 273 |
except Exception: |
271 |
logger.exception(u'unknown error when formatting username')
|
|
274 |
logger.exception('unknown error when formatting username') |
|
272 | 275 |
else: |
273 | 276 |
return username |
274 | 277 | |
... | ... | |
379 | 382 |
logger.debug('looking for users by attribute %r and user field %r with value %r: not found', |
380 | 383 |
saml_attribute, user_field, value) |
381 | 384 |
continue |
382 |
logger.info(u'looking for user by attribute %r and user field %r with value %r: found %s',
|
|
385 |
logger.info('looking for user by attribute %r and user field %r with value %r: found %s', |
|
383 | 386 |
saml_attribute, user_field, value, display_truncated_list(users_found)) |
384 | 387 |
users.update(users_found) |
385 | 388 |
if len(users) == 1: |
386 | 389 |
user = list(users)[0] |
387 |
logger.info(u'looking for user by attributes %r: found user %s', lookup_by_attributes, user)
|
|
390 |
logger.info('looking for user by attributes %r: found user %s', lookup_by_attributes, user) |
|
388 | 391 |
return user |
389 | 392 |
elif len(users) > 1: |
390 |
logger.warning(u'looking for user by attributes %r: too many users found(%d), failing',
|
|
393 |
logger.warning('looking for user by attributes %r: too many users found(%d), failing', |
|
391 | 394 |
lookup_by_attributes, len(users)) |
392 | 395 |
return None |
393 | 396 | |
... | ... | |
412 | 415 |
try: |
413 | 416 |
value = force_text(tpl).format(realm=realm, attributes=saml_attributes, idp=idp) |
414 | 417 |
except ValueError: |
415 |
logger.warning(u'invalid attribute mapping template %r', tpl)
|
|
418 |
logger.warning('invalid attribute mapping template %r', tpl) |
|
416 | 419 |
except (AttributeError, KeyError, IndexError, ValueError) as e: |
417 | 420 |
logger.warning( |
418 |
u'invalid reference in attribute mapping template %r: %s', tpl, e)
|
|
421 |
'invalid reference in attribute mapping template %r: %s', tpl, e) |
|
419 | 422 |
else: |
420 | 423 |
model_field = user._meta.get_field(field) |
421 | 424 |
if hasattr(model_field, 'max_length'): |
... | ... | |
424 | 427 |
old_value = getattr(user, field) |
425 | 428 |
setattr(user, field, value) |
426 | 429 |
attribute_set = True |
427 |
logger.info(u'set field %s of user %s to value %r (old value %r)', field, user, value, old_value)
|
|
430 |
logger.info('set field %s of user %s to value %r (old value %r)', field, user, value, old_value) |
|
428 | 431 |
if attribute_set: |
429 | 432 |
user.save() |
430 | 433 | |
... | ... | |
477 | 480 |
groups.append(group) |
478 | 481 |
for group in Group.objects.filter(pk__in=[g.pk for g in groups]).exclude(user=user): |
479 | 482 |
logger.info( |
480 |
u'adding group %s (%s) to user %s (%s)', group, group.pk, user, user.pk)
|
|
483 |
'adding group %s (%s) to user %s (%s)', group, group.pk, user, user.pk) |
|
481 | 484 |
User.groups.through.objects.get_or_create(group=group, user=user) |
482 | 485 |
qs = User.groups.through.objects.exclude( |
483 | 486 |
group__pk__in=[g.pk for g in groups]).filter(user=user) |
484 | 487 |
for rel in qs: |
485 |
logger.info(u'removing group %s (%s) from user %s (%s)', rel.group, rel.group.pk, rel.user, rel.user.pk)
|
|
488 |
logger.info('removing group %s (%s) from user %s (%s)', rel.group, rel.group.pk, rel.user, rel.user.pk) |
|
486 | 489 |
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 | |
... | ... | |
197 | 199 |
values = attributes.setdefault(at.name, []) |
198 | 200 |
for value in at.attributeValue: |
199 | 201 |
content = [any.exportToXml() for any in value.any] |
200 |
content = ''.join(content)
|
|
201 |
values.append(lasso_decode(content))
|
|
202 |
content = ''.join(lasso_decode(content.decode))
|
|
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 | ||
16 | 18 |
import re |
17 | 19 |
import base64 |
18 | 20 |
import zlib |
... | ... | |
174 | 176 |
url, body, relay_state = idp.process_authn_request_redirect( |
175 | 177 |
response['Location'], |
176 | 178 |
auth_result=False, |
177 |
msg=u'User is not allowed to login')
|
|
179 |
msg='User is not allowed to login') |
|
178 | 180 |
assert not relay_state |
179 | 181 |
assert url.endswith(reverse('mellon_login')) |
180 | 182 |
response = app.post(reverse('mellon_login'), params={'SAMLResponse': body, 'RelayState': relay_state}) |
... | ... | |
195 | 197 |
url, body, relay_state = idp.process_authn_request_redirect( |
196 | 198 |
response['Location'], |
197 | 199 |
auth_result=False, |
198 |
msg=u'User is not allowed to login')
|
|
200 |
msg='User is not allowed to login') |
|
199 | 201 |
assert not relay_state |
200 | 202 |
assert body is None |
201 | 203 |
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 |
... | ... | |
84 | 86 |
d = { |
85 | 87 |
'x': datetime.datetime(2010, 10, 10, 10, 10, 34), |
86 | 88 |
'y': 1, |
87 |
'z': 'uu',
|
|
89 |
'z': 'u', |
|
88 | 90 |
} |
89 | 91 |
assert set(flatten_datetime(d).keys()) == set(['x', 'y', 'z']) |
90 | 92 |
assert flatten_datetime(d)['x'] == '2010-10-10T10:10:34' |
91 | 93 |
assert flatten_datetime(d)['y'] == 1 |
92 |
assert flatten_datetime(d)['z'] == 'uu' |
|
94 |
assert flatten_datetime(d)['z'] == 'u' |
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 |
- |