Skip to content

Commit dc015e0

Browse files
committed
Be able to register future SP x509cert on the settings and publish it on SP metadata
1 parent 5e17c19 commit dc015e0

File tree

10 files changed

+137
-61
lines changed

10 files changed

+137
-61
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ Or also we can provide those data in the setting file at the 'x509cert' and the
157157

158158
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.
159159

160+
Use `sp_new.crt` if you are in a key rollover process and you want to
161+
publish that x509certificate on Service Provider metadata.
162+
160163
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:
161164

162165
```bash
@@ -279,6 +282,15 @@ This is the settings.json file:
279282
// the certs folder. But we can also provide them with the following parameters
280283
"x509cert": "",
281284
"privateKey": ""
285+
286+
/*
287+
* Key rollover
288+
* If you plan to update the SP x509cert and privateKey
289+
* you can define here the new x509cert and it will be
290+
* published on the SP metadata so Identity Providers can
291+
* read them and get ready for rollover.
292+
*/
293+
// 'x509certNew': '',
282294
},
283295

284296
// Identity Provider Data that we want connected with our SP.
@@ -924,6 +936,7 @@ Configuration of the OneLogin Python Toolkit
924936
* ***check_sp_certs*** Checks if the x509 certs of the SP exists and are valid.
925937
* ***get_sp_key*** Returns the x509 private key of the SP.
926938
* ***get_sp_cert*** Returns the x509 public cert of the SP.
939+
* ***get_sp_cert_new*** Returns the future x509 public cert of the SP.
927940
* ***get_idp_cert*** Returns the x509 public cert of the IdP.
928941
* ***get_sp_data*** Gets the SP data.
929942
* ***get_idp_data*** Gets the IdP data.
@@ -932,6 +945,7 @@ Configuration of the OneLogin Python Toolkit
932945
* ***get_organization*** Gets organization data.
933946
* ***format_idp_cert*** Formats the IdP cert.
934947
* ***format_sp_cert*** Formats the SP cert.
948+
* ***format_sp_cert_new*** Formats the SP cert new.
935949
* ***format_sp_key*** Formats the private key.
936950
* ***set_strict*** Activates or deactivates the strict mode.
937951
* ***is_strict*** Returns if the 'strict' mode is active.

demo-bottle/saml/certs/README

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde
22

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

5-
* sp.key Private Key
6-
* sp.crt Public cert
5+
* sp.key Private Key
6+
* sp.crt Public cert
7+
* sp_new.crt Future Public cert
78

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

demo-django/saml/certs/README

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde
22

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

5-
* sp.key Private Key
6-
* sp.crt Public cert
5+
* sp.key Private Key
6+
* sp.crt Public cert
7+
* sp_new.crt Future Public cert
78

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

demo-flask/saml/certs/README

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde
22

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

5-
* sp.key Private Key
6-
* sp.crt Public cert
5+
* sp.key Private Key
6+
* sp.crt Public cert
7+
* sp_new.crt Future Public cert
78

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

demo_pyramid/demo_pyramid/saml/certs/README

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ Take care of this folder that could contain private key. Be sure that this folde
22

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

5-
* sp.key Private Key
6-
* sp.crt Public cert
5+
* sp.key Private Key
6+
* sp.crt Public cert
7+
* sp_new.crt Future Public cert
78

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

src/onelogin/saml2/settings.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ def __init__(self, settings=None, custom_base_path=None, sp_validation_only=Fals
111111

112112
self.format_idp_cert()
113113
self.format_sp_cert()
114+
if 'x509certNew' in self.__sp:
115+
self.format_sp_cert_new()
114116
self.format_sp_key()
115117

116118
def __load_paths(self, base_path=None):
@@ -522,6 +524,23 @@ def get_sp_cert(self):
522524

523525
return cert or None
524526

527+
def get_sp_cert_new(self):
528+
"""
529+
Returns the x509 public of the SP planned
530+
to be used soon instead the other public cert
531+
532+
:returns: SP public cert new
533+
:rtype: string or None
534+
"""
535+
cert = self.__sp.get('x509certNew')
536+
cert_file_name = self.__paths['cert'] + 'sp_new.crt'
537+
538+
if not cert and exists(cert_file_name):
539+
with open(cert_file_name) as f:
540+
cert = f.read()
541+
542+
return cert or None
543+
525544
def get_idp_cert(self):
526545
"""
527546
Returns the x509 public cert of the IdP.
@@ -590,6 +609,10 @@ def get_sp_metadata(self):
590609
self.__security['metadataCacheDuration'],
591610
self.get_contacts(), self.get_organization()
592611
)
612+
613+
cert_new = self.get_sp_cert_new()
614+
metadata = OneLogin_Saml2_Metadata.add_x509_key_descriptors(metadata, cert_new)
615+
593616
cert = self.get_sp_cert()
594617
metadata = OneLogin_Saml2_Metadata.add_x509_key_descriptors(metadata, cert)
595618

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

731+
def format_sp_cert_new(self):
732+
"""
733+
Formats the SP cert.
734+
"""
735+
self.__sp['x509certNew'] = OneLogin_Saml2_Utils.format_cert(self.__sp['x509certNew'])
736+
708737
def format_sp_key(self):
709738
"""
710739
Formats the private key.

tests/settings/settings7.json

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"strict": false,
3+
"debug": false,
4+
"custom_base_path": "../../../tests/data/customPath/",
5+
"sp": {
6+
"entityId": "http://stuff.com/endpoints/metadata.php",
7+
"assertionConsumerService": {
8+
"url": "http://stuff.com/endpoints/endpoints/acs.php"
9+
},
10+
"singleLogoutService": {
11+
"url": "http://stuff.com/endpoints/endpoints/sls.php"
12+
},
13+
"NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
14+
"privateKey": "MIICXgIBAAKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABAoGAD4/Z4LWVWV6D1qMIp1Gzr0ZmdWTE1SPdZ7Ej8glGnCzPdguCPuzbhGXmIg0VJ5D+02wsqws1zd48JSMXXM8zkYZVwQYIPUsNn5FetQpwxDIMPmhHg+QNBgwOnk8JK2sIjjLPL7qY7Itv7LT7Gvm5qSOkZ33RCgXcgz+okEIQMYkCQQDzbTOyDL0c5WQV6A2k06T/azdhUdGXF9C0+WkWSfNaovmTgRXh1G+jMlr82Snz4p4/STt7P/XtyWzF3pkVgZr3AkEA7nPjXwHlttNEMo6AtxHd47nizK2NUN803ElIUT8P9KSCoERmSXq66PDekGNic4ldpsSvOeYCk8MAYoDBy9kvVwJBAMLgX4xg6lzhv7hR5+pWjTb1rIY6rCHbrPfU264+UZXz9v2BT/VUznLF81WMvStD9xAPHpFS6R0OLghSZhdzhI0CQQDL8Duvfxzrn4b9QlmduV8wLERoT6rEVxKLsPVz316TGrxJvBZLk/cV0SRZE1cZf4ukXSWMfEcJ/0Zt+LdG1CqjAkEAqwLSglJ9Dy3HpgMz4vAAyZWzAxvyA1zW0no9GOLcPQnYaNUN/Fy2SYtETXTb0CQ9X1rt8ffkFP7ya+5TC83aMg==",
15+
"x509cert": "MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMCTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYDVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xiZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2ZlaWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2QarQ4/67OZfHd7R+POBXhophSMv1ZOo",
16+
"x509certNew": "MIICVDCCAb2gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBHMQswCQYDVQQGEwJ1czEQMA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMTcwNDA3MDgzMDAzWhcNMjcwNDA1MDgzMDAzWjBHMQswCQYDVQQGEwJ1czEQMA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIGA1UEAwwLZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKhPS4/0azxbQekHHewQGKD7Pivr3CDpsrKxY3xlVanxj427OwzOb5KUVzsDEazumt6sZFY8HfidsjXY4EYA4ZzyL7ciIAR5vlAsIYN9nJ4AwVDnN/RjVwj+TN6BqWPLpVIpHc6Dl005HyE0zJnk1DZDn2tQVrIzbD3FhCp7YeotAgMBAAGjUDBOMB0GA1UdDgQWBBRYZx4thASfNvR/E7NsCF2IaZ7wIDAfBgNVHSMEGDAWgBRYZx4thASfNvR/E7NsCF2IaZ7wIDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBACz4aobx9aG3kh+rNyrlgM3K6dYfnKG1/YH5sJCAOvg8kDr0fQAQifH8lFVWumKUMoAe0bFTfwWtp/VJ8MprrEJth6PFeZdczpuv+fpLcNj2VmNVJqvQYvS4m36OnBFh1QFZW8UrbFIfdtm2nuZ+twSKqfKwjLdqcoX0p39h7Uw/"
17+
},
18+
"idp": {
19+
"entityId": "http://idp.example.com/",
20+
"singleSignOnService": {
21+
"url": "http://idp.example.com/SSOService.php"
22+
},
23+
"singleLogoutService": {
24+
"url": "http://idp.example.com/SingleLogoutService.php"
25+
},
26+
"x509cert": "MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMCTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYDVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xiZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2ZlaWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2QarQ4/67OZfHd7R+POBXhophSMv1ZOo"
27+
},
28+
"security": {
29+
"authnRequestsSigned": false,
30+
"wantAssertionsSigned": false,
31+
"signMetadata": false
32+
},
33+
"contactPerson": {
34+
"technical": {
35+
"givenName": "technical_name",
36+
"emailAddress": "technical@example.com"
37+
},
38+
"support": {
39+
"givenName": "support_name",
40+
"emailAddress": "support@example.com"
41+
}
42+
},
43+
"organization": {
44+
"en-US": {
45+
"name": "sp_test",
46+
"displayname": "SP test",
47+
"url": "http://sp.example.com"
48+
}
49+
}
50+
}

tests/src/OneLogin/saml2_tests/expensify_test.py.txt

Lines changed: 0 additions & 50 deletions
This file was deleted.

tests/src/OneLogin/saml2_tests/settings_test.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,21 @@ def testGetSPCert(self):
165165
settings_3 = OneLogin_Saml2_Settings(settings_data, custom_base_path=custom_base_path)
166166
self.assertIsNone(settings_3.get_sp_cert())
167167

168+
def testGetSPCertNew(self):
169+
"""
170+
Tests the get_sp_cert_new method of the OneLogin_Saml2_Settings
171+
"""
172+
settings_data = self.loadSettingsJSON()
173+
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"
174+
settings = OneLogin_Saml2_Settings(settings_data)
175+
self.assertEqual(cert, settings.get_sp_cert())
176+
self.assertIsNone(settings.get_sp_cert_new())
177+
178+
settings = OneLogin_Saml2_Settings(self.loadSettingsJSON('settings7.json'))
179+
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"
180+
self.assertEqual(cert, settings.get_sp_cert())
181+
self.assertEqual(cert_new, settings.get_sp_cert_new())
182+
168183
def testGetSPKey(self):
169184
"""
170185
Tests the get_sp_key method of the OneLogin_Saml2_Settings
@@ -337,6 +352,23 @@ def testGetSPMetadata(self):
337352
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)
338353
self.assertIn('<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://stuff.com/endpoints/endpoints/sls.php"/>', metadata)
339354
self.assertIn('<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>', metadata)
355+
self.assertEquals(2, metadata.count('<md:KeyDescriptor'))
356+
self.assertEquals(1, metadata.count('<md:KeyDescriptor use="signing"'))
357+
self.assertEquals(1, metadata.count('<md:KeyDescriptor use="encryption"'))
358+
359+
def testGetSPMetadata(self):
360+
"""
361+
Tests the getSPMetadata method of the OneLogin_Saml2_Settings
362+
Case with x509certNew
363+
"""
364+
settings = OneLogin_Saml2_Settings(self.loadSettingsJSON('settings7.json'))
365+
metadata = settings.get_sp_metadata()
366+
367+
self.assertNotEqual(len(metadata), 0)
368+
self.assertIn('<md:SPSSODescriptor', metadata)
369+
self.assertEquals(4, metadata.count('<md:KeyDescriptor'))
370+
self.assertEquals(2, metadata.count('<md:KeyDescriptor use="signing"'))
371+
self.assertEquals(2, metadata.count('<md:KeyDescriptor use="encryption"'))
340372

341373
def testGetUnicodeSPMetadata(self):
342374
"""

tests/src/OneLogin/saml2_tests/signed_response_test.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ def testResponseSignedAssertionNot(self):
4444
response = OneLogin_Saml2_Response(settings, b64encode(message))
4545

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

5148
def testResponseAndAssertionSigned(self):
5249
"""

0 commit comments

Comments
 (0)