views: ignore XML content in SAML attributes (#43193)

This commit is contained in:
Benjamin Dauvergne 2020-05-21 21:01:49 +02:00
parent 92703b3105
commit c05f4a3129
2 changed files with 20 additions and 6 deletions

View File

@ -209,16 +209,24 @@ class LoginView(ProfileMixin, LogMixin, View):
'error_redirect_after_timeout': error_redirect_after_timeout,
})
def get_attribute_value(self, attribute, attribute_value):
# check attribute_value contains only text
for node in attribute_value.any:
if not isinstance(node, lasso.MiscTextNode) or not node.textChild:
self.log.warning('unsupported attribute %s', attribute.exportToXml())
return None
return ''.join(lasso_decode(node.content) for node in attribute_value.any)
def sso_success(self, request, login):
attributes = {}
attribute_statements = login.assertion.attributeStatement
for ats in attribute_statements:
for at in ats.attribute:
values = attributes.setdefault(at.name, [])
for value in at.attributeValue:
contents = [lasso_decode(any.exportToXml()) for any in value.any]
content = ''.join(contents)
values.append(content)
for attribute_value in at.attributeValue:
content = self.get_attribute_value(at, attribute_value)
if content is not None:
values.append(content)
attributes['issuer'] = login.remoteProviderId
if login.nameIdentifier:
name_id = login.nameIdentifier

View File

@ -32,6 +32,7 @@ from django.utils.six.moves.urllib import parse as urlparse
from django.utils.encoding import force_str
from mellon.utils import create_metadata
from mellon.views import lasso_decode
from httmock import all_requests, HTTMock, response as mock_response
@ -121,6 +122,7 @@ class MockIdp(object):
break
else:
attribute = lasso.Saml2Attribute()
attribute.name = name
attributes.append(attribute)
statement.attribute = attributes
attribute_values = list(attribute.attributeValue)
@ -138,6 +140,7 @@ class MockIdp(object):
atv.any = value_any
add_attribute('email', 'john', '.doe@gmail.com')
add_attribute('wtf', 'john', lasso.MiscTextNode.newWithXmlNode('<a>coucou</a>'))
add_attribute('first_name', '<i>Fr\xe9d\xe9ric</i>')
if not auth_result and msg:
login.response.status.statusMessage = msg
@ -164,8 +167,8 @@ class MockIdp(object):
del self.artifact
del self.artifact_message
login.buildResponseMsg()
assert 'rsa-sha256' in login.msgBody
return '<?xml version="1.0"?>\n' + login.msgBody
assert 'rsa-sha256' in lasso_decode(login.msgBody)
return '<?xml version="1.0"?>\n' + lasso_decode(login.msgBody)
def mock_artifact_resolver(self):
@all_requests
@ -204,6 +207,9 @@ def test_sso(db, app, idp, caplog, sp_settings):
assert 'created new user' in caplog.text
assert 'logged in using SAML' in caplog.text
assert urlparse.urlparse(response['Location']).path == sp_settings.LOGIN_REDIRECT_URL
assert app.session['mellon_session']['first_name'] == ['<i>Fr\xe9d\xe9ric</i>']
assert app.session['mellon_session']['email'] == ['john.doe@gmail.com']
assert app.session['mellon_session']['wtf'] == []
def test_sso_request_denied(db, app, idp, caplog, sp_settings):