Skip to content

Commit a6ef115

Browse files
author
Roland Hedberg
committed
Fixed handling of signed and then encrypted response assertions. At the same time added support for dealing with any combination of encrypted/non-encrypted assertions.
1 parent fca906e commit a6ef115

11 files changed

+632
-379
lines changed

src/saml2/assertion.py

Lines changed: 100 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -543,107 +543,109 @@ class EntityCategories(object):
543543
pass
544544

545545

546-
class Assertion(dict):
547-
""" Handles assertions about subjects """
548-
549-
def __init__(self, dic=None):
550-
dict.__init__(self, dic)
551-
self.acs = []
552-
553-
@staticmethod
554-
def _authn_context_decl(decl, authn_auth=None):
555-
"""
556-
Construct the authn context with a authn context declaration
557-
:param decl: The authn context declaration
558-
:param authn_auth: Authenticating Authority
559-
:return: An AuthnContext instance
560-
"""
546+
def _authn_context_class_ref(authn_class, authn_auth=None):
547+
"""
548+
Construct the authn context with a authn context class reference
549+
:param authn_class: The authn context class reference
550+
:param authn_auth: Authenticating Authority
551+
:return: An AuthnContext instance
552+
"""
553+
cntx_class = factory(saml.AuthnContextClassRef, text=authn_class)
554+
if authn_auth:
561555
return factory(saml.AuthnContext,
562-
authn_context_decl=decl,
556+
authn_context_class_ref=cntx_class,
563557
authenticating_authority=factory(
564558
saml.AuthenticatingAuthority, text=authn_auth))
565-
566-
def _authn_context_decl_ref(self, decl_ref, authn_auth=None):
567-
"""
568-
Construct the authn context with a authn context declaration reference
569-
:param decl_ref: The authn context declaration reference
570-
:param authn_auth: Authenticating Authority
571-
:return: An AuthnContext instance
572-
"""
559+
else:
573560
return factory(saml.AuthnContext,
574-
authn_context_decl_ref=decl_ref,
575-
authenticating_authority=factory(
576-
saml.AuthenticatingAuthority, text=authn_auth))
561+
authn_context_class_ref=cntx_class)
577562

578-
@staticmethod
579-
def _authn_context_class_ref(authn_class, authn_auth=None):
580-
"""
581-
Construct the authn context with a authn context class reference
582-
:param authn_class: The authn context class reference
583-
:param authn_auth: Authenticating Authority
584-
:return: An AuthnContext instance
585-
"""
586-
cntx_class = factory(saml.AuthnContextClassRef, text=authn_class)
587-
if authn_auth:
588-
return factory(saml.AuthnContext,
589-
authn_context_class_ref=cntx_class,
590-
authenticating_authority=factory(
591-
saml.AuthenticatingAuthority, text=authn_auth))
592-
else:
593-
return factory(saml.AuthnContext,
594-
authn_context_class_ref=cntx_class)
595-
596-
def _authn_statement(self, authn_class=None, authn_auth=None,
597-
authn_decl=None, authn_decl_ref=None, authn_instant="",
598-
subject_locality=""):
599-
"""
600-
Construct the AuthnStatement
601-
:param authn_class: Authentication Context Class reference
602-
:param authn_auth: Authenticating Authority
603-
:param authn_decl: Authentication Context Declaration
604-
:param authn_decl_ref: Authentication Context Declaration reference
605-
:param authn_instant: When the Authentication was performed.
606-
Assumed to be seconds since the Epoch.
607-
:param subject_locality: Specifies the DNS domain name and IP address
608-
for the system from which the assertion subject was apparently
609-
authenticated.
610-
:return: An AuthnContext instance
611-
"""
612-
if authn_instant:
613-
_instant = instant(time_stamp=authn_instant)
614-
else:
615-
_instant = instant()
616-
617-
if authn_class:
618-
res = factory(
619-
saml.AuthnStatement,
620-
authn_instant=_instant,
621-
session_index=sid(),
622-
authn_context=self._authn_context_class_ref(
623-
authn_class, authn_auth))
624-
elif authn_decl:
625-
res = factory(
626-
saml.AuthnStatement,
627-
authn_instant=_instant,
628-
session_index=sid(),
629-
authn_context=self._authn_context_decl(authn_decl, authn_auth))
630-
elif authn_decl_ref:
631-
res = factory(
632-
saml.AuthnStatement,
633-
authn_instant=_instant,
634-
session_index=sid(),
635-
authn_context=self._authn_context_decl_ref(authn_decl_ref,
636-
authn_auth))
637-
else:
638-
res = factory(
639-
saml.AuthnStatement,
640-
authn_instant=_instant,
641-
session_index=sid())
642563

643-
if subject_locality:
644-
res.subject_locality = saml.SubjectLocality(text=subject_locality)
564+
def _authn_context_decl(decl, authn_auth=None):
565+
"""
566+
Construct the authn context with a authn context declaration
567+
:param decl: The authn context declaration
568+
:param authn_auth: Authenticating Authority
569+
:return: An AuthnContext instance
570+
"""
571+
return factory(saml.AuthnContext,
572+
authn_context_decl=decl,
573+
authenticating_authority=factory(
574+
saml.AuthenticatingAuthority, text=authn_auth))
645575

646-
return res
576+
577+
def _authn_context_decl_ref(decl_ref, authn_auth=None):
578+
"""
579+
Construct the authn context with a authn context declaration reference
580+
:param decl_ref: The authn context declaration reference
581+
:param authn_auth: Authenticating Authority
582+
:return: An AuthnContext instance
583+
"""
584+
return factory(saml.AuthnContext,
585+
authn_context_decl_ref=decl_ref,
586+
authenticating_authority=factory(
587+
saml.AuthenticatingAuthority, text=authn_auth))
588+
589+
590+
def authn_statement(authn_class=None, authn_auth=None,
591+
authn_decl=None, authn_decl_ref=None, authn_instant="",
592+
subject_locality=""):
593+
"""
594+
Construct the AuthnStatement
595+
:param authn_class: Authentication Context Class reference
596+
:param authn_auth: Authenticating Authority
597+
:param authn_decl: Authentication Context Declaration
598+
:param authn_decl_ref: Authentication Context Declaration reference
599+
:param authn_instant: When the Authentication was performed.
600+
Assumed to be seconds since the Epoch.
601+
:param subject_locality: Specifies the DNS domain name and IP address
602+
for the system from which the assertion subject was apparently
603+
authenticated.
604+
:return: An AuthnContext instance
605+
"""
606+
if authn_instant:
607+
_instant = instant(time_stamp=authn_instant)
608+
else:
609+
_instant = instant()
610+
611+
if authn_class:
612+
res = factory(
613+
saml.AuthnStatement,
614+
authn_instant=_instant,
615+
session_index=sid(),
616+
authn_context=_authn_context_class_ref(
617+
authn_class, authn_auth))
618+
elif authn_decl:
619+
res = factory(
620+
saml.AuthnStatement,
621+
authn_instant=_instant,
622+
session_index=sid(),
623+
authn_context=_authn_context_decl(authn_decl, authn_auth))
624+
elif authn_decl_ref:
625+
res = factory(
626+
saml.AuthnStatement,
627+
authn_instant=_instant,
628+
session_index=sid(),
629+
authn_context=_authn_context_decl_ref(authn_decl_ref,
630+
authn_auth))
631+
else:
632+
res = factory(
633+
saml.AuthnStatement,
634+
authn_instant=_instant,
635+
session_index=sid())
636+
637+
if subject_locality:
638+
res.subject_locality = saml.SubjectLocality(text=subject_locality)
639+
640+
return res
641+
642+
643+
class Assertion(dict):
644+
""" Handles assertions about subjects """
645+
646+
def __init__(self, dic=None):
647+
dict.__init__(self, dic)
648+
self.acs = []
647649

648650
def construct(self, sp_entity_id, in_response_to, consumer_url,
649651
name_id, attrconvs, policy, issuer, authn_class=None,
@@ -695,10 +697,10 @@ def construct(self, sp_entity_id, in_response_to, consumer_url,
695697
conds = policy.conditions(sp_entity_id)
696698

697699
if authn_auth or authn_class or authn_decl or authn_decl_ref:
698-
_authn_statement = self._authn_statement(authn_class, authn_auth,
699-
authn_decl, authn_decl_ref,
700-
authn_instant,
701-
subject_locality)
700+
_authn_statement = authn_statement(authn_class, authn_auth,
701+
authn_decl, authn_decl_ref,
702+
authn_instant,
703+
subject_locality)
702704
else:
703705
_authn_statement = None
704706

src/saml2/entity.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -852,14 +852,6 @@ def _parse_response(self, xmlstr, response_cls, service, binding,
852852

853853
xmlstr = self.unravel(xmlstr, binding, response_cls.msgtype)
854854
origxml = xmlstr
855-
if outstanding_certs is not None:
856-
_response = samlp.any_response_from_string(xmlstr)
857-
if len(_response.encrypted_assertion) > 0:
858-
_, cert_file = make_temp(
859-
"%s" % outstanding_certs[
860-
_response.in_response_to]["key"], decode=False)
861-
cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
862-
xmlstr = cbxs.decrypt(xmlstr, cert_file)
863855
if not xmlstr: # Not a valid reponse
864856
return None
865857

@@ -878,18 +870,14 @@ def _parse_response(self, xmlstr, response_cls, service, binding,
878870

879871
logger.debug("XMLSTR: %s" % xmlstr)
880872

881-
if hasattr(response.response, 'encrypted_assertion'):
882-
for encrypted_assertion in response.response.encrypted_assertion:
883-
if encrypted_assertion.extension_elements is not None:
884-
assertion_list = extension_elements_to_elements(
885-
encrypted_assertion.extension_elements, [saml])
886-
for assertion in assertion_list:
887-
_assertion = saml.assertion_from_string(
888-
str(assertion))
889-
response.response.assertion.append(_assertion)
890-
891873
if response:
892-
response = response.verify()
874+
if outstanding_certs is not None:
875+
_, key_file = make_temp(
876+
"%s" % outstanding_certs[
877+
response.in_response_to]["key"], decode=False)
878+
else:
879+
key_file = ""
880+
response = response.verify(key_file)
893881

894882
if not response:
895883
return None

0 commit comments

Comments
 (0)