Skip to content

Commit 2749128

Browse files
committed
Merge pull request #69 from open-craft/edx4-metadata-key-fix
Allow metadata signing with SP key specified as config value, not file
2 parents 10381bb + 3a67869 commit 2749128

File tree

2 files changed

+55
-27
lines changed

2 files changed

+55
-27
lines changed

src/onelogin/saml2/settings.py

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -565,9 +565,21 @@ def get_sp_metadata(self):
565565
# Sign metadata
566566
if 'signMetadata' in self.__security and self.__security['signMetadata'] is not False:
567567
if self.__security['signMetadata'] is True:
568-
key_file_name = 'sp.key'
569-
cert_file_name = 'sp.crt'
568+
# Use the SP's normal key to sign the metadata:
569+
if not cert:
570+
raise OneLogin_Saml2_Error(
571+
'Cannot sign metadata: missing SP public key certificate.',
572+
OneLogin_Saml2_Error.PUBLIC_CERT_FILE_NOT_FOUND
573+
)
574+
cert_metadata = cert
575+
key_metadata = self.get_sp_key()
576+
if not key_metadata:
577+
raise OneLogin_Saml2_Error(
578+
'Cannot sign metadata: missing SP private key.',
579+
OneLogin_Saml2_Error.PRIVATE_KEY_FILE_NOT_FOUND
580+
)
570581
else:
582+
# Use a custom key to sign the metadata:
571583
if ('keyFileName' not in self.__security['signMetadata'] or
572584
'certFileName' not in self.__security['signMetadata']):
573585
raise OneLogin_Saml2_Error(
@@ -576,30 +588,28 @@ def get_sp_metadata(self):
576588
)
577589
key_file_name = self.__security['signMetadata']['keyFileName']
578590
cert_file_name = self.__security['signMetadata']['certFileName']
579-
key_metadata_file = self.__paths['cert'] + key_file_name
580-
cert_metadata_file = self.__paths['cert'] + cert_file_name
581-
582-
if not exists(key_metadata_file):
583-
raise OneLogin_Saml2_Error(
584-
'Private key file not found: %s',
585-
OneLogin_Saml2_Error.PRIVATE_KEY_FILE_NOT_FOUND,
586-
key_metadata_file
587-
)
591+
key_metadata_file = self.__paths['cert'] + key_file_name
592+
cert_metadata_file = self.__paths['cert'] + cert_file_name
588593

589-
if not exists(cert_metadata_file):
590-
raise OneLogin_Saml2_Error(
591-
'Public cert file not found: %s',
592-
OneLogin_Saml2_Error.PUBLIC_CERT_FILE_NOT_FOUND,
593-
cert_metadata_file
594-
)
595-
596-
f_metadata_key = open(key_metadata_file, 'r')
597-
key_metadata = f_metadata_key.read()
598-
f_metadata_key.close()
594+
try:
595+
with open(key_metadata_file, 'r') as f_metadata_key:
596+
key_metadata = f_metadata_key.read()
597+
except IOError:
598+
raise OneLogin_Saml2_Error(
599+
'Private key file not readable: %s',
600+
OneLogin_Saml2_Error.PRIVATE_KEY_FILE_NOT_FOUND,
601+
key_metadata_file
602+
)
599603

600-
f_metadata_cert = open(cert_metadata_file, 'r')
601-
cert_metadata = f_metadata_cert.read()
602-
f_metadata_cert.close()
604+
try:
605+
with open(cert_metadata_file, 'r') as f_metadata_cert:
606+
cert_metadata = f_metadata_cert.read()
607+
except IOError:
608+
raise OneLogin_Saml2_Error(
609+
'Public cert file not readable: %s',
610+
OneLogin_Saml2_Error.PUBLIC_CERT_FILE_NOT_FOUND,
611+
cert_metadata_file
612+
)
603613

604614
metadata = OneLogin_Saml2_Metadata.sign_metadata(metadata, key_metadata, cert_metadata)
605615

tests/src/OneLogin/saml2_tests/settings_test.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from os.path import dirname, join, exists, sep
88
import unittest
99

10+
from onelogin.saml2.errors import OneLogin_Saml2_Error
1011
from onelogin.saml2.settings import OneLogin_Saml2_Settings
1112
from onelogin.saml2.utils import OneLogin_Saml2_Utils
1213

@@ -371,8 +372,24 @@ def testGetSPMetadataSigned(self):
371372
if 'security' not in settings_info:
372373
settings_info['security'] = {}
373374
settings_info['security']['signMetadata'] = True
374-
settings = OneLogin_Saml2_Settings(settings_info)
375+
self.generateAndCheckMetadata(settings_info)
376+
377+
# Now try again with SP keys set directly in settings and not from files:
378+
del settings_info['custom_base_path']
379+
# Now the keys should not be found, so metadata generation won't work:
380+
with self.assertRaises(OneLogin_Saml2_Error):
381+
OneLogin_Saml2_Settings(settings_info).get_sp_metadata()
382+
# Set the keys in the settings:
383+
settings_info['sp']['x509cert'] = self.file_contents(join(self.data_path, 'customPath', 'certs', 'sp.crt'))
384+
settings_info['sp']['privateKey'] = self.file_contents(join(self.data_path, 'customPath', 'certs', 'sp.key'))
385+
self.generateAndCheckMetadata(settings_info)
375386

387+
def generateAndCheckMetadata(self, settings):
388+
"""
389+
Helper method: Given some settings, generate metadata and validate it
390+
"""
391+
if not isinstance(settings, OneLogin_Saml2_Settings):
392+
settings = OneLogin_Saml2_Settings(settings)
376393
metadata = settings.get_sp_metadata()
377394
self.assertIn('<md:SPSSODescriptor', metadata)
378395
self.assertIn('entityID="http://stuff.com/endpoints/metadata.php"', metadata)
@@ -385,6 +402,7 @@ def testGetSPMetadataSigned(self):
385402
self.assertIn('<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>', metadata)
386403
self.assertIn('<ds:Reference', metadata)
387404
self.assertIn('<ds:KeyInfo><ds:X509Data><ds:X509Certificate>', metadata)
405+
return metadata
388406

389407
def testGetSPMetadataSignedNoMetadataCert(self):
390408
"""
@@ -411,7 +429,7 @@ def testGetSPMetadataSignedNoMetadataCert(self):
411429
settings.get_sp_metadata()
412430
self.assertTrue(False)
413431
except Exception as e:
414-
self.assertIn('Private key file not found', e.message)
432+
self.assertIn('Private key file not readable', e.message)
415433

416434
settings_info['security']['signMetadata'] = {
417435
'keyFileName': 'sp.key',
@@ -422,7 +440,7 @@ def testGetSPMetadataSignedNoMetadataCert(self):
422440
settings.get_sp_metadata()
423441
self.assertTrue(False)
424442
except Exception as e:
425-
self.assertIn('Public cert file not found', e.message)
443+
self.assertIn('Public cert file not readable', e.message)
426444

427445
settings_info['security']['signMetadata'] = 'invalid_value'
428446
settings = OneLogin_Saml2_Settings(settings_info)

0 commit comments

Comments
 (0)