Hello community,

here is the log from the commit of package python-pysaml2 for openSUSE:Factory 
checked in at 2020-07-14 07:56:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pysaml2 (Old)
 and      /work/SRC/openSUSE:Factory/.python-pysaml2.new.3060 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pysaml2"

Tue Jul 14 07:56:25 2020 rev:17 rq:820096 version:5.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pysaml2/python-pysaml2.changes    
2020-06-15 20:28:54.454041131 +0200
+++ /work/SRC/openSUSE:Factory/.python-pysaml2.new.3060/python-pysaml2.changes  
2020-07-14 07:58:46.297689005 +0200
@@ -1,0 +2,9 @@
+Fri Jul 10 12:29:12 UTC 2020 - Dirk Mueller <[email protected]>
+
+- update to 5.3.0:
+  - Fix check for nameid_format set to the string "None" in the configuration
+  - Fix presence of empty eIDAS RequestedAttributes element on AuthnRequest
+  - Refactor create_authn_request method to be easier to reason about
+  - Fix NameIDPolicy checks for allowed Format and allowCreate values
+
+-------------------------------------------------------------------

Old:
----
  v5.1.0.tar.gz

New:
----
  v5.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pysaml2.spec ++++++
--- /var/tmp/diff_new_pack.7YHOWo/_old  2020-07-14 07:58:48.105694860 +0200
+++ /var/tmp/diff_new_pack.7YHOWo/_new  2020-07-14 07:58:48.109694872 +0200
@@ -20,7 +20,7 @@
 %global modname pysaml2
 %global skip_python2 1
 Name:           python-pysaml2
-Version:        5.1.0
+Version:        5.3.0
 Release:        0
 Summary:        Python implementation of SAML Version 2 to be used in a WSGI 
environment
 License:        Apache-2.0

++++++ v5.1.0.tar.gz -> v5.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysaml2-5.1.0/CHANGELOG.md 
new/pysaml2-5.3.0/CHANGELOG.md
--- old/pysaml2-5.1.0/CHANGELOG.md      2020-06-09 13:03:44.000000000 +0200
+++ new/pysaml2-5.3.0/CHANGELOG.md      2020-06-25 19:31:48.000000000 +0200
@@ -1,5 +1,17 @@
 # Changelog
 
+## 5.3.0 (2020-06-25)
+
+- Fix check for nameid_format set to the string "None" in the configuration
+
+
+## 5.2.0 (2020-06-23)
+
+- Fix presence of empty eIDAS RequestedAttributes element on AuthnRequest
+- Refactor create_authn_request method to be easier to reason about
+- Fix NameIDPolicy checks for allowed Format and allowCreate values
+
+
 ## 5.1.0 (2020-06-09)
 
 - support eIDAS RequestedAttributes per AuthnRequest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysaml2-5.1.0/VERSION new/pysaml2-5.3.0/VERSION
--- old/pysaml2-5.1.0/VERSION   2020-06-09 13:03:44.000000000 +0200
+++ new/pysaml2-5.3.0/VERSION   2020-06-25 19:31:48.000000000 +0200
@@ -1 +1 @@
-5.1.0
+5.3.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pysaml2-5.1.0/src/saml2/client_base.py 
new/pysaml2-5.3.0/src/saml2/client_base.py
--- old/pysaml2-5.1.0/src/saml2/client_base.py  2020-06-09 13:03:44.000000000 
+0200
+++ new/pysaml2-5.3.0/src/saml2/client_base.py  2020-06-25 19:31:48.000000000 
+0200
@@ -14,6 +14,7 @@
 
 from saml2.mdstore import destinations
 from saml2.profile import paos, ecp
+from saml2.saml import NAMEID_FORMAT_PERSISTENT
 from saml2.saml import NAMEID_FORMAT_TRANSIENT
 from saml2.samlp import AuthnQuery, RequestedAuthnContext
 from saml2.samlp import NameIDMappingRequest
@@ -90,6 +91,52 @@
     pass
 
 
+def create_requested_attribute_node(requested_attrs, attribute_converters):
+    items = []
+    for attr in requested_attrs:
+        friendly_name = attr.get('friendly_name')
+        name = attr.get('name')
+        name_format = attr.get('name_format')
+        is_required = str(attr.get('required', False)).lower()
+
+        if not name and not friendly_name:
+            raise ValueError("Missing required attribute: 'name' or 
'friendly_name'")
+
+        if not name:
+            for converter in attribute_converters:
+                try:
+                    name = converter._to[friendly_name.lower()]
+                except KeyError:
+                    continue
+                else:
+                    if not name_format:
+                        name_format = converter.name_format
+                    break
+
+        if not friendly_name:
+            for converter in attribute_converters:
+                try:
+                    friendly_name = converter._fro[name.lower()]
+                except KeyError:
+                    continue
+                else:
+                    if not name_format:
+                        name_format = converter.name_format
+                    break
+
+        items.append(
+            RequestedAttribute(
+                is_required=is_required,
+                name_format=name_format,
+                friendly_name=friendly_name,
+                name=name,
+            )
+        )
+
+    node = RequestedAttributes(extension_elements=items)
+    return node
+
+
 class Base(Entity):
     """ The basic pySAML2 service provider class """
 
@@ -261,120 +308,90 @@
         :return: either a tuple of request ID and <samlp:AuthnRequest> instance
                  or a tuple of request ID and str when sign is set to True
         """
-        client_crt = None
-        if "client_crt" in kwargs:
-            client_crt = kwargs["client_crt"]
-
         args = {}
 
-        if self.config.getattr('hide_assertion_consumer_service', 'sp'):
+        # AssertionConsumerServiceURL
+        # AssertionConsumerServiceIndex
+        hide_assertion_consumer_service = 
self.config.getattr('hide_assertion_consumer_service', 'sp')
+        assertion_consumer_service_url = (
+            kwargs.pop("assertion_consumer_service_urls", [None])[0]
+            or kwargs.pop("assertion_consumer_service_url", None)
+        )
+        assertion_consumer_service_index = 
kwargs.pop("assertion_consumer_service_index", None)
+        service_url = (self.service_urls(service_url_binding or binding) or 
[None])[0]
+        if hide_assertion_consumer_service:
             args["assertion_consumer_service_url"] = None
             binding = None
-        else:
-            try:
-                args["assertion_consumer_service_url"] = kwargs[
-                    "assertion_consumer_service_urls"][0]
-                del kwargs["assertion_consumer_service_urls"]
-            except KeyError:
-                try:
-                    args["assertion_consumer_service_url"] = kwargs[
-                        "assertion_consumer_service_url"]
-                    del kwargs["assertion_consumer_service_url"]
-                except KeyError:
-                    try:
-                        args["assertion_consumer_service_index"] = str(
-                            kwargs["assertion_consumer_service_index"])
-                        del kwargs["assertion_consumer_service_index"]
-                    except KeyError:
-                        if service_url_binding is None:
-                            service_urls = self.service_urls(binding)
-                        else:
-                            service_urls = 
self.service_urls(service_url_binding)
-                        args["assertion_consumer_service_url"] = 
service_urls[0]
-
-        try:
-            args["provider_name"] = kwargs["provider_name"]
-        except KeyError:
-            if binding == BINDING_PAOS:
-                pass
-            else:
-                args["provider_name"] = self._my_name()
+        elif assertion_consumer_service_url:
+            args["assertion_consumer_service_url"] = 
assertion_consumer_service_url
+        elif assertion_consumer_service_index:
+            args["assertion_consumer_service_index"] = 
assertion_consumer_service_index
+        elif service_url:
+            args["assertion_consumer_service_url"] = service_url
+
+        # ProviderName
+        provider_name = kwargs.get("provider_name")
+        if not provider_name and binding != BINDING_PAOS:
+            provider_name = self._my_name()
+        args["provider_name"] = provider_name
 
         # Allow argument values either as class instances or as dictionaries
         # all of these have cardinality 0..1
         _msg = AuthnRequest()
-        for param in ["scoping", "requested_authn_context", "conditions",
-                      "subject"]:
-            try:
-                _item = kwargs[param]
-            except KeyError:
-                pass
+        for param in ["scoping", "requested_authn_context", "conditions", 
"subject"]:
+            _item = kwargs.pop(param, None)
+            if not _item:
+                continue
+
+            if isinstance(_item, _msg.child_class(param)):
+                args[param] = _item
+            elif isinstance(_item, dict):
+                args[param] = RequestedAuthnContext(**_item)
             else:
-                del kwargs[param]
-                # either class instance or argument dictionary
-                if isinstance(_item, _msg.child_class(param)):
-                    args[param] = _item
-                elif isinstance(_item, dict):
-                    args[param] = RequestedAuthnContext(**_item)
-                else:
-                    raise ValueError("%s or wrong type expected %s" % (_item,
-                                                                       param))
-
-        try:
-            args["name_id_policy"] = kwargs["name_id_policy"]
-            del kwargs["name_id_policy"]
-        except KeyError:
-            if allow_create is None:
-                allow_create = 
self.config.getattr("name_id_format_allow_create", "sp")
-                if allow_create is None:
-                    allow_create = "false"
-                else:
-                    if allow_create is True:
-                        allow_create = "true"
-                    else:
-                        allow_create = "false"
+                raise ValueError("Wrong type for param 
{name}".format(name=param))
 
-            if nameid_format == "":
-                name_id_policy = None
-            else:
-                if nameid_format is None:
-                    nameid_format = self.config.getattr("name_id_format", "sp")
+        # NameIDPolicy
+        nameid_format_config = self.config.getattr("name_id_format", "sp")
+        nameid_format_config = (
+            nameid_format_config[0]
+            if isinstance(nameid_format_config, list)
+            else nameid_format_config
+        )
+        nameid_format = (
+            nameid_format
+            if nameid_format is not None
+            else NAMEID_FORMAT_TRANSIENT
+            if nameid_format_config is None
+            else None
+            if nameid_format_config == 'None'
+            else nameid_format_config
+        )
 
-                    # If no nameid_format has been set in the configuration
-                    # or passed in then transient is the default.
-                    if nameid_format is None:
-                        # SAML 2.0 errata says AllowCreate MUST NOT be used for
-                        # transient ids - to make a conservative change this is
-                        # only applied for the default cause
-                        allow_create = None
-                        nameid_format = NAMEID_FORMAT_TRANSIENT
-
-                    # If a list has been configured or passed in choose the
-                    # first since NameIDPolicy can only have one format 
specified.
-                    elif isinstance(nameid_format, list):
-                        nameid_format = nameid_format[0]
-
-                    # Allow a deployer to signal that no format should be 
specified
-                    # in the NameIDPolicy by passing in or configuring the 
string 'None'.
-                    elif nameid_format == 'None':
-                        nameid_format = None
+        allow_create_config = 
self.config.getattr("name_id_format_allow_create", "sp")
+        allow_create = (
+            None
+            # SAML 2.0 errata says AllowCreate MUST NOT be used for transient 
ids
+            if nameid_format == NAMEID_FORMAT_TRANSIENT
+            else allow_create
+            if allow_create is not None
+            else str(bool(allow_create_config)).lower()
+        )
 
-                name_id_policy = samlp.NameIDPolicy(allow_create=allow_create,
-                                                    format=nameid_format)
+        name_id_policy = (
+            kwargs.pop("name_id_policy", None)
+            if "name_id_policy" in kwargs
+            else None
+            if nameid_format == ""
+            else samlp.NameIDPolicy(allow_create=allow_create, 
format=nameid_format)
+        )
 
-            if name_id_policy and vorg:
-                try:
-                    name_id_policy.sp_name_qualifier = vorg
-                    name_id_policy.format = saml.NAMEID_FORMAT_PERSISTENT
-                except KeyError:
-                    pass
-            args["name_id_policy"] = name_id_policy
+        if name_id_policy and vorg:
+            name_id_policy.sp_name_qualifier = vorg
+            name_id_policy.format = nameid_format or NAMEID_FORMAT_PERSISTENT
 
-        try:
-            nsprefix = kwargs["nsprefix"]
-        except KeyError:
-            nsprefix = None
+        args["name_id_policy"] = name_id_policy
 
+        # eIDAS SPType
         conf_sp_type = self.config.getattr('sp_type', 'sp')
         conf_sp_type_in_md = self.config.getattr('sp_type_in_metadata', 'sp')
         if conf_sp_type and conf_sp_type_in_md is False:
@@ -383,63 +400,21 @@
             item = sp_type.SPType(text=conf_sp_type)
             extensions.add_extension_element(item)
 
+        # eIDAS RequestedAttributes
         requested_attrs = (
             requested_attributes
             or self.config.getattr('requested_attributes', 'sp')
             or []
         )
-
-        if not extensions:
-            extensions = Extensions()
-
-        items = []
-        for attr in requested_attrs:
-            friendly_name = attr.get('friendly_name')
-            name = attr.get('name')
-            name_format = attr.get('name_format')
-            is_required = str(attr.get('required', False)).lower()
-
-            if not name and not friendly_name:
-                raise ValueError(
-                    "Missing required attribute: '{}' or '{}'".format(
-                        'name', 'friendly_name'
-                    )
-                )
-
-            if not name:
-                for converter in self.config.attribute_converters:
-                    try:
-                        name = converter._to[friendly_name.lower()]
-                    except KeyError:
-                        continue
-                    else:
-                        if not name_format:
-                            name_format = converter.name_format
-                        break
-
-            if not friendly_name:
-                for converter in self.config.attribute_converters:
-                    try:
-                        friendly_name = converter._fro[name.lower()]
-                    except KeyError:
-                        continue
-                    else:
-                        if not name_format:
-                            name_format = converter.name_format
-                        break
-
-            items.append(
-                RequestedAttribute(
-                    is_required=is_required,
-                    name_format=name_format,
-                    friendly_name=friendly_name,
-                    name=name,
-                )
+        if requested_attrs:
+            req_attrs_node = create_requested_attribute_node(
+                requested_attrs, self.config.attribute_converters
             )
+            if not extensions:
+                extensions = Extensions()
+            extensions.add_extension_element(req_attrs_node)
 
-        item = RequestedAttributes(extension_elements=items)
-        extensions.add_extension_element(item)
-
+        # ForceAuthn
         force_authn = str(
             kwargs.pop("force_authn", None)
             or self.config.getattr("force_authn", "sp")
@@ -452,28 +427,50 @@
                 AuthnRequest(), extensions, **kwargs
             )
             args.update(_args)
-
         args.pop("id", None)
 
-        if sign is None:
-            sign = self.authn_requests_signed
+        client_crt = kwargs.get("client_crt")
+        nsprefix = kwargs.get("nsprefix")
+        sign = self.authn_requests_signed if sign is None else sign
 
         if (sign and self.sec.cert_handler.generate_cert()) or client_crt is 
not None:
             with self.lock:
                 self.sec.cert_handler.update_cert(True, client_crt)
                 if client_crt is not None:
                     sign_prepare = True
-                return self._message(AuthnRequest, destination, message_id,
-                                     consent, extensions, sign, sign_prepare,
-                                     protocol_binding=binding,
-                                     scoping=scoping, nsprefix=nsprefix,
-                                     sign_alg=sign_alg, digest_alg=digest_alg,
-                                     **args)
-        return self._message(AuthnRequest, destination, message_id, consent,
-                             extensions, sign, sign_prepare,
-                             protocol_binding=binding,
-                             scoping=scoping, nsprefix=nsprefix,
-                             sign_alg=sign_alg, digest_alg=digest_alg, **args)
+                msg = self._message(
+                    AuthnRequest,
+                    destination,
+                    message_id,
+                    consent,
+                    extensions,
+                    sign,
+                    sign_prepare,
+                    protocol_binding=binding,
+                    scoping=scoping,
+                    nsprefix=nsprefix,
+                    sign_alg=sign_alg,
+                    digest_alg=digest_alg,
+                    **args,
+                )
+        else:
+            msg = self._message(
+                AuthnRequest,
+                destination,
+                message_id,
+                consent,
+                extensions,
+                sign,
+                sign_prepare,
+                protocol_binding=binding,
+                scoping=scoping,
+                nsprefix=nsprefix,
+                sign_alg=sign_alg,
+                digest_alg=digest_alg,
+                **args,
+            )
+
+        return msg
 
     def create_attribute_query(self, destination, name_id=None,
             attribute=None, message_id=0, consent=None,


Reply via email to