Skip to content

Commit a5423c3

Browse files
committed
Fix #181 Add DigestMethod support. (Add sign_algorithm and digest_algorithm parameters to sign_metadata and add_sign
1 parent 1621567 commit a5423c3

9 files changed

Lines changed: 91 additions & 9 deletions

File tree

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,14 @@ In addition to the required settings data (idp, sp), extra settings can be defin
399399
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
400400
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
401401
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
402-
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
402+
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
403+
404+
// Algorithm that the toolkit will use on digest process. Options:
405+
// 'http://www.w3.org/2000/09/xmldsig#sha1'
406+
// 'http://www.w3.org/2001/04/xmlenc#sha256'
407+
// 'http://www.w3.org/2001/04/xmldsig-more#sha384'
408+
// 'http://www.w3.org/2001/04/xmlenc#sha512'
409+
'digestAlgorithm' => 'http://www.w3.org/2000/09/xmldsig#sha1
403410
},
404411
405412
// Contact information template, it is recommended to supply

demo-bottle/saml/advanced_settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"wantNameId" : true,
1111
"wantNameIdEncrypted": false,
1212
"wantAssertionsEncrypted": false,
13-
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
13+
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
14+
"digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1"
1415
},
1516
"contactPerson": {
1617
"technical": {

demo-django/saml/advanced_settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"wantNameId" : true,
1111
"wantNameIdEncrypted": false,
1212
"wantAssertionsEncrypted": false,
13-
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
13+
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
14+
"digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1"
1415
},
1516
"contactPerson": {
1617
"technical": {

demo-flask/saml/advanced_settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"wantNameId" : true,
1111
"wantNameIdEncrypted": false,
1212
"wantAssertionsEncrypted": false,
13-
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
13+
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
14+
"digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1"
1415
},
1516
"contactPerson": {
1617
"technical": {

src/onelogin/saml2/metadata.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def builder(sp, authnsign=False, wsign=False, valid_until=None, cache_duration=N
202202
return metadata
203203

204204
@staticmethod
205-
def sign_metadata(metadata, key, cert, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
205+
def sign_metadata(metadata, key, cert, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1, digest_algorithm=OneLogin_Saml2_Constants.SHA1):
206206
"""
207207
Signs the metadata with the key/cert provided
208208
@@ -218,10 +218,13 @@ def sign_metadata(metadata, key, cert, sign_algorithm=OneLogin_Saml2_Constants.R
218218
:param sign_algorithm: Signature algorithm method
219219
:type sign_algorithm: string
220220
221+
:param digest_algorithm: Digest algorithm method
222+
:type digest_algorithm: string
223+
221224
:returns: Signed Metadata
222225
:rtype: string
223226
"""
224-
return OneLogin_Saml2_Utils.add_sign(metadata, key, cert, False, sign_algorithm)
227+
return OneLogin_Saml2_Utils.add_sign(metadata, key, cert, False, sign_algorithm, digest_algorithm)
225228

226229
@staticmethod
227230
def add_x509_key_descriptors(metadata, cert=None):

src/onelogin/saml2/settings.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@ def __add_default_values(self):
283283
# Signature Algorithm
284284
self.__security.setdefault('signatureAlgorithm', OneLogin_Saml2_Constants.RSA_SHA1)
285285

286+
# Digest Algorithm
287+
self.__security.setdefault('digestAlgorithm', OneLogin_Saml2_Constants.SHA1)
288+
286289
# AttributeStatement required by default
287290
self.__security.setdefault('wantAttributeStatement', True)
288291

@@ -639,7 +642,10 @@ def get_sp_metadata(self):
639642
cert_metadata_file
640643
)
641644

642-
metadata = OneLogin_Saml2_Metadata.sign_metadata(metadata, key_metadata, cert_metadata)
645+
signature_algorithm = self.__security['signatureAlgorithm']
646+
digest_algorithm = self.__security['digestAlgorithm']
647+
648+
metadata = OneLogin_Saml2_Metadata.sign_metadata(metadata, key_metadata, cert_metadata, signature_algorithm, digest_algorithm)
643649

644650
return metadata
645651

src/onelogin/saml2/utils.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ def write_temp_file(content):
797797
return f_temp
798798

799799
@staticmethod
800-
def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
800+
def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1, digest_algorithm=OneLogin_Saml2_Constants.SHA1):
801801
"""
802802
Adds signature key and senders certificate to an element (Message or
803803
Assertion).
@@ -816,6 +816,12 @@ def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constant
816816
817817
:param sign_algorithm: Signature algorithm method
818818
:type sign_algorithm: string
819+
820+
:param digest_algorithm: Digest algorithm method
821+
:type digest_algorithm: string
822+
823+
:returns: Signed XML
824+
:rtype: string
819825
"""
820826
if xml is None or xml == '':
821827
raise Exception('Empty string supplied as input')
@@ -866,7 +872,15 @@ def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constant
866872
else:
867873
elem[0].insert(0, signature)
868874

869-
ref = signature.addReference(xmlsec.TransformSha1)
875+
digest_algorithm_transform_map = {
876+
OneLogin_Saml2_Constants.SHA1: xmlsec.TransformSha1,
877+
OneLogin_Saml2_Constants.SHA256: xmlsec.TransformSha256,
878+
OneLogin_Saml2_Constants.SHA384: xmlsec.TransformSha384,
879+
OneLogin_Saml2_Constants.SHA512: xmlsec.TransformSha512
880+
}
881+
digest_algorithm_transform = digest_algorithm_transform_map.get(digest_algorithm, xmlsec.TransformSha1)
882+
883+
ref = signature.addReference(digest_algorithm_transform)
870884
ref.addTransform(xmlsec.TransformEnveloped)
871885
ref.addTransform(xmlsec.TransformExclC14N)
872886

tests/src/OneLogin/saml2_tests/metadata_test.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from onelogin.saml2.metadata import OneLogin_Saml2_Metadata
1616
from onelogin.saml2.settings import OneLogin_Saml2_Settings
17+
from onelogin.saml2.constants import OneLogin_Saml2_Constants
1718

1819

1920
class OneLogin_Saml2_Metadata_Test(unittest.TestCase):
@@ -222,12 +223,32 @@ def testSignMetadata(self):
222223

223224
self.assertIn('<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>', signed_metadata)
224225
self.assertIn('<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>', signed_metadata)
226+
self.assertIn('<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>', signed_metadata)
225227
self.assertIn('<ds:Reference', signed_metadata)
226228
self.assertIn('<ds:KeyInfo><ds:X509Data>\n<ds:X509Certificate>', signed_metadata)
227229

228230
with self.assertRaisesRegexp(Exception, 'Empty string supplied as input'):
229231
OneLogin_Saml2_Metadata.sign_metadata('', key, cert)
230232

233+
signed_metadata_2 = OneLogin_Saml2_Metadata.sign_metadata(metadata, key, cert, OneLogin_Saml2_Constants.RSA_SHA256, OneLogin_Saml2_Constants.SHA384)
234+
self.assertIn('<md:SPSSODescriptor', signed_metadata_2)
235+
self.assertIn('entityID="http://stuff.com/endpoints/metadata.php"', signed_metadata_2)
236+
self.assertIn('AuthnRequestsSigned="false"', signed_metadata_2)
237+
self.assertIn('WantAssertionsSigned="false"', signed_metadata_2)
238+
239+
self.assertIn('<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"', signed_metadata_2)
240+
self.assertIn('Location="http://stuff.com/endpoints/endpoints/acs.php"', signed_metadata_2)
241+
self.assertIn('<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"', signed_metadata_2)
242+
self.assertIn(' Location="http://stuff.com/endpoints/endpoints/sls.php"/>', signed_metadata_2)
243+
244+
self.assertIn('<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>', signed_metadata_2)
245+
246+
self.assertIn('<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>', signed_metadata_2)
247+
self.assertIn('<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha384"/>', signed_metadata_2)
248+
self.assertIn('<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>', signed_metadata_2)
249+
self.assertIn('<ds:Reference', signed_metadata_2)
250+
self.assertIn('<ds:KeyInfo><ds:X509Data>\n<ds:X509Certificate>', signed_metadata_2)
251+
231252
def testAddX509KeyDescriptors(self):
232253
"""
233254
Tests the addX509KeyDescriptors method of the OneLogin_Saml2_Metadata

tests/src/OneLogin/saml2_tests/utils_test.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,34 @@ def testAddSign(self):
810810
with self.assertRaisesRegexp(Exception, 'Error parsing xml string'):
811811
OneLogin_Saml2_Utils.add_sign(1, key, cert)
812812

813+
def testAddSignCheckAlg(self):
814+
"""
815+
Tests the add_sign method of the OneLogin_Saml2_Utils
816+
Case: Review signature & digest algorithm
817+
"""
818+
settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
819+
key = settings.get_sp_key()
820+
cert = settings.get_sp_cert()
821+
822+
xml_authn = b64decode(self.file_contents(join(self.data_path, 'requests', 'authn_request.xml.base64')))
823+
xml_authn_signed = OneLogin_Saml2_Utils.add_sign(xml_authn, key, cert)
824+
self.assertIn('<ds:SignatureValue>', xml_authn_signed)
825+
self.assertIn('<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>', xml_authn_signed)
826+
self.assertIn('<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>', xml_authn_signed)
827+
self.assertIn('<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>', xml_authn_signed)
828+
829+
xml_authn_signed_2 = OneLogin_Saml2_Utils.add_sign(xml_authn, key, cert, False, OneLogin_Saml2_Constants.RSA_SHA256, OneLogin_Saml2_Constants.SHA384)
830+
self.assertIn('<ds:SignatureValue>', xml_authn_signed_2)
831+
self.assertIn('<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>', xml_authn_signed_2)
832+
self.assertIn('<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#sha384"/>', xml_authn_signed_2)
833+
self.assertIn('<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>', xml_authn_signed_2)
834+
835+
xml_authn_signed_3 = OneLogin_Saml2_Utils.add_sign(xml_authn, key, cert, False, OneLogin_Saml2_Constants.RSA_SHA384, OneLogin_Saml2_Constants.SHA512)
836+
self.assertIn('<ds:SignatureValue>', xml_authn_signed_3)
837+
self.assertIn('<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>', xml_authn_signed_3)
838+
self.assertIn('<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha512"/>', xml_authn_signed_3)
839+
self.assertIn('<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"/>', xml_authn_signed_3)
840+
813841
def testValidateSign(self):
814842
"""
815843
Tests the validate_sign method of the OneLogin_Saml2_Utils

0 commit comments

Comments
 (0)