From 00f20dc8b3126f37c8579e419581db44b14c6d43 Mon Sep 17 00:00:00 2001 From: Vlad Mencl Date: Tue, 9 Jun 2026 09:42:29 +1200 Subject: [PATCH 1/4] fix: use quote instead of quote_plus MDQ spec explicitly asks for spaces to be encoded as %20, not + This is achieved by urllib.parse.quote - the only difference quote_plus brings is it would be encoding spaces as '+': https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote_plus While entityIDs cannot really contain spaces (not permitted in an URI), this is all just a technicality, but quote is the correct function to use. --- src/pyff/api.py | 4 ++-- src/pyff/builtins.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pyff/api.py b/src/pyff/api.py index 4eb751cd..11ae867e 100644 --- a/src/pyff/api.py +++ b/src/pyff/api.py @@ -4,7 +4,7 @@ from datetime import datetime, timedelta from json import dumps from typing import Any, Optional -from urllib.parse import quote_plus +from urllib.parse import quote import pyramid.httpexceptions as exc import pytz @@ -395,7 +395,7 @@ def _links(url: str, title: Any = None) -> None: aliases = request.registry.aliases for a in aliases.keys(): for v in request.registry.md.store.attribute(aliases[a]): - _links(f'{a}/{quote_plus(v)}') + _links(f'{a}/{quote(v)}') response = Response(dumps(jrd, default=json_serializer)) response.headers['Content-Type'] = 'application/json' diff --git a/src/pyff/builtins.py b/src/pyff/builtins.py index d75cfe38..586fac2d 100644 --- a/src/pyff/builtins.py +++ b/src/pyff/builtins.py @@ -16,7 +16,7 @@ from datetime import datetime from io import BytesIO from typing import Optional -from urllib.parse import quote_plus, urlparse +from urllib.parse import quote, urlparse import pybergshamra from pyuppsala import etree @@ -552,7 +552,7 @@ def _nop(x): enc = _nop if req.args.get('urlencode_filenames'): - enc = quote_plus + enc = quote if output_file is None: return req.t From 31f70635961d96913cae271d3cf995bb5f405364 Mon Sep 17 00:00:00 2001 From: Vlad Mencl Date: Tue, 20 Oct 2026 09:29:31 +1300 Subject: [PATCH 2/4] nfc: fix typo in error message Got copy-pasted from set_reginfo below. Here (in set_pubinfo), the element to be inserted is PublicationInfo. --- src/pyff/samlmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyff/samlmd.py b/src/pyff/samlmd.py index 1cc4b8a8..75bfeb03 100644 --- a/src/pyff/samlmd.py +++ b/src/pyff/samlmd.py @@ -1401,7 +1401,7 @@ def set_entity_attributes(e, d, nf=NF_URI): def set_pubinfo(e, publisher=None, creation_instant=None): if e.tag != "{{{}}}EntitiesDescriptor".format(NS['md']): - raise MetadataException("I can only set RegistrationAuthority to EntitiesDescriptor elements") + raise MetadataException("I can only set PublicationInfo to EntitiesDescriptor elements") if publisher is None: raise MetadataException("At least publisher must be provided") From c7fd8381aefe63706f9b193d019706f37b03271c Mon Sep 17 00:00:00 2001 From: Vlad Mencl Date: Tue, 20 Oct 2026 14:24:44 +1300 Subject: [PATCH 3/4] fix: use quote with safe='' There is a difference between quote and quote_plus in default value for safe: * quote defaults to safe='/' (and so would pass '/' without encoding) * quote_plus defaults to safe='' (and so encodes '/') Invoke quote with safe='' to make sure '/' gets encoded. --- src/pyff/api.py | 2 +- src/pyff/builtins.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pyff/api.py b/src/pyff/api.py index 11ae867e..8da2ec59 100644 --- a/src/pyff/api.py +++ b/src/pyff/api.py @@ -395,7 +395,7 @@ def _links(url: str, title: Any = None) -> None: aliases = request.registry.aliases for a in aliases.keys(): for v in request.registry.md.store.attribute(aliases[a]): - _links(f'{a}/{quote(v)}') + _links(f"{a}/{quote(v, safe='')}") response = Response(dumps(jrd, default=json_serializer)) response.headers['Content-Type'] = 'application/json' diff --git a/src/pyff/builtins.py b/src/pyff/builtins.py index 586fac2d..d6e2a09d 100644 --- a/src/pyff/builtins.py +++ b/src/pyff/builtins.py @@ -3,6 +3,7 @@ """ import base64 +import functools import hashlib import ipaddress import json @@ -552,7 +553,7 @@ def _nop(x): enc = _nop if req.args.get('urlencode_filenames'): - enc = quote + enc = functools.partial(quote, safe='') if output_file is None: return req.t From 096fb3bbc098663857d6c85f98652b50f5686ee7 Mon Sep 17 00:00:00 2001 From: Vlad Mencl Date: Wed, 21 Oct 2026 08:51:14 +1300 Subject: [PATCH 4/4] fix: samlmd: allow PublicationInfo also on EntityDescriptor The [spec for Registration and Publication Info extension](https://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/cs01/saml-metadata-rpi-v1.0-cs01.html#_Toc324866169) says PublicationInfo can appear either in EntitiesDescriptor or EntityDescriptor. Allow it so. --- src/pyff/samlmd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyff/samlmd.py b/src/pyff/samlmd.py index 75bfeb03..8856b9ee 100644 --- a/src/pyff/samlmd.py +++ b/src/pyff/samlmd.py @@ -1400,8 +1400,8 @@ def set_entity_attributes(e, d, nf=NF_URI): def set_pubinfo(e, publisher=None, creation_instant=None): - if e.tag != "{{{}}}EntitiesDescriptor".format(NS['md']): - raise MetadataException("I can only set PublicationInfo to EntitiesDescriptor elements") + if e.tag not in ["{{{}}}EntityDescriptor".format(NS['md']), "{{{}}}EntitiesDescriptor".format(NS['md'])]: + raise MetadataException("I can only set PublicationInfo to EntityDescriptor or EntitiesDescriptor elements") if publisher is None: raise MetadataException("At least publisher must be provided")