summaryrefslogtreecommitdiff
path: root/src/saml2/entity.py
diff options
context:
space:
mode:
authorScott Koranda <skoranda@gmail.com>2017-12-27 15:08:28 -0600
committerIvan Kanakarakis <ivan.kanak@gmail.com>2018-11-21 17:36:02 +0200
commit23fe5142709a0894b02b166a84dcead945b0c93e (patch)
treec0b190173261080637bdd434ebf0458dd4ff1d80 /src/saml2/entity.py
parent40a3699ef25a514b4a2ba7bf1ce2a0cdb3428abf (diff)
downloadpysaml2-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.py69
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
# ------------------------------------------------------------------------