Skip to content

Commit c53a11f

Browse files
committed
Now the SP is able to select the algorithm to be used on signatures
1 parent f64c157 commit c53a11f

8 files changed

Lines changed: 91 additions & 25 deletions

File tree

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,15 @@ In addition to the required settings data (idp, sp), there is extra information
323323
// Provide the desired Timestamp, for example 2015-06-26T20:00:00Z
324324
'metadataValidUntil': null,
325325
// Provide the desired duration, for example PT518400S (6 days)
326-
'metadataCacheDuration': null
326+
'metadataCacheDuration': null,
327+
328+
// Algorithm that the toolkit will use on signing process. Options:
329+
// 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
330+
// 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'
331+
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
332+
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
333+
// 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
334+
'signatureAlgorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
327335
},
328336

329337
// Contact information template, it is recommended to suply a

demo-django/saml/advanced_settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"wantMessagesSigned": false,
99
"wantAssertionsSigned": false,
1010
"wantNameIdEncrypted": false
11+
"signatureAlgorithm" => "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
1112
},
1213
"contactPerson": {
1314
"technical": {
@@ -26,4 +27,4 @@
2627
"url": "http://sp.example.com"
2728
}
2829
}
29-
}
30+
}

demo-flask/saml/advanced_settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"signMetadata": false,
88
"wantMessagesSigned": false,
99
"wantAssertionsSigned": false,
10-
"wantNameIdEncrypted": false
10+
"wantNameIdEncrypted": false,
11+
"signatureAlgorithm" => "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
1112
},
1213
"contactPerson": {
1314
"technical": {

src/onelogin/saml2/auth.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ def process_slo(self, keep_local_session=False, request_id=None, delete_session_
152152

153153
security = self.__settings.get_security_data()
154154
if 'logoutResponseSigned' in security and security['logoutResponseSigned']:
155-
parameters['SigAlg'] = OneLogin_Saml2_Constants.RSA_SHA1
156-
parameters['Signature'] = self.build_response_signature(logout_response, parameters.get('RelayState', None))
155+
parameters['SigAlg'] = security['signatureAlgorithm']
156+
parameters['Signature'] = self.build_response_signature(logout_response, parameters.get('RelayState', None), security['signatureAlgorithm'])
157157

158158
return self.redirect_to(self.get_slo_url(), parameters)
159159
else:
@@ -274,8 +274,8 @@ def login(self, return_to=None, force_authn=False, is_passive=False):
274274

275275
security = self.__settings.get_security_data()
276276
if security.get('authnRequestsSigned', False):
277-
parameters['SigAlg'] = OneLogin_Saml2_Constants.RSA_SHA1
278-
parameters['Signature'] = self.build_request_signature(saml_request, parameters['RelayState'])
277+
parameters['SigAlg'] = security['signatureAlgorithm']
278+
parameters['Signature'] = self.build_request_signature(saml_request, parameters['RelayState'], security['signatureAlgorithm'])
279279
return self.redirect_to(self.get_sso_url(), parameters)
280280

281281
def logout(self, return_to=None, name_id=None, session_index=None):
@@ -315,8 +315,8 @@ def logout(self, return_to=None, name_id=None, session_index=None):
315315

316316
security = self.__settings.get_security_data()
317317
if security.get('logoutRequestSigned', False):
318-
parameters['SigAlg'] = OneLogin_Saml2_Constants.RSA_SHA1
319-
parameters['Signature'] = self.build_request_signature(saml_request, parameters['RelayState'])
318+
parameters['SigAlg'] = security['signatureAlgorithm']
319+
parameters['Signature'] = self.build_request_signature(saml_request, parameters['RelayState'], security['signatureAlgorithm'])
320320
return self.redirect_to(slo_url, parameters)
321321

322322
def get_sso_url(self):
@@ -342,7 +342,7 @@ def get_slo_url(self):
342342
url = idp_data['singleLogoutService']['url']
343343
return url
344344

345-
def build_request_signature(self, saml_request, relay_state):
345+
def build_request_signature(self, saml_request, relay_state, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
346346
"""
347347
Builds the Signature of the SAML Request.
348348
@@ -351,21 +351,27 @@ def build_request_signature(self, saml_request, relay_state):
351351
352352
:param relay_state: The target URL the user should be redirected to
353353
:type relay_state: string
354+
355+
:param sign_algorithm: Signature algorithm method
356+
:type sign_algorithm: string
354357
"""
355-
return self.__build_signature(saml_request, relay_state, 'SAMLRequest')
358+
return self.__build_signature(saml_request, relay_state, 'SAMLRequest', sign_algorithm)
356359

357-
def build_response_signature(self, saml_response, relay_state):
360+
def build_response_signature(self, saml_response, relay_state, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
358361
"""
359362
Builds the Signature of the SAML Response.
360363
:param saml_request: The SAML Response
361364
:type saml_request: string
362365
363366
:param relay_state: The target URL the user should be redirected to
364367
:type relay_state: string
368+
369+
:param sign_algorithm: Signature algorithm method
370+
:type sign_algorithm: string
365371
"""
366-
return self.__build_signature(saml_response, relay_state, 'SAMLResponse')
372+
return self.__build_signature(saml_response, relay_state, 'SAMLResponse', sign_algorithm)
367373

368-
def __build_signature(self, saml_data, relay_state, saml_type):
374+
def __build_signature(self, saml_data, relay_state, saml_type, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
369375
"""
370376
Builds the Signature
371377
:param saml_data: The SAML Data
@@ -376,6 +382,9 @@ def __build_signature(self, saml_data, relay_state, saml_type):
376382
377383
:param saml_type: The target URL the user should be redirected to
378384
:type saml_type: string SAMLRequest | SAMLResponse
385+
386+
:param sign_algorithm: Signature algorithm method
387+
:type sign_algorithm: string
379388
"""
380389
assert saml_type in ['SAMLRequest', 'SAMLResponse']
381390

@@ -395,10 +404,20 @@ def __build_signature(self, saml_data, relay_state, saml_type):
395404

396405
saml_data_str = '%s=%s' % (saml_type, quote_plus(saml_data))
397406
relay_state_str = 'RelayState=%s' % quote_plus(relay_state)
398-
alg_str = 'SigAlg=%s' % quote_plus(OneLogin_Saml2_Constants.RSA_SHA1)
407+
alg_str = 'SigAlg=%s' % quote_plus(sign_algorithm)
399408

400409
sign_data = [saml_data_str, relay_state_str, alg_str]
401410
msg = '&'.join(sign_data)
402411

403-
signature = dsig_ctx.signBinary(str(msg), xmlsec.TransformRsaSha1)
412+
# Sign the metadata with our private key.
413+
sign_algorithm_transform_map = {
414+
OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.TransformDsaSha1,
415+
OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.TransformRsaSha1,
416+
OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.TransformRsaSha256,
417+
OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.TransformRsaSha384,
418+
OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.TransformRsaSha512
419+
}
420+
sign_algorithm_transform = sign_algorithm_transform_map.get(sign_algorithm, xmlsec.TransformRsaSha1)
421+
422+
signature = dsig_ctx.signBinary(str(msg), sign_algorithm_transform)
404423
return b64encode(signature)

src/onelogin/saml2/constants.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,30 @@ class OneLogin_Saml2_Constants(object):
7676
STATUS_PARTIAL_LOGOUT = 'urn:oasis:names:tc:SAML:2.0:status:PartialLogout'
7777
STATUS_PROXY_COUNT_EXCEEDED = 'urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded'
7878

79-
# Crypto
80-
RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
81-
79+
# Namespaces
8280
NSMAP = {
8381
'samlp': NS_SAMLP,
8482
'saml': NS_SAML,
8583
'ds': NS_DS,
8684
'xenc': NS_XENC
8785
}
86+
87+
# Sign & Crypto
88+
SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1'
89+
SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'
90+
SHA384 = 'http://www.w3.org/2001/04/xmlencsha384'
91+
SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'
92+
93+
DSA_SHA1 = 'http://www.w3.org/2000/09/xmld/sig#dsa-sha1'
94+
RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
95+
RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
96+
RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
97+
RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
98+
99+
# Enc
100+
TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'
101+
AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'
102+
AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'
103+
AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'
104+
RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'
105+
RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'

src/onelogin/saml2/metadata.py

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

155155
@staticmethod
156-
def sign_metadata(metadata, key, cert):
156+
def sign_metadata(metadata, key, cert, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
157157
"""
158158
Signs the metadata with the key/cert provided
159159
@@ -166,10 +166,13 @@ def sign_metadata(metadata, key, cert):
166166
:param cert: x509 cert
167167
:type cert: string
168168
169+
:param sign_algorithm: Signature algorithm method
170+
:type sign_algorithm: string
171+
169172
:returns: Signed Metadata
170173
:rtype: string
171174
"""
172-
return OneLogin_Saml2_Utils.add_sign(metadata, key, cert)
175+
return OneLogin_Saml2_Utils.add_sign(metadata, key, cert, False, sign_algorithm)
173176

174177
@staticmethod
175178
def add_x509_key_descriptors(metadata, cert=None):

src/onelogin/saml2/settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ def __add_default_values(self):
295295
if 'wantNameIdEncrypted' not in self.__security.keys():
296296
self.__security['wantNameIdEncrypted'] = False
297297

298+
# Signature Algorithm
299+
if 'signatureAlgorithm' not in self.__security.keys():
300+
self.__security['signatureAlgorithm'] = OneLogin_Saml2_Constants.RSA_SHA1
301+
298302
if 'x509cert' not in self.__idp:
299303
self.__idp['x509cert'] = ''
300304
if 'certFingerprint' not in self.__idp:

src/onelogin/saml2/utils.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ def write_temp_file(content):
759759
return f_temp
760760

761761
@staticmethod
762-
def add_sign(xml, key, cert, debug=False):
762+
def add_sign(xml, key, cert, debug=False, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
763763
"""
764764
Adds signature key and senders certificate to an element (Message or
765765
Assertion).
@@ -770,11 +770,14 @@ def add_sign(xml, key, cert, debug=False):
770770
:param key: The private key
771771
:type: string
772772
773+
:param cert: The public
774+
:type: string
775+
773776
:param debug: Activate the xmlsec debug
774777
:type: bool
775778
776-
:param cert: The public
777-
:type: string
779+
:param sign_algorithm: Signature algorithm method
780+
:type sign_algorithm: string
778781
"""
779782
if xml is None or xml == '':
780783
raise Exception('Empty string supplied as input')
@@ -807,7 +810,16 @@ def add_sign(xml, key, cert, debug=False):
807810
xmlsec.set_error_callback(print_xmlsec_errors)
808811

809812
# Sign the metadata with our private key.
810-
signature = Signature(xmlsec.TransformExclC14N, xmlsec.TransformRsaSha1)
813+
sign_algorithm_transform_map = {
814+
OneLogin_Saml2_Constants.DSA_SHA1: xmlsec.TransformDsaSha1,
815+
OneLogin_Saml2_Constants.RSA_SHA1: xmlsec.TransformRsaSha1,
816+
OneLogin_Saml2_Constants.RSA_SHA256: xmlsec.TransformRsaSha256,
817+
OneLogin_Saml2_Constants.RSA_SHA384: xmlsec.TransformRsaSha384,
818+
OneLogin_Saml2_Constants.RSA_SHA512: xmlsec.TransformRsaSha512
819+
}
820+
sign_algorithm_transform = sign_algorithm_transform_map.get(sign_algorithm, xmlsec.TransformRsaSha1)
821+
822+
signature = Signature(xmlsec.TransformExclC14N, sign_algorithm_transform)
811823

812824
issuer = OneLogin_Saml2_Utils.query(elem, '//saml:Issuer')
813825
if len(issuer) > 0:

0 commit comments

Comments
 (0)