diff options
author | Scott Koranda <skoranda@gmail.com> | 2017-12-27 15:08:28 -0600 |
---|---|---|
committer | Ivan Kanakarakis <ivan.kanak@gmail.com> | 2018-11-21 17:36:02 +0200 |
commit | 23fe5142709a0894b02b166a84dcead945b0c93e (patch) | |
tree | c0b190173261080637bdd434ebf0458dd4ff1d80 /src/saml2/entity.py | |
parent | 40a3699ef25a514b4a2ba7bf1ce2a0cdb3428abf (diff) | |
download | pysaml2-23fe5142709a0894b02b166a84dcead945b0c93e.tar.gz |
Add want_assertions_or_response_signed functionality
Add the ability to configure an SP to require either a signed response
or signed assertions.
Signed-off-by: Ivan Kanakarakis <ivan.kanak@gmail.com>
Diffstat (limited to 'src/saml2/entity.py')
-rw-r--r-- | src/saml2/entity.py | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/src/saml2/entity.py b/src/saml2/entity.py index 32cf355f..67d42dd0 100644 --- a/src/saml2/entity.py +++ b/src/saml2/entity.py @@ -30,6 +30,7 @@ from saml2.saml import NameID from saml2.saml import EncryptedAssertion from saml2.saml import Issuer from saml2.saml import NAMEID_FORMAT_ENTITY +from saml2.response import AuthnResponse from saml2.response import LogoutResponse from saml2.response import UnsolicitedResponse from saml2.time_util import instant @@ -63,6 +64,7 @@ from saml2.httpbase import HTTPBase from saml2.sigver import security_context from saml2.sigver import response_factory from saml2.sigver import SigverError +from saml2.sigver import SignatureError from saml2.sigver import make_temp from saml2.sigver import pre_encryption_part from saml2.sigver import pre_signature_part @@ -1135,18 +1137,40 @@ class Entity(HTTPBase): if not xmlstr: # Not a valid reponse return None + # Record the response signature requirement. + require_response_signature = response.require_response_signature + + # Force the requirement that the response be signed in order to + # force signature checking to happen so that we can know whether + # or not the response is signed. The attribute on the response class + # is reset to the recorded value in the finally clause below. + response.require_response_signature = True + try: response = response.loads(xmlstr, False, origxml=xmlstr) + response_is_signed = True except SigverError as err: - logger.error("Signature Error: %s", err) - raise + response_is_signed = False + if require_response_signature: + logger.error("Signature Error: %s", err) + raise + else: + # The response is not signed but a signature is not required + # so reset the attribute on the response class to the recorded + # value and attempt to consume the unpacked XML again. + response.require_response_signature = require_response_signature + response = response.loads(xmlstr, False, origxml=xmlstr) + except UnsolicitedResponse: logger.error("Unsolicited response") raise except Exception as err: + response_is_signed = False if "not well-formed" in "%s" % err: logger.error("Not well-formed XML") raise + finally: + response.require_response_signature = require_response_signature logger.debug("XMLSTR: %s", xmlstr) @@ -1166,7 +1190,46 @@ class Entity(HTTPBase): for _cert in cert: keys.append(_cert["key"]) - response = response.verify(keys) + only_identity_in_encrypted_assertion = False + if "only_identity_in_encrypted_assertion" in kwargs: + only_identity_in_encrypted_assertion = kwargs[ + "only_identity_in_encrypted_assertion"] + + # Record the assertions signature requirement. + require_signature = response.require_signature + + # Force the requirement that the assertions be signed in order to + # force signature checking to happen so that we can know whether + # or not the assertions are signed. The attribute on the response class + # is reset to the recorded value in the finally clause below. + response.require_signature = True + + try: + # Verify that the assertion is syntactically correct and the + # signature on the assertion is correct if present. + response = response.verify(keys) + assertions_are_signed = True + except SignatureError as err: + assertions_are_signed = False + if require_signature: + logger.error("Signature Error: %s", err) + raise + else: + response.require_signature = require_signature + response = response.verify(keys) + except Exception as err: + logger.error("Exception verifying assertion: %s" % err) + finally: + response.require_signature = require_signature + + # If so configured enforce that either the response is signed + # or the assertions within it are signed. + if response.require_signature_or_response_signature: + if not response_is_signed and not assertions_are_signed: + msg = "Neither the response nor the assertions are signed" + logger.error(msg) + raise SigverError(msg) + return response # ------------------------------------------------------------------------ |