From 175a4501aeb963f5a3ee09fa8ff1ef7a9ac5eae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20Wersd=C3=B6rfer?= Date: Thu, 13 Feb 2025 13:11:52 +0100 Subject: [PATCH 1/4] #976 remove import of deprecated cgi module --- src/saml2/httputil.py | 6 ++++-- src/saml2/pack.py | 9 ++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/saml2/httputil.py b/src/saml2/httputil.py index 3ad668b71..80115aaa3 100644 --- a/src/saml2/httputil.py +++ b/src/saml2/httputil.py @@ -1,4 +1,3 @@ -import cgi import hashlib import hmac from http.cookies import SimpleCookie @@ -182,7 +181,10 @@ def extract(environ, empty=False, err=False): :param empty: Stops on empty fields (default: Fault) :param err: Stops on errors in fields (default: Fault) """ - formdata = cgi.parse(environ["wsgi.input"], environ, empty, err) + input_stream = environ["wsgi.input"] + content_length = int(environ.get("CONTENT_LENGTH", 0)) + formdata_bytes = input_stream.read(content_length) + formdata = parse_qs(formdata_bytes.decode('utf-8')) # Remove single entries from lists for key, value in iter(formdata.items()): if len(value) == 1: diff --git a/src/saml2/pack.py b/src/saml2/pack.py index 99c32476b..cee1cf1c8 100644 --- a/src/saml2/pack.py +++ b/src/saml2/pack.py @@ -8,14 +8,9 @@ """ import base64 - - -try: - import html -except Exception: - import cgi as html # type: ignore[no-redef] - +import html import logging + from urllib.parse import urlencode from urllib.parse import urlparse from xml.etree import ElementTree as ElementTree From 39f352a7cdcfe623c31ed6af06caff8121cb1829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20Wersd=C3=B6rfer?= Date: Thu, 13 Feb 2025 17:37:52 +0100 Subject: [PATCH 2/4] #976 need to avoid dbm.sqlite which is default in Python >= 3.13 --- src/saml2/server.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/saml2/server.py b/src/saml2/server.py index 8b5572001..aad3d02af 100644 --- a/src/saml2/server.py +++ b/src/saml2/server.py @@ -55,7 +55,18 @@ } +def _avoid_dbm_sqlite(): + """ + Force dbm.gnu to be used instead of dbm.sqlite because of threading issues when + running idp_server.py. The dbm.sqlite is the default dbm module used by Python >= 3.13 + """ + import dbm.gnu + import dbm + dbm._defaultmod = dbm.gnu + + def _shelve_compat(name, *args, **kwargs): + _avoid_dbm_sqlite() try: return shelve.open(name, *args, **kwargs) except dbm.error[0]: From c1fcef160216de0f949b03dbbff36947ff765f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20Wersd=C3=B6rfer?= Date: Fri, 14 Feb 2025 14:31:33 +0100 Subject: [PATCH 3/4] #976 use dbm.dumb for Python 3.13+ --- src/saml2/server.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/saml2/server.py b/src/saml2/server.py index aad3d02af..2ee4c301f 100644 --- a/src/saml2/server.py +++ b/src/saml2/server.py @@ -4,6 +4,7 @@ """Contains classes and functions that a SAML2.0 Identity provider (IdP) or attribute authority (AA) may use to conclude its tasks. """ +import sys import dbm import importlib import logging @@ -55,20 +56,14 @@ } -def _avoid_dbm_sqlite(): - """ - Force dbm.gnu to be used instead of dbm.sqlite because of threading issues when - running idp_server.py. The dbm.sqlite is the default dbm module used by Python >= 3.13 - """ - import dbm.gnu - import dbm - dbm._defaultmod = dbm.gnu - - def _shelve_compat(name, *args, **kwargs): - _avoid_dbm_sqlite() try: - return shelve.open(name, *args, **kwargs) + if sys.version_info < (3, 13): + return shelve.open(name, *args, **kwargs) + else: + # Python 3.13 and later uses dbm.sqlite3 as default which is not compatible + # with cheroot using threading. So, we need to use dbm.dumb instead. + return shelve.Shelf(dbm.dumb.open(name), *args, **kwargs) except dbm.error[0]: # Python 3 whichdb needs to try .db to determine type if name.endswith(".db"): From 5871dde81fe41e23195f53ca2c4ff280e47a7dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20Wersd=C3=B6rfer?= Date: Tue, 18 Feb 2025 10:48:51 +0100 Subject: [PATCH 4/4] Update src/saml2/httputil.py Co-authored-by: Ivan Kanakarakis --- src/saml2/httputil.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/saml2/httputil.py b/src/saml2/httputil.py index 80115aaa3..c7abc6fdd 100644 --- a/src/saml2/httputil.py +++ b/src/saml2/httputil.py @@ -183,8 +183,8 @@ def extract(environ, empty=False, err=False): """ input_stream = environ["wsgi.input"] content_length = int(environ.get("CONTENT_LENGTH", 0)) - formdata_bytes = input_stream.read(content_length) - formdata = parse_qs(formdata_bytes.decode('utf-8')) + input_data = input_stream.read(content_length).decode('utf-8') + formdata = parse_qs(input_data) # Remove single entries from lists for key, value in iter(formdata.items()): if len(value) == 1: