Skip to content

Commit

Permalink
Merge pull request #164 from open-craft/mtyaka/non-ascii-support
Browse files Browse the repository at this point in the history
Add support for non-ascii fields in settings.
  • Loading branch information
pitbulk authored Sep 23, 2016
2 parents 6f36e59 + 4e73f17 commit aef5af9
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 22 deletions.
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": "technical@example.com"
},
"support": {
"givenName": "Süppört Nämé",
"emailAddress": "support@example.com"
}
},
"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

0 comments on commit aef5af9

Please sign in to comment.