Skip to content

Commit e00eb9e

Browse files
Merge commit from fork
* Security: in summary serializer only allow access to metadata that is available in the catalog. * add RESTAPI_EXTRA_NON_METADATA_ATTRIBUTES environment --------- Co-authored-by: Mauro Amico <mauro.amico@gmail.com>
1 parent bf963e9 commit e00eb9e

3 files changed

Lines changed: 35 additions & 7 deletions

File tree

news/+6263b817.bugfix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security: in summary serializer only allow access to metadata that is available in the catalog.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add support for the `RESTAPI_ADDITIONAL_NON_METADATA_ATTRIBUTES` environment variable, a comma-separated list of extra attribute names appended to the summary serializer's `non_metadata_attributes`.

src/plone/restapi/serializer/summary.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212
from zope.interface import implementer
1313
from zope.interface import Interface
1414

15+
import logging
16+
import os
17+
18+
19+
logger = logging.getLogger(__name__)
20+
21+
ADDITIONAL_NON_METADATA_ATTRIBUTES = {
22+
attr.strip()
23+
for attr in os.environ.get("RESTAPI_ADDITIONAL_NON_METADATA_ATTRIBUTES", "").split(
24+
","
25+
)
26+
if attr.strip()
27+
}
28+
1529

1630
@implementer(IJSONSummarySerializerMetadata)
1731
class JSONSummarySerializerMetadata:
@@ -30,7 +44,7 @@ def non_metadata_attributes(self):
3044
return {
3145
"getPath",
3246
"getURL",
33-
}
47+
} | ADDITIONAL_NON_METADATA_ATTRIBUTES
3448

3549
def blocklisted_attributes(self):
3650
return {
@@ -112,14 +126,26 @@ def metadata_fields(self):
112126
if not isinstance(additional_metadata_fields, list):
113127
additional_metadata_fields = [additional_metadata_fields]
114128
additional_metadata_fields = set(additional_metadata_fields)
115-
129+
if not additional_metadata_fields:
130+
return self.default_metadata_fields
131+
132+
fields_cache = self.request.get("_summary_fields_cache", None)
133+
if fields_cache is None:
134+
catalog = getToolByName(self.context, "portal_catalog")
135+
fields_cache = set(catalog.schema()) | self.non_metadata_attributes
136+
self.request.set("_summary_fields_cache", fields_cache)
116137
if "_all" in additional_metadata_fields:
117-
fields_cache = self.request.get("_summary_fields_cache", None)
118-
if fields_cache is None:
119-
catalog = getToolByName(self.context, "portal_catalog")
120-
fields_cache = set(catalog.schema()) | self.non_metadata_attributes
121-
self.request.set("_summary_fields_cache", fields_cache)
122138
additional_metadata_fields = fields_cache
139+
else:
140+
rejected_metadata_fields = additional_metadata_fields - fields_cache
141+
if rejected_metadata_fields:
142+
logger.debug(
143+
"Rejected metadata_fields %s requested for %s: not available "
144+
"in the catalog schema or non_metadata_attributes.",
145+
sorted(rejected_metadata_fields),
146+
self.context,
147+
)
148+
additional_metadata_fields = additional_metadata_fields & fields_cache
123149

124150
return self.default_metadata_fields | additional_metadata_fields
125151

0 commit comments

Comments
 (0)