Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for non-ascii fields in settings. #164

Merged
merged 1 commit into from
Sep 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/onelogin/saml2/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def builder(sp, authnsign=False, wsign=False, valid_until=None, cache_duration=N
contacts_info.append(contact)
str_contacts = '\n'.join(contacts_info) + '\n'

metadata = """<?xml version="1.0"?>
metadata = u"""<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
%(valid)s
%(cache)s
Expand Down Expand Up @@ -241,7 +241,7 @@ def add_x509_key_descriptors(metadata, cert=None):
if cert is None or cert == '':
return metadata
try:
xml = parseString(metadata)
xml = parseString(metadata.encode('utf-8'))
except Exception as e:
raise Exception('Error parsing metadata. ' + e.message)

Expand Down
32 changes: 16 additions & 16 deletions src/onelogin/saml2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def decode_base64_and_inflate(value):
:rtype: string
"""

return zlib.decompress(base64.b64decode(value), -15)
return zlib.decompress(base64.b64decode(value), -15).decode('utf-8')

@staticmethod
def deflate_and_base64_encode(value):
Expand All @@ -86,7 +86,7 @@ def deflate_and_base64_encode(value):
:returns: The deflated and encoded string
:rtype: string
"""
return base64.b64encode(zlib.compress(value)[2:-4])
return base64.b64encode(zlib.compress(value.encode('utf-8'))[2:-4])

@staticmethod
def validate_xml(xml, schema, debug=False):
Expand All @@ -107,11 +107,11 @@ def validate_xml(xml, schema, debug=False):
if isinstance(xml, Document):
xml = xml.toxml()
elif isinstance(xml, etree._Element):
xml = tostring(xml)
xml = tostring(xml, encoding='unicode')

# Switch to lxml for schema validation
try:
dom = fromstring(str(xml))
dom = fromstring(xml.encode('utf-8'))
except Exception:
return 'unloaded_xml'

Expand All @@ -130,7 +130,7 @@ def validate_xml(xml, schema, debug=False):

return 'invalid_xml'

return parseString(etree.tostring(dom))
return parseString(etree.tostring(dom, encoding='unicode').encode('utf-8'))

@staticmethod
def format_cert(cert, heads=True):
Expand Down Expand Up @@ -655,7 +655,7 @@ def generate_name_id(value, sp_nq, sp_format, cert=None, debug=False, nq=None):

edata = enc_ctx.encryptXml(enc_data, elem[0])

newdoc = parseString(etree.tostring(edata))
newdoc = parseString(etree.tostring(edata, encoding='unicode').encode('utf-8'))

if newdoc.hasChildNodes():
child = newdoc.firstChild
Expand Down Expand Up @@ -791,7 +791,7 @@ def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constant
elem = xml
elif isinstance(xml, Document):
xml = xml.toxml()
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
elif isinstance(xml, Element):
xml.setAttributeNS(
unicode(OneLogin_Saml2_Constants.NS_SAMLP),
Expand All @@ -804,9 +804,9 @@ def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constant
unicode(OneLogin_Saml2_Constants.NS_SAML)
)
xml = xml.toxml()
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
elif isinstance(xml, basestring):
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
else:
raise Exception('Error parsing xml string')

Expand Down Expand Up @@ -849,7 +849,7 @@ def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constant
dsig_ctx.signKey = sign_key
dsig_ctx.sign(signature)

newdoc = parseString(etree.tostring(elem))
newdoc = parseString(etree.tostring(elem, encoding='unicode').encode('utf-8'))

signature_nodes = newdoc.getElementsByTagName("Signature")

Expand Down Expand Up @@ -895,7 +895,7 @@ def validate_sign(xml, cert=None, fingerprint=None, fingerprintalg='sha1', valid
elem = xml
elif isinstance(xml, Document):
xml = xml.toxml()
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
elif isinstance(xml, Element):
xml.setAttributeNS(
unicode(OneLogin_Saml2_Constants.NS_SAMLP),
Expand All @@ -908,9 +908,9 @@ def validate_sign(xml, cert=None, fingerprint=None, fingerprintalg='sha1', valid
unicode(OneLogin_Saml2_Constants.NS_SAML)
)
xml = xml.toxml()
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
elif isinstance(xml, basestring):
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
else:
raise Exception('Error parsing xml string')

Expand Down Expand Up @@ -963,17 +963,17 @@ def validate_metadata_sign(xml, cert=None, fingerprint=None, fingerprintalg='sha
elem = xml
elif isinstance(xml, Document):
xml = xml.toxml()
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
elif isinstance(xml, Element):
xml.setAttributeNS(
unicode(OneLogin_Saml2_Constants.NS_MD),
'xmlns:md',
unicode(OneLogin_Saml2_Constants.NS_MD)
)
xml = xml.toxml()
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
elif isinstance(xml, basestring):
elem = fromstring(str(xml))
elem = fromstring(xml.encode('utf-8'))
else:
raise Exception('Error parsing xml string')

Expand Down
47 changes: 47 additions & 0 deletions tests/settings/settings6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"strict": false,
"debug": false,
"custom_base_path": "../../../tests/data/customPath/",
"sp": {
"entityId": "http://stuff.com/endpoints/metadata.php",
"assertionConsumerService": {
"url": "http://stuff.com/endpoints/endpoints/acs.php"
},
"singleLogoutService": {
"url": "http://stuff.com/endpoints/endpoints/sls.php"
},
"NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
},
"idp": {
"entityId": "http://idp.example.com/",
"singleSignOnService": {
"url": "http://idp.example.com/SSOService.php"
},
"singleLogoutService": {
"url": "http://idp.example.com/SingleLogoutService.php"
},
"x509cert": "MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMCTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYDVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xiZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2ZlaWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2QarQ4/67OZfHd7R+POBXhophSMv1ZOo"
},
"security": {
"authnRequestsSigned": false,
"wantAssertionsSigned": false,
"signMetadata": false
},
"contactPerson": {
"technical": {
"givenName": "Téçhnïçäl Nämé",
"emailAddress": "[email protected]"
},
"support": {
"givenName": "Süppört Nämé",
"emailAddress": "[email protected]"
}
},
"organization": {
"en-US": {
"name": "sp_test",
"displayname": "Sérvïçé prövïdér",
"url": "http://sp.example.com"
}
}
}
18 changes: 16 additions & 2 deletions tests/src/OneLogin/saml2_tests/auth_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class OneLogin_Saml2_Auth_Test(unittest.TestCase):
data_path = join(dirname(dirname(dirname(dirname(__file__)))), 'data')
settings_path = join(dirname(dirname(dirname(dirname(__file__)))), 'settings')

def loadSettingsJSON(self):
filename = join(self.settings_path, 'settings1.json')
def loadSettingsJSON(self, name='settings1.json'):
filename = join(self.settings_path, name)
if exists(filename):
stream = open(filename, 'r')
settings = json.load(stream)
Expand Down Expand Up @@ -566,6 +566,20 @@ def testLogin(self):
hostname = OneLogin_Saml2_Utils.get_self_host(request_data)
self.assertIn(u'http://%s/index.html' % hostname, parsed_query['RelayState'])

def testLoginWithUnicodeSettings(self):
"""
Tests the login method of the OneLogin_Saml2_Auth class
Case Login with unicode settings. An AuthnRequest is built an redirect executed
"""
settings_info = self.loadSettingsJSON('settings6.json')
request_data = self.get_request()
auth = OneLogin_Saml2_Auth(request_data, old_settings=settings_info)

target_url = auth.login()
parsed_query = parse_qs(urlparse(target_url)[4])
hostname = OneLogin_Saml2_Utils.get_self_host(request_data)
self.assertIn(u'http://%s/index.html' % hostname, parsed_query['RelayState'])

def testLoginWithRelayState(self):
"""
Tests the login method of the OneLogin_Saml2_Auth class
Expand Down
18 changes: 16 additions & 2 deletions tests/src/OneLogin/saml2_tests/settings_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class OneLogin_Saml2_Settings_Test(unittest.TestCase):
data_path = join(dirname(dirname(dirname(dirname(__file__)))), 'data')
settings_path = join(dirname(dirname(dirname(dirname(__file__)))), 'settings')

def loadSettingsJSON(self):
filename = join(self.settings_path, 'settings1.json')
def loadSettingsJSON(self, name='settings1.json'):
filename = join(self.settings_path, name)
if exists(filename):
stream = open(filename, 'r')
settings = json.load(stream)
Expand Down Expand Up @@ -397,6 +397,20 @@ def testGetSPMetadata(self):
self.assertIn('<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://stuff.com/endpoints/endpoints/sls.php"/>', metadata)
self.assertIn('<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>', metadata)

def testGetUnicodeSPMetadata(self):
"""
Tests the getSPMetadata method of the OneLogin_Saml2_Settings
Case unicode metadata
"""
settings = OneLogin_Saml2_Settings(self.loadSettingsJSON('settings6.json'))
metadata = settings.get_sp_metadata()

self.assertIn('<md:SPSSODescriptor', metadata)
self.assertIn('<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://stuff.com/endpoints/endpoints/acs.php" index="1"/>', metadata)
self.assertIn(u'<md:OrganizationDisplayName xml:lang="en-US">Sérvïçé prövïdér</md:OrganizationDisplayName>', metadata)
self.assertIn(u'<md:GivenName>Téçhnïçäl Nämé</md:GivenName>', metadata)
self.assertIn(u'<md:GivenName>Süppört Nämé</md:GivenName>', metadata)

def testGetSPMetadataSigned(self):
"""
Tests the getSPMetadata method of the OneLogin_Saml2_Settings
Expand Down
12 changes: 12 additions & 0 deletions tests/src/OneLogin/saml2_tests/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ def file_contents(self, filename):
f.close()
return content

def testDeflateBase64Roundtrip(self):
"""
Tests deflate_and_base64_encode and decode_base64_and_inflate methods of OneLogin_Saml2_Utils
"""
body = 'Some random string.'
encoded = OneLogin_Saml2_Utils.deflate_and_base64_encode(body)
self.assertEqual(OneLogin_Saml2_Utils.decode_base64_and_inflate(encoded), body)

unicode_body = u'Sömé rändöm nön-äsçïï strïng.'
unicode_encoded = OneLogin_Saml2_Utils.deflate_and_base64_encode(unicode_body)
self.assertEqual(OneLogin_Saml2_Utils.decode_base64_and_inflate(unicode_encoded), unicode_body)

def testValidateXML(self):
"""
Tests the validate_xml method of the OneLogin_Saml2_Utils
Expand Down