Skip to content

Commit

Permalink
Be able to register future SP x509cert on the settings and publish it…
Browse files Browse the repository at this point in the history
… on SP metadata
  • Loading branch information
pitbulk committed May 11, 2017
1 parent 5e17c19 commit dc015e0
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 61 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ Or also we can provide those data in the setting file at the 'x509cert' and the

Sometimes we could need a signature on the metadata published by the SP, in this case we could use the x.509 cert previously mentioned or use a new x.509 cert: metadata.crt and metadata.key.

Use `sp_new.crt` if you are in a key rollover process and you want to
publish that x509certificate on Service Provider metadata.

If you want to create self-signed certs, you can do it at the https://www.samltool.com/self_signed_certs.php service, or using the command:

```bash
Expand Down Expand Up @@ -279,6 +282,15 @@ This is the settings.json file:
// the certs folder. But we can also provide them with the following parameters
"x509cert": "",
"privateKey": ""

/*
* Key rollover
* If you plan to update the SP x509cert and privateKey
* you can define here the new x509cert and it will be
* published on the SP metadata so Identity Providers can
* read them and get ready for rollover.
*/
// 'x509certNew': '',
},

// Identity Provider Data that we want connected with our SP.
Expand Down Expand Up @@ -924,6 +936,7 @@ Configuration of the OneLogin Python Toolkit
* ***check_sp_certs*** Checks if the x509 certs of the SP exists and are valid.
* ***get_sp_key*** Returns the x509 private key of the SP.
* ***get_sp_cert*** Returns the x509 public cert of the SP.
* ***get_sp_cert_new*** Returns the future x509 public cert of the SP.
* ***get_idp_cert*** Returns the x509 public cert of the IdP.
* ***get_sp_data*** Gets the SP data.
* ***get_idp_data*** Gets the IdP data.
Expand All @@ -932,6 +945,7 @@ Configuration of the OneLogin Python Toolkit
* ***get_organization*** Gets organization data.
* ***format_idp_cert*** Formats the IdP cert.
* ***format_sp_cert*** Formats the SP cert.
* ***format_sp_cert_new*** Formats the SP cert new.
* ***format_sp_key*** Formats the private key.
* ***set_strict*** Activates or deactivates the strict mode.
* ***is_strict*** Returns if the 'strict' mode is active.
Expand Down
5 changes: 3 additions & 2 deletions demo-bottle/saml/certs/README
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde

Onelogin Python Toolkit expects that certs for the SP could be stored in this folder as:

* sp.key Private Key
* sp.crt Public cert
* sp.key Private Key
* sp.crt Public cert
* sp_new.crt Future Public cert

Also you can use other cert to sign the metadata of the SP using the:

Expand Down
5 changes: 3 additions & 2 deletions demo-django/saml/certs/README
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde

Onelogin Python Toolkit expects that certs for the SP could be stored in this folder as:

* sp.key Private Key
* sp.crt Public cert
* sp.key Private Key
* sp.crt Public cert
* sp_new.crt Future Public cert

Also you can use other cert to sign the metadata of the SP using the:

Expand Down
5 changes: 3 additions & 2 deletions demo-flask/saml/certs/README
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde

Onelogin Python Toolkit expects that certs for the SP could be stored in this folder as:

* sp.key Private Key
* sp.crt Public cert
* sp.key Private Key
* sp.crt Public cert
* sp_new.crt Future Public cert

Also you can use other cert to sign the metadata of the SP using the:

Expand Down
5 changes: 3 additions & 2 deletions demo_pyramid/demo_pyramid/saml/certs/README
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde

Onelogin Python Toolkit expects that certs for the SP could be stored in this folder as:

* sp.key Private Key
* sp.crt Public cert
* sp.key Private Key
* sp.crt Public cert
* sp_new.crt Future Public cert

Also you can use other cert to sign the metadata of the SP using the:

Expand Down
29 changes: 29 additions & 0 deletions src/onelogin/saml2/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ def __init__(self, settings=None, custom_base_path=None, sp_validation_only=Fals

self.format_idp_cert()
self.format_sp_cert()
if 'x509certNew' in self.__sp:
self.format_sp_cert_new()
self.format_sp_key()

def __load_paths(self, base_path=None):
Expand Down Expand Up @@ -522,6 +524,23 @@ def get_sp_cert(self):

return cert or None

def get_sp_cert_new(self):
"""
Returns the x509 public of the SP planned
to be used soon instead the other public cert
:returns: SP public cert new
:rtype: string or None
"""
cert = self.__sp.get('x509certNew')
cert_file_name = self.__paths['cert'] + 'sp_new.crt'

if not cert and exists(cert_file_name):
with open(cert_file_name) as f:
cert = f.read()

return cert or None

def get_idp_cert(self):
"""
Returns the x509 public cert of the IdP.
Expand Down Expand Up @@ -590,6 +609,10 @@ def get_sp_metadata(self):
self.__security['metadataCacheDuration'],
self.get_contacts(), self.get_organization()
)

cert_new = self.get_sp_cert_new()
metadata = OneLogin_Saml2_Metadata.add_x509_key_descriptors(metadata, cert_new)

cert = self.get_sp_cert()
metadata = OneLogin_Saml2_Metadata.add_x509_key_descriptors(metadata, cert)

Expand Down Expand Up @@ -705,6 +728,12 @@ def format_sp_cert(self):
"""
self.__sp['x509cert'] = OneLogin_Saml2_Utils.format_cert(self.__sp['x509cert'])

def format_sp_cert_new(self):
"""
Formats the SP cert.
"""
self.__sp['x509certNew'] = OneLogin_Saml2_Utils.format_cert(self.__sp['x509certNew'])

def format_sp_key(self):
"""
Formats the private key.
Expand Down
50 changes: 50 additions & 0 deletions tests/settings/settings7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"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",
"privateKey": "MIICXgIBAAKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABAoGAD4/Z4LWVWV6D1qMIp1Gzr0ZmdWTE1SPdZ7Ej8glGnCzPdguCPuzbhGXmIg0VJ5D+02wsqws1zd48JSMXXM8zkYZVwQYIPUsNn5FetQpwxDIMPmhHg+QNBgwOnk8JK2sIjjLPL7qY7Itv7LT7Gvm5qSOkZ33RCgXcgz+okEIQMYkCQQDzbTOyDL0c5WQV6A2k06T/azdhUdGXF9C0+WkWSfNaovmTgRXh1G+jMlr82Snz4p4/STt7P/XtyWzF3pkVgZr3AkEA7nPjXwHlttNEMo6AtxHd47nizK2NUN803ElIUT8P9KSCoERmSXq66PDekGNic4ldpsSvOeYCk8MAYoDBy9kvVwJBAMLgX4xg6lzhv7hR5+pWjTb1rIY6rCHbrPfU264+UZXz9v2BT/VUznLF81WMvStD9xAPHpFS6R0OLghSZhdzhI0CQQDL8Duvfxzrn4b9QlmduV8wLERoT6rEVxKLsPVz316TGrxJvBZLk/cV0SRZE1cZf4ukXSWMfEcJ/0Zt+LdG1CqjAkEAqwLSglJ9Dy3HpgMz4vAAyZWzAxvyA1zW0no9GOLcPQnYaNUN/Fy2SYtETXTb0CQ9X1rt8ffkFP7ya+5TC83aMg==",
"x509cert": "MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMCTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYDVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xiZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2ZlaWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2QarQ4/67OZfHd7R+POBXhophSMv1ZOo",
"x509certNew": "MIICVDCCAb2gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBHMQswCQYDVQQGEwJ1czEQMA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMTcwNDA3MDgzMDAzWhcNMjcwNDA1MDgzMDAzWjBHMQswCQYDVQQGEwJ1czEQMA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIGA1UEAwwLZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKhPS4/0azxbQekHHewQGKD7Pivr3CDpsrKxY3xlVanxj427OwzOb5KUVzsDEazumt6sZFY8HfidsjXY4EYA4ZzyL7ciIAR5vlAsIYN9nJ4AwVDnN/RjVwj+TN6BqWPLpVIpHc6Dl005HyE0zJnk1DZDn2tQVrIzbD3FhCp7YeotAgMBAAGjUDBOMB0GA1UdDgQWBBRYZx4thASfNvR/E7NsCF2IaZ7wIDAfBgNVHSMEGDAWgBRYZx4thASfNvR/E7NsCF2IaZ7wIDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBACz4aobx9aG3kh+rNyrlgM3K6dYfnKG1/YH5sJCAOvg8kDr0fQAQifH8lFVWumKUMoAe0bFTfwWtp/VJ8MprrEJth6PFeZdczpuv+fpLcNj2VmNVJqvQYvS4m36OnBFh1QFZW8UrbFIfdtm2nuZ+twSKqfKwjLdqcoX0p39h7Uw/"
},
"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": "technical_name",
"emailAddress": "technical@example.com"
},
"support": {
"givenName": "support_name",
"emailAddress": "support@example.com"
}
},
"organization": {
"en-US": {
"name": "sp_test",
"displayname": "SP test",
"url": "http://sp.example.com"
}
}
}
50 changes: 0 additions & 50 deletions tests/src/OneLogin/saml2_tests/expensify_test.py.txt

This file was deleted.

32 changes: 32 additions & 0 deletions tests/src/OneLogin/saml2_tests/settings_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,21 @@ def testGetSPCert(self):
settings_3 = OneLogin_Saml2_Settings(settings_data, custom_base_path=custom_base_path)
self.assertIsNone(settings_3.get_sp_cert())

def testGetSPCertNew(self):
"""
Tests the get_sp_cert_new method of the OneLogin_Saml2_Settings
"""
settings_data = self.loadSettingsJSON()
cert = "-----BEGIN CERTIFICATE-----\nMIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMC\nTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYD\nVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG\n9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4\nMTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xi\nZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2Zl\naWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5v\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LO\nNoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHIS\nKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d\n1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8\nBUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7n\nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2Qar\nQ4/67OZfHd7R+POBXhophSMv1ZOo\n-----END CERTIFICATE-----\n"
settings = OneLogin_Saml2_Settings(settings_data)
self.assertEqual(cert, settings.get_sp_cert())
self.assertIsNone(settings.get_sp_cert_new())

settings = OneLogin_Saml2_Settings(self.loadSettingsJSON('settings7.json'))
cert_new = "-----BEGIN CERTIFICATE-----\nMIICVDCCAb2gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBHMQswCQYDVQQGEwJ1czEQ\nMA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIGA1UEAwwLZXhh\nbXBsZS5jb20wHhcNMTcwNDA3MDgzMDAzWhcNMjcwNDA1MDgzMDAzWjBHMQswCQYD\nVQQGEwJ1czEQMA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIG\nA1UEAwwLZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKhP\nS4/0azxbQekHHewQGKD7Pivr3CDpsrKxY3xlVanxj427OwzOb5KUVzsDEazumt6s\nZFY8HfidsjXY4EYA4ZzyL7ciIAR5vlAsIYN9nJ4AwVDnN/RjVwj+TN6BqWPLpVIp\nHc6Dl005HyE0zJnk1DZDn2tQVrIzbD3FhCp7YeotAgMBAAGjUDBOMB0GA1UdDgQW\nBBRYZx4thASfNvR/E7NsCF2IaZ7wIDAfBgNVHSMEGDAWgBRYZx4thASfNvR/E7Ns\nCF2IaZ7wIDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBACz4aobx9aG3\nkh+rNyrlgM3K6dYfnKG1/YH5sJCAOvg8kDr0fQAQifH8lFVWumKUMoAe0bFTfwWt\np/VJ8MprrEJth6PFeZdczpuv+fpLcNj2VmNVJqvQYvS4m36OnBFh1QFZW8UrbFIf\ndtm2nuZ+twSKqfKwjLdqcoX0p39h7Uw/\n-----END CERTIFICATE-----\n"
self.assertEqual(cert, settings.get_sp_cert())
self.assertEqual(cert_new, settings.get_sp_cert_new())

def testGetSPKey(self):
"""
Tests the get_sp_key method of the OneLogin_Saml2_Settings
Expand Down Expand Up @@ -337,6 +352,23 @@ def testGetSPMetadata(self):
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('<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)
self.assertEquals(2, metadata.count('<md:KeyDescriptor'))
self.assertEquals(1, metadata.count('<md:KeyDescriptor use="signing"'))
self.assertEquals(1, metadata.count('<md:KeyDescriptor use="encryption"'))

def testGetSPMetadata(self):
"""
Tests the getSPMetadata method of the OneLogin_Saml2_Settings
Case with x509certNew
"""
settings = OneLogin_Saml2_Settings(self.loadSettingsJSON('settings7.json'))
metadata = settings.get_sp_metadata()

self.assertNotEqual(len(metadata), 0)
self.assertIn('<md:SPSSODescriptor', metadata)
self.assertEquals(4, metadata.count('<md:KeyDescriptor'))
self.assertEquals(2, metadata.count('<md:KeyDescriptor use="signing"'))
self.assertEquals(2, metadata.count('<md:KeyDescriptor use="encryption"'))

def testGetUnicodeSPMetadata(self):
"""
Expand Down
3 changes: 0 additions & 3 deletions tests/src/OneLogin/saml2_tests/signed_response_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ def testResponseSignedAssertionNot(self):
response = OneLogin_Saml2_Response(settings, b64encode(message))

self.assertEquals('someone@example.org', response.get_nameid())
from onelogin.saml2.utils import OneLogin_Saml2_Utils
assertion_nodes = OneLogin_Saml2_Utils.query(response.document, '//saml:Assertion')
self.assertEquals(len(assertion_nodes), 1)

def testResponseAndAssertionSigned(self):
"""
Expand Down

0 comments on commit dc015e0

Please sign in to comment.