diff --git a/src/saml2/metadata.py b/src/saml2/metadata.py
index 5c465032..b2317131 100644
--- a/src/saml2/metadata.py
+++ b/src/saml2/metadata.py
@@ -66,10 +66,10 @@ def metadata_tostring_fix(desc, nspair, xmlstring=""):
     if not xmlstring:
         xmlstring = desc.to_string(nspair)
 
-    if six.PY2:
+    try:
         if "\"xs:string\"" in xmlstring and XMLNSXS not in xmlstring:
             xmlstring = xmlstring.replace(MDNS, MDNS + XMLNSXS)
-    else:
+    except TypeError:
         if b"\"xs:string\"" in xmlstring and bXMLNSXS not in xmlstring:
             xmlstring = xmlstring.replace(bMDNS, bMDNS + bXMLNSXS)
 

make_metadata.py fails to generate signed metadata with Python 3
When using Python 3, `make_metadata.py` and the examples error out when trying to generate signed metadata.

The problem is that [`sign_entity_descriptor()`](https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/metadata.py#L810) returns `str` (from a backend's [`sign_statement()`](https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/sigver.py#L796), which calls `decode()` on the data), and then passes it to [`metadata_tostring_fix()`](https://github.com/IdentityPython/pysaml2/blob/master/src/saml2/metadata.py#L65), which expects it to be a `bytes` in Python 3.

## Code Version
At least 5.0.0, 5.1.0 and current master are affected.

## Expected Behavior
It should not crash.

## Current Behavior
```
Traceback (most recent call last):
  File "./sp.py", line 830, in metadata
    _args.sign,
  File "/home/asdf/pysaml2/venv/lib/python3.7/site-packages/pysaml2-5.1.0-py3.7.egg/saml2/metadata.py", line 113, in create_metadata_string
    return metadata_tostring_fix(eid, nspair, xmldoc)
  File "/home/asdf/pysaml2/venv/lib/python3.7/site-packages/pysaml2-5.1.0-py3.7.egg/saml2/metadata.py", line 73, in metadata_tostring_fix
    if b"\"xs:string\"" in xmlstring and bXMLNSXS not in xmlstring:
TypeError: 'in <string>' requires string as left operand, not bytes
```

## Possible Solution

The backwards-compatible change would probably be to make `metadata_tostring_fix()` accept `str` for Python 3.

The library contains two uses of that function, in `make_metadata.py` and `create_metadata_string()`, both after a call to `sign_entity_descriptor()`. However, in case someone is using `metadata_tostring_fix()` externally, it might be a good idea to make it allow both `bytes` and `str`.

## Steps to Reproduce
1. Run the `sp-wsgi` example using Python 3.
2. Access `http://localhost:8087/metadata`.
3. Observe the error message in the console.

diff --git a/tests/test_39_metadata.py b/tests/test_39_metadata.py
index a3796083..8ab6dfa5 100644
--- a/tests/test_39_metadata.py
+++ b/tests/test_39_metadata.py
@@ -1,7 +1,10 @@
 import copy
 from saml2.config import SPConfig
-from saml2.metadata import entity_descriptor
+from saml2.metadata import create_metadata_string, entity_descriptor
 from saml2.saml import NAME_FORMAT_URI, NAME_FORMAT_BASIC
+from saml2 import sigver
+
+from pathutils import full_path
 
 __author__ = 'roland'
 
@@ -47,5 +50,17 @@ def test_requested_attribute_name_format():
         assert req_attr.name_format == NAME_FORMAT_BASIC
 
 
+def test_signed_metadata_proper_str_bytes_handling():
+    sp_conf_2 = sp_conf.copy()
+    sp_conf_2['key_file'] = full_path("test.key")
+    sp_conf_2['cert_file'] = full_path("inc-md-cert.pem")
+    # requires xmlsec binaries per https://pysaml2.readthedocs.io/en/latest/examples/sp.html
+    sp_conf_2['xmlsec_binary'] = sigver.get_xmlsec_binary(["/opt/local/bin"])
+    cnf = SPConfig().load(sp_conf_2, metadata_construction=True)
+
+    # This will raise TypeError if string/bytes handling is not correct
+    sp_metadata = create_metadata_string('', config=cnf, sign=True)
+
+
 if __name__ == '__main__':
-    test_requested_attribute_name_format()
\ No newline at end of file
+    test_requested_attribute_name_format()

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov
apt-get update apt-get install -y gcc xmlsec1
3.8
example/requirements.txt tests/test-requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
autocommand==2.2.2
backports.tarfile==1.2.0
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
cheroot==10.0.1
CherryPy==18.10.0
coverage==7.6.1
cryptography==44.0.2
defusedxml==0.7.1
dnspython==2.6.1
exceptiongroup==1.2.2
idna==3.10
importlib_resources==6.4.5
iniconfig==2.1.0
jaraco.collections==5.1.0
jaraco.context==6.0.1
jaraco.functools==4.1.0
jaraco.text==4.0.0
Mako==1.3.9
MarkupSafe==2.1.5
mock==5.2.0
more-itertools==10.5.0
packaging==24.2
pluggy==1.5.0
portend==3.2.0
pyasn1==0.6.1
pycparser==2.22
pymongo==4.10.1
pyOpenSSL==25.0.0
-e git+https://github.com/IdentityPython/pysaml2.git@8e0582ad87307f59370028ca93a4aa6f1bdc10a4#egg=pysaml2
pytest==8.3.5
pytest-cov==5.0.0
python-dateutil==2.9.0.post0
pytz==2025.2
PyYAML==6.0.2
requests==2.32.3
responses==0.25.7
six==1.17.0
tempora==5.7.1
tomli==2.2.1
typing_extensions==4.13.0
urllib3==2.2.3
zc.lockfile==3.0.post1
zipp==3.20.2

name: pysaml2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=24.2=py38h06a4308_0
  - python=3.8.20=he870216_0
  - readline=8.2=h5eee18b_0
  - setuptools=75.1.0=py38h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.44.0=py38h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - autocommand==2.2.2
      - backports-tarfile==1.2.0
      - certifi==2025.1.31
      - cffi==1.17.1
      - charset-normalizer==3.4.1
      - cheroot==10.0.1
      - cherrypy==18.10.0
      - coverage==7.6.1
      - cryptography==44.0.2
      - defusedxml==0.7.1
      - dnspython==2.6.1
      - exceptiongroup==1.2.2
      - idna==3.10
      - importlib-resources==6.4.5
      - iniconfig==2.1.0
      - jaraco-collections==5.1.0
      - jaraco-context==6.0.1
      - jaraco-functools==4.1.0
      - jaraco-text==4.0.0
      - mako==1.3.9
      - markupsafe==2.1.5
      - mock==5.2.0
      - more-itertools==10.5.0
      - packaging==24.2
      - pluggy==1.5.0
      - portend==3.2.0
      - pyasn1==0.6.1
      - pycparser==2.22
      - pymongo==4.10.1
      - pyopenssl==25.0.0
      - pysaml2==5.3.0
      - pytest==8.3.5
      - pytest-cov==5.0.0
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyyaml==6.0.2
      - requests==2.32.3
      - responses==0.25.7
      - six==1.17.0
      - tempora==5.7.1
      - tomli==2.2.1
      - typing-extensions==4.13.0
      - urllib3==2.2.3
      - zc-lockfile==3.0.post1
      - zipp==3.20.2
prefix: /opt/conda/envs/pysaml2

tests/test_39_metadata.py::test_signed_metadata_proper_str_bytes_handling
tests/test_39_metadata.py::test_requested_attribute_name_format
src/saml2/metadata.py
src/saml2/metadata.py