Skip to content

Commit 34d22e0

Browse files
authored
Merge pull request SAML-Toolkits#57 from onelogin/key_rollover_mngmt
Improve Key Rollover management
2 parents f7a9652 + 650d2b9 commit 34d22e0

File tree

21 files changed

+825
-194
lines changed

21 files changed

+825
-194
lines changed

README.md

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

144144
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.
145145

146+
Use `sp_new.crt` if you are in a key rollover process and you want to
147+
publish that x509certificate on Service Provider metadata.
148+
146149
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:
147150

148151
```bash
@@ -253,6 +256,15 @@ This is the settings.json file:
253256
// the certs folder. But we can also provide them with the following parameters
254257
"x509cert": "",
255258
"privateKey": ""
259+
260+
/*
261+
* Key rollover
262+
* If you plan to update the SP x509cert and privateKey
263+
* you can define here the new x509cert and it will be
264+
* published on the SP metadata so Identity Providers can
265+
* read them and get ready for rollover.
266+
*/
267+
// 'x509certNew': '',
256268
},
257269

258270
// Identity Provider Data that we want connected with our SP.
@@ -296,6 +308,22 @@ This is the settings.json file:
296308
*/
297309
// "certFingerprint": "",
298310
// "certFingerprintAlgorithm": "sha1",
311+
312+
/* In some scenarios the IdP uses different certificates for
313+
* signing/encryption, or is under key rollover phase and
314+
* more than one certificate is published on IdP metadata.
315+
* In order to handle that the toolkit offers that parameter.
316+
* (when used, 'x509cert' and 'certFingerprint' values are
317+
* ignored).
318+
*/
319+
// 'x509certMulti': {
320+
// 'signing': [
321+
// '<cert1-string>'
322+
// ],
323+
// 'encryption': [
324+
// '<cert2-string>'
325+
// ]
326+
// }
299327
}
300328
}
301329
```
@@ -449,6 +477,23 @@ json_data_file.close()
449477
auth = OneLogin_Saml2_Auth(req, settings_data)
450478
```
451479

480+
#### Metadata Based Configuration
481+
482+
The method above requires a little extra work to manually specify attributes about the IdP. (And your SP application)
483+
484+
There's an easier method -- use a metadata exchange. Metadata is just an XML file that defines the capabilities of both the IdP and the SP application. It also contains the X.509 public key certificates which add to the trusted relationship. The IdP administrator can also configure custom settings for an SP based on the metadata.
485+
486+
Using ````parse_remote```` IdP metadata can be obtained and added to the settings withouth further ado.
487+
488+
``
489+
idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote('https://example.com/auth/saml2/idp/metadata')
490+
``
491+
492+
If the Metadata contains several entities, the relevant EntityDescriptor can be specified when retrieving the settings from the IdpMetadataParser by its Entity Id value:
493+
494+
idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote(https://example.com/metadatas, entity_id='idp_entity_id')
495+
496+
452497
#### How load the library ####
453498

454499
In order to use the toolkit library you need to import the file that contains the class that you will need
@@ -777,6 +822,26 @@ else:
777822
```
778823

779824

825+
### SP Key rollover ###
826+
827+
If you plan to update the SP x509cert and privateKey you can define the new x509cert as $settings['sp']['x509certNew'] and it will be
828+
published on the SP metadata so Identity Providers can read them and get ready for rollover.
829+
830+
831+
### IdP with multiple certificates ###
832+
833+
In some scenarios the IdP uses different certificates for
834+
signing/encryption, or is under key rollover phase and more than one certificate is published on IdP metadata.
835+
836+
In order to handle that the toolkit offers the $settings['idp']['x509certMulti'] parameter.
837+
838+
When that parameter is used, 'x509cert' and 'certFingerprint' values will be ignored by the toolkit.
839+
840+
The 'x509certMulti' is an array with 2 keys:
841+
- 'signing'. An array of certs that will be used to validate IdP signature
842+
- 'encryption' An array with one unique cert that will be used to encrypt data to be sent to the IdP.
843+
844+
780845
### Main classes and methods ###
781846

782847
Described below are the main classes and methods that can be invoked from the SAML2 library.
@@ -884,14 +949,17 @@ Configuration of the OneLogin Python Toolkit
884949
* ***check_sp_certs*** Checks if the x509 certs of the SP exists and are valid.
885950
* ***get_sp_key*** Returns the x509 private key of the SP.
886951
* ***get_sp_cert*** Returns the x509 public cert of the SP.
952+
* ***get_sp_cert_new*** Returns the future x509 public cert of the SP.
887953
* ***get_idp_cert*** Returns the x509 public cert of the IdP.
888954
* ***get_sp_data*** Gets the SP data.
889955
* ***get_idp_data*** Gets the IdP data.
890956
* ***get_security_data*** Gets security data.
891957
* ***get_contacts*** Gets contacts data.
892958
* ***get_organization*** Gets organization data.
893959
* ***format_idp_cert*** Formats the IdP cert.
960+
* ***format_idp_cert_multi*** Formats all registered IdP certs.
894961
* ***format_sp_cert*** Formats the SP cert.
962+
* ***format_sp_cert_new*** Formats the SP cert new.
895963
* ***format_sp_key*** Formats the private key.
896964
* ***set_strict*** Activates or deactivates the strict mode.
897965
* ***is_strict*** Returns if the 'strict' mode is active.

demo-django/saml/certs/README

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ 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
8+
79

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

demo-flask/saml/certs/README

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ 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
8+
79

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

demo_pyramid/demo_pyramid/saml/certs/README

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ 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
8+
79

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

src/onelogin/saml2/auth.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -534,10 +534,15 @@ def __validate_signature(self, data, saml_type, raise_exceptions=False):
534534
)
535535
return True
536536

537-
x509cert = self.get_settings().get_idp_cert()
537+
idp_data = self.get_settings().get_idp_data()
538538

539-
if not x509cert:
540-
error_msg = "In order to validate the sign on the %s, the x509cert of the IdP is required" % saml_type
539+
exists_x509cert = 'x509cert' in idp_data and idp_data['x509cert']
540+
exists_multix509sign = 'x509certMulti' in idp_data and \
541+
'signing' in idp_data['x509certMulti'] and \
542+
idp_data['x509certMulti']['signing']
543+
544+
if not (exists_x509cert or exists_multix509sign):
545+
error_msg = 'In order to validate the sign on the %s, the x509cert of the IdP is required' % saml_type
541546
self.__errors.append(error_msg)
542547
raise OneLogin_Saml2_Error(
543548
error_msg,
@@ -559,15 +564,29 @@ def __validate_signature(self, data, saml_type, raise_exceptions=False):
559564
lowercase_urlencoding
560565
)
561566

562-
if not OneLogin_Saml2_Utils.validate_binary_sign(signed_query,
563-
OneLogin_Saml2_Utils.b64decode(signature),
564-
x509cert,
565-
sign_alg,
566-
self.__settings.is_debug_active()):
567+
if exists_multix509sign:
568+
for cert in idp_data['x509certMulti']['signing']:
569+
if OneLogin_Saml2_Utils.validate_binary_sign(signed_query,
570+
OneLogin_Saml2_Utils.b64decode(signature),
571+
cert,
572+
sign_alg):
573+
return True
567574
raise OneLogin_Saml2_ValidationError(
568-
'Signature validation failed. %s rejected.' % saml_type,
575+
'Signature validation failed. %s rejected' % saml_type,
569576
OneLogin_Saml2_ValidationError.INVALID_SIGNATURE
570577
)
578+
else:
579+
cert = idp_data['x509cert']
580+
581+
if not OneLogin_Saml2_Utils.validate_binary_sign(signed_query,
582+
OneLogin_Saml2_Utils.b64decode(signature),
583+
cert,
584+
sign_alg,
585+
self.__settings.is_debug_active()):
586+
raise OneLogin_Saml2_ValidationError(
587+
'Signature validation failed. %s rejected' % saml_type,
588+
OneLogin_Saml2_ValidationError.INVALID_SIGNATURE
589+
)
571590
return True
572591
except Exception as e:
573592
self.__error_reason = str(e)

0 commit comments

Comments
 (0)