Problem/Motivation

Per #3035979-141: [DISCUSSION] Should a facility be added to JSON:API which limits automatic exposure of all entities:

I asked the security team about #3035979-131: [DISCUSSION] Should a facility be added to JSON:API which limits automatic exposure of all entities proposal 1 (GET-only by default, but a configuration change can enable the current behavior with write access), and the nine team members who responded were all in favor of that proposal. (Didn't hear yet from @greggles or @samuel.mortenson who've given ongoing feedback here on the issue.)

The proposal hardens Drupal against most more serious attacks by default, and can also be used to switch an existing site back into read-only mode in case of emergency. There's still a decent risk of information disclosure, but such vulnerabilities are generally less serious. (While SA-CORE-2019-003 was exploitable over GET for core REST, that is definitely the exception rather than the rule.)

Marking RTBC since the JSON:API maintainers, the release managers, and at least a substantial portion of the security team can live with this compromise. (Not marking "Fixed" just yet so that others have a bit more time to respond, but note that unless we hear otherwise we'll go ahead and start implementing this proposal soon, probably first thing tomorrow, EU-time).

Note that the scope of the proposed resolution is significantly smaller than #2957061: A read only mode so that the security team could potentially recommend a course of action for sites that cannot be updated at the very moment a security fix is released, so we will probably want a new implementation issue for the "GET-only by default" proposal. The implementation issue can discuss implementation details, specifics of the UI, how to warn users of the implications of enabling write access, etc. It should also receive usability review.

Proposed resolution

Add a read-only mode to JSON:API.

  • When it's enabled, it does what it says. Everything is read-only.
  • When it's off, it's just like JSON:API today.
  • The default would be read-only "on".

BC break: none, we'll add an update path that automatically sets it to "off" for existing installs, resulting in existing installs undergoing zero functional change.

Remaining tasks

  1. Patch implementing UI + config
  2. UX team sign-off
  3. Patch making JSON:API respecting the config
  4. Update path: create this configuration on existing JSON:API sites, default to "off" to not break those sites
  5. Followups needed:
  6. RTBC
  7. Commit

User interface changes

The first and only HTML UI is added:

it's accessible via the same UI where other web services are configured:

API changes

Data model changes

The first and only piece of configuration is added.

CommentFileSizeAuthor
#88 3039568-88.patch31.13 KBwim leers
#88 interdiff.txt504 byteswim leers
#48 3039568-47.patch26.73 KBwim leers
#48 interdiff.txt3.22 KBwim leers
#48 interdiff-41.txt1.19 KBwim leers
#48 interdiff-39.txt996 byteswim leers
#48 Screenshot 2019-03-13 at 09.32.29.png249.5 KBwim leers
#36 Screenshot 2019-03-13 at 01.46.16.png227.47 KBwim leers
#36 3039568-35.patch25.87 KBwim leers
#36 interdiff.txt1.5 KBwim leers
#33 3039568-33.patch25.92 KBwim leers
#33 interdiff.txt1.43 KBwim leers
#32 3039568-30.patch25.91 KBwim leers
#32 interdiff.txt1.09 KBwim leers
#32 Screenshot 2019-03-13 at 00.54.01.png220.47 KBwim leers
#27 3039568-27.patch25.88 KBwim leers
#27 interdiff.txt1015 byteswim leers
#17 3039568-17.patch25.74 KBwim leers
#17 interdiff.txt11.62 KBwim leers
#17 Screenshot 2019-03-13 at 00.18.21.png216.74 KBwim leers
#16 3039568-13.patch25.74 KBwim leers
#16 interdiff.txt11.62 KBwim leers
#12 3039568-11.patch15.08 KBwim leers
#12 interdiff.txt1.1 KBwim leers
#10 3039568-10.patch15 KBwim leers
#10 interdiff.txt1.32 KBwim leers
#10 Screenshot 2019-03-12 at 23.50.08.png216.72 KBwim leers
#9 3039568-5.patch14.69 KBwim leers
#9 interdiff.txt9.42 KBwim leers
#3 3039568-3.patch6.02 KBwim leers
#3 interdiff.txt2.96 KBwim leers
#2 Screenshot 2019-03-12 at 20.42.40.png273.38 KBwim leers
#2 Screenshot 2019-03-12 at 20.41.59.png202.4 KBwim leers
#2 3039568-2.patch3.08 KBwim leers
#55 Screenshot 2019-03-13 at 10.34.16.png246.72 KBwim leers
#55 interdiff.txt2.59 KBwim leers
#55 3039568-54.patch26.71 KBwim leers
#60 interdiff.txt3.81 KBwim leers
#60 3039568-60.patch30.46 KBwim leers
#63 interdiff.txt1.37 KBwim leers
#63 3039568-61.patch30.4 KBwim leers
#63 Screenshot 2019-03-13 at 15.15.18.png242.88 KBwim leers
#67 interdiff.txt1.19 KBwim leers
#67 3039568-67.patch30.29 KBwim leers
#67 Screenshot 2019-03-13 at 17.05.02.png208.24 KBwim leers
#75 interdiff.txt2.7 KBwim leers
#75 3039568-75.patch30.29 KBwim leers
#76 interdiff-tests.txt4.84 KBwim leers
#76 3039568-76-tests-only-FAIL.patch30.72 KBwim leers
#76 interdiff-fix.txt2.15 KBwim leers
#76 interdiff.txt6.96 KBwim leers
#76 3039568-76.patch30.81 KBwim leers
#79 interdiff.txt1.1 KBwim leers
#79 3039568-79.patch30.94 KBwim leers
#85 interdiff.txt9.17 KBwim leers
#85 3039568-85.patch32.11 KBwim leers
#87 interdiff.txt1.31 KBwim leers
#87 3039568-86.patch31.1 KBwim leers

Comments

Wim Leers created an issue. See original summary.

wim leers’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new3.08 KB
new202.4 KB
new273.38 KB

Initial patch, with UI + configuration.

wim leers’s picture

Issue summary: View changes
StatusFileSize
new2.96 KB
new6.02 KB

This makes JSON:API respect the configuration. Note that tests aren't yet updated, so this should cause a massive number of test failures, since the tests do still assume that writes are enabled by default.

Status: Needs review » Needs work

The last submitted patch, 3: 3039568-3.patch, failed testing. View results

e0ipso’s picture

Off to a great start!

  1. +++ b/jsonapi.routing.yml
    @@ -1,2 +1,10 @@
    +  path: '/admin/config/services/jsonapi'
    

    This collides with JSON:API Extras. I think it's OK, we can work it out there. Can you open an issue to make sure that happens?

  2. +++ b/jsonapi.routing.yml
    @@ -1,2 +1,10 @@
    +    _title: 'JSON:API'
    

    Let's make a not about Read-Only in the page title to show that there should not be scope creep in this config screen.

  3. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,66 @@
    + * Filters routes based on the HTTP method.
    

    … and the configuration flag.

  4. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,66 @@
    +      if ($route->hasDefault(Routes::JSON_API_ROUTE_FLAG_KEY) && $route->getMethods() !== ['GET']) {
    

    We probably want to include ['GET', 'HEAD', 'OPTIONS', 'TRACE'] here.

    $is_read_only_route = array_reduce($route->getMethods(), function ($read_only, $method) {
      return $read_only && in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE']);
    }, TRUE);
    if (… && $is_read_only_route)
    
e0ipso’s picture

Two general comments.

  1. Aside from fixing the tests we also need the hook_update (just making sure we don't forget).
  2. If this is a JSON:API-specific fix (still puzzled about that), doesn't it make more sense to use ResourceTypeRepository::isMutableResourceType? That'll simplify the patch quite a bit.
effulgentsia’s picture

[/admin/config/services/jsonapi] collides with JSON:API Extras. I think it's OK, we can work it out there. Can you open an issue to make sure that happens?

What about keeping the path the same, and having JSON:API Extras form_alter the form to add all of its stuff to it? In which case,

+++ b/jsonapi.links.menu.yml
@@ -0,0 +1,5 @@
+  description: "Enable or disable JSON:API's read-only mode."

Should this description be more generic, like "Configure JSON:API"?

Alternatively, maybe we keep this description as-is, and make it JSON:API Extras's responsibility to alter it to the more generic one?

e0ipso’s picture

What about keeping the path the same, and having JSON:API Extras form_alter the form to add all of its stuff to it? In which case,

I thought about this, but I want this screen / setting to be dead simple and uncluttered.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new9.42 KB
new14.69 KB

This should make most tests pass. (All if I'm lucky enough to not have missed a spot, but I'll let DrupalCI run the entire test suite instead of my machine.)

wim leers’s picture

Issue summary: View changes
StatusFileSize
new216.72 KB
new1.32 KB
new15 KB

Talked to @xjm, she told me about the outcome of the UX team meeting. I made three changes in response to that:

  1. From a checkbox to radios.
  2. Used the suggested labels
  3. Improved description on the form.

I pushed back against two things:

  1. Storing as a string instead of a boolean to allow contrib to add additional (probably more granular) states does not make sense for four reasons:
    1. It makes it harder to move this HTTP API read-only mode out of JSON:API and into core.
    2. Any contrib module that would use this could then easily break JSON:API, by failing to change the value back to one of the two allowed values of JSON:API. (Not to mention it makes the config schema ineffective.)
    3. Any contrib module wanting to provide more granular measures of control besides the two could easily form alter this setting away, and undo the service decoration that #3 added, to instead impose its own restrictions of its own making, on its own terms, with its own config schema.
  2. Making the text in https://www.drupal.org/files/issues/2019-03-12/Screenshot%202019-03-12%2... more generic to make it more sensible to let contrib modules add additional configuration was another request. But look at "RSS publishing" just below, that also specifically lists every setting you can change. Same for "URL aliases". Same for "Languages". Same for "Content language". The "REST" example is a bad one, since that is not core, but https://www.drupal.org/project/restui (that module has all sorts of UX problems…).

    Besides, if a contrib module truly wants to alter that form, then they can also alter this description.

Before
After
xjm’s picture

Thanks @Wim Leers!

UX contributors who should be credited:
webchick, benjifisher, jhodgdon, Gábor Hojtsy, xjm, phenaproxima, ckrina, effulgentsia, wordlinemine

One thing I can't remember now whether Wim and I discussed is also potentially adding a line to the hook_help() about it, but that's less important than the in-context docs on the form.

Other things discussed with UX team that we won't implement at this point (in addition to the things Wim pushed back on above):

  1. We discussed adding a status report info message (or worldlinemine was suggesting a warning), but we should scope that to a followup since the radio is the essential change.
  2. We discussed listing the specific resources that were exposed and how in a table below the main form, to help the site owner understand the implications of their choice, but that should also be scoped to a followup.
  3. The UX team all agreed not to add any kind of confirm form since it would be redundant "Cover Your Access-control". ;)
wim leers’s picture

StatusFileSize
new1.1 KB
new15.08 KB

#5:

  1. Done: #3039600: Update JSON:API Extras' route for compatibility with JSON:API 2.4.
  2. Hah, I like that. But that would be inconsistent with other things on the /admin/config page. Furthermore, we can't stop contrib modules from altering stuff onto here anyway. But we can set the right example in JSON:API Extras, by having it create an Extras tab on the configuration page that this patch is adding :)
  3. 🦅👁 Fixed!
  4. JSON:API doesn't have any of those implemented. But I don't mind being future-proof.

#6:

  1. Yep, that's listed as remaining task 4 :)
  2. The method filter runs very early in the request processing system: at this point we don't have a ResourceType object yet.

#7:

What about keeping the path the same, and having JSON:API Extras form_alter the form to add all of its stuff to it?

See my response to #5.2.

Should this description be more generic, like "Configure JSON:API"?

See #10.2 (the second thing I pushed back against).

Alternatively, maybe we keep this description as-is, and make it JSON:API Extras's responsibility to alter it to the more generic one?

👍


#8: Then I think you'll like my response to #5.2 :)

xjm’s picture

+++ b/src/Form/JsonApiSettingsForm.php
@@ -0,0 +1,61 @@
+      '#description' => $this->t('When writing is allowed, entities can be added, changed or removed via JSON:API. <a href=":docs">This may have security implications.</a>', [':docs' => 'https://www.drupal.org/docs/8/modules/jsonapi/security-considerations']),

Oh, one other nitpick that came up in the meeting is that we need the Oxford comma here:

[...] added, changed, or removed [...]

xjm’s picture

This collides with JSON:API Extras. I think it's OK, we can work it out there. Can you open an issue to make sure that happens?

@e0ipso, we also discussed in the UX meeting that from a usability perspective, JSON:API extras might add its config to the same page. (It's out of scope here and not in any way something that impacts core inclusion, just was the unanimous recommendation of UX people in the meeting.)

xjm’s picture

Oops, looks like #14 was also already discussed above. Sorry, crossposts!

wim leers’s picture

Assigned: wim leers » Unassigned
StatusFileSize
new11.62 KB
new25.74 KB

Fixed CS violations, all tests should be green now. Past midnight once again. Signing off. 👋🏻

I sincerely hope there's constructive feedback awaiting me in the morning so we can get this committed in about 24 hours. 🙏

wim leers’s picture

Issue summary: View changes
StatusFileSize
new216.74 KB
new11.62 KB
new25.74 KB

#13: ✅

Updated screenshot in IS, no before/after here since the difference is so tiny.

wim leers’s picture

Issue summary: View changes

I mixed up screenshots.

wim leers’s picture

Issue summary: View changes

Wim Leers credited ckrina.

wim leers’s picture

UX contributors who should be credited:
webchick, benjifisher, jhodgdon, Gábor Hojtsy, xjm, phenaproxima, ckrina, effulgentsia, wordlinemine

wim leers’s picture

StatusFileSize
new1015 bytes
new25.88 KB

😭One last coding standards violation: 80 cols!

jhodgdon’s picture

My feeling on the screenshot in #17:
- The radio options seem very clear to me.
- I am not sure the term "entities" is clear to all users. Suggest putting something in that clarifies it, like saying instead of just "entities"
entities (content items, taxonomy terms, ...)

Or something similar.

xjm’s picture

Issue summary: View changes

Looks like worldlinemine also still needs to be credited as well: https://www.drupal.org/u/worldlinemine

Meanwhile, adding the followup tasks to the IS.

seanb’s picture

  1. +++ b/src/Form/JsonApiSettingsForm.php
    @@ -0,0 +1,61 @@
    +        'r' => $this->t('Allow only reading'),
    +        'rw' => $this->t('Allow reading and writing'),
    

    I was thinking maybe we could use the word 'access' to make it more clear, and it also might not be clear what reading and writing is about for less technical users. So maybe something like:
    - Allow only read access to the API.
    - Allow read and write access to the API.

    The part 'access to the API' might be redundant and could be fixed by adding a field label: 'Define access to the API', but just some thoughts.

    I also think these need a dot at the end, like on the /admin/config/media/file-system page.

  2. +++ b/src/Form/JsonApiSettingsForm.php
    @@ -0,0 +1,61 @@
    +      '#description' => $this->t('When writing is allowed, entities can be added, changed, or removed via JSON:API. <a href=":docs">This may have security implications.</a>', [':docs' => 'https://www.drupal.org/docs/8/modules/jsonapi/security-considerations']),
    

    I think we discussed in the UX meeting we could probably use the Warning: prefix, similar to the permissions page. So this would then be Warning: When writing is allowed, entities can be added, changed, or removed via JSON:API. This may have security implications..

xjm’s picture

Issue summary: View changes
wim leers’s picture

Issue summary: View changes
StatusFileSize
new220.47 KB
new1.09 KB
new25.91 KB

#29: weird, I did copy/paste their nickname too! 🤔

#28: ✅

Before
After
wim leers’s picture

StatusFileSize
new1.43 KB
new25.92 KB

#30:

  1. 🤔I specifically avoided using the word "access", since this is not doing access checking (which has a whole set of expectations in Drupal) … and @jhodgdon just said in #28 she felt it's very clear. Crucially, this is a UI specifically for technical users — I don't think non-technical users will be configuring JSON:API.

    🦅👁 Added the periods, great catch! ✅

  2. 🤔 Isn't the This may have security implications. link scary enough already? I don't think we need to make it sound more scary than necessary.

I also noticed #10's refactor had a bug in the submit handler. Trivial fix.

dries’s picture

Great progress! Thanks everyone for trying hard to get JSON:API to land.

It's a minor suggestion, but "This may have security implications." sounds a bit scary. I'd write it in a positive way: "When no write operations are required, setting JSON-API to read-only is recommended as it hardens your site's security.". The latter helps the user understand the why and feels more constructive. That extra explanation could incentivize more people to opt for read-only. Again, not a showstopper by any means, and it might have been debated in other places.

xjm’s picture

@Dries, we also just discussed almost exactly that in the UX channel. I think Wim will have an updated patch with some changes we proposed to address making it a warning that's actionable rather than vague and therefore scary. Thank you!

wim leers’s picture

Issue summary: View changes
StatusFileSize
new1.5 KB
new25.87 KB
new227.47 KB

After a lot of back and forth between @seanb, @xjm and I, we settled on this:

Before
After

#34: Hi, Dries, nice to see you here! I believe this change also addresses your concerns!

seanb’s picture

#36 Looks good to me! Thanks.

dries’s picture

Agree that #36 looks better!

andrewmacpherson’s picture

This needs a $form['read_only']['#title'], because '#type' => 'radios' is rendered as a fieldset with a legend. The patch in #36 gives us an empty legend.

It could use a configure key in the info.yml file too

andrewmacpherson’s picture

Status: Needs review » Needs work
effulgentsia’s picture

  1. +++ b/jsonapi.services.yml
    @@ -143,6 +143,13 @@ services:
    +  method_filter.jsonapi:
    +    public: false
    +    class: Drupal\jsonapi\Routing\ReadOnlyModeMethodFilter
    +    decorates: method_filter
    +    arguments: ['@method_filter.jsonapi.inner', '@config.factory']
    

    Why use decoration here? Why not just add it as a separate route filter?

  2. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,69 @@
    +      $is_read_only_route = !empty(array_diff($route->getMethods(), $read_only_methods));
    +      if ($is_jsonapi_route && $is_read_only_route) {
    +        $collection->remove($name);
    +      }
    

    Based on this logic, is_read_only_route is incorrectly named, because it's actually telling you if it's a route that allows writes. Also, it's not handling the case where $route->getMethods() returns empty, because the meaning of that is that all methods are allowed. The jsonapi module doesn't create such routes, but we shouldn't assume that here.

  3. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,69 @@
    +    throw new MethodNotAllowedHttpException(array_unique($all_supported_methods), sprintf("JSON:API's read-only mode is enabled. Site administrators can enable writes at %s.", Url::fromRoute('jsonapi.settings')->setAbsolute()->toString(TRUE)->getGeneratedUrl()));
    

    $all_supported_methods is always empty. We need to add the supported methods to it.

gabesullice’s picture

After catching up on this issue, this would be my ideal:

[ ] Accept only JSON:API read operations.
[ ] Accept all JSON:API create, read, update, and delete operations.

Warning: You should not unnecessarily accept all operations. By limiting your site to only read operations you can reduce your exposure to potential security vulnerabilities. Learn more about securing your site here.

Here are my reasonings:

  1. "Allow only reading JSON:API": implies that there are access control implecations. It suggests that existing access controls won't be respected, which is of course untrue. Even if you choose "allow," many requests will often be forbidden. Therefore, I've changed this to "accept" because... once a request is accepted, access will still be checked.
  2. "Allow only reading JSON:API": "only" sounds strange here because it's not paired with a similar word in the corresponding option. Therefore, I added all to balance things out.
  3. "Allow only reading JSON:API": What we're allowing are read operations. Not reading JSON:API. JSON:API is a specification. Also, reading as a term is an imprecise developer-ism.
  4. Warning: I changed this because the warning was describing a feature of JSON:API. It wasn't actually telling a user why that option might be undesirable. As above, the language also makes it sound like JSON:API will bypass entity access controls, which it will not.

    Let's not forget... we're adding this read-only mode because of a fear of hypothetical, as-yet-unknown bugs in preexisting entity access controls—not because we're aware of any existing or inherent flaws in JSON:API's respect for, or usage of, these public access APIs.


Regarding the follow-up:

Non-blocker, major UX task: Discuss whether the site owner should see a list or table on the page of the resources that are exposed.

When and where was it decided that either of these should exist at all?

I'm very -1 to this follow-up.

This is not information that the site owner should see. AFAIK, that information will be entirely unactionable and overwhelming. JSON:API's docs are already very clear about what data it exposes.


I'm also wondering about #6.2 or, alternatively, why unsafe methods are ever added in Routes.php. Why not just prevent the routes from being created at all? (or send them to a no-op controller method like EntityResource::getReadOnlyErrorResponse())?

I think it's because the route filter allows for the generic error response, which is a DX win?

gabesullice’s picture

I think we also need a configure key in our module info file.

e0ipso’s picture

I'm also wondering about #6.2 or, alternatively, why unsafe methods are ever added in Routes.php. Why not just prevent the routes from being created at all? (or send them to a no-op controller method like EntityResource::getReadOnlyErrorResponse())?

I think the intent is that this technique is moved out of JSON:API and generalized in core. At least my reviews have had that in mind. However you are right that I have not seen a follow-up created (or mentioned) in that direction. If that is not the intent, then I agree that we should approach this differently from a technical perspective.

Can someone, please, confirm the assumption above ☝️?

e0ipso’s picture

WRT the error object:

throw new MethodNotAllowedHttpException(array_unique($all_supported_methods), sprintf("JSON:API's read-only mode is enabled. Site administrators can enable writes at %s.", Url::fromRoute('jsonapi.settings')->setAbsolute()->toString(TRUE)->getGeneratedUrl()));

It would be great if we could add a Link to https://www.drupal.org/docs/8/modules/jsonapi/security-considerations and have a more detailed explanation there.

jibran’s picture

I'm glad we have got here after the long discussion.

+++ b/config/schema/jsonapi.schema.yml
@@ -0,0 +1,7 @@
+jsonapi.settings:
+  type: config_object
+  label: 'JSON:API settings'
+  mapping:
+    read_only:
+      type: boolean
+      label: 'Read-only mode enabled'

We need a hook_update_N to update the config active storage of existing sites with JSON:API installed.

xjm’s picture

For the followup issues, we can discuss them on the issues once filed and decide whether they're wontfix or a different fix or whatnot. :) Although I do think we want these left open to migrate into the core queue. We can move the feedback for them over once they're posted.

wim leers’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs upgrade path, -Needs upgrade path tests +Needs update path, +Needs update path tests
StatusFileSize
new26.73 KB
new3.22 KB
new1.19 KB
new996 bytes
new249.5 KB

#39: Done. But we don't have UX team sign-off on that label yet :(

#41:

  1. Because:
    1. route filters have priorities lying very closely to each other, I think there's relatively high risk of disrupting some site by introducing a new one that may be operating with the same priority as the new route filter we'd introduce here
    2. this is doing conceptually exactly the same as the method filter, it just has some extra logic — if it's a "richer" version of an existing service, we might as well decorate it — just like BigPipe is doing with html_response.attachments_processor.big_pipe
  2. ✅ Yep, bad naming at 2 AM. Note that we can make assumptions about JSON:API routes since this is only acting on JSON:API routes.
  3. ✅ GOOD CATCH! This will result in better error responses! 👍

#42:

  • I think those labels make sense, but we arrived at the current ones after extensive back-and-forth with UX team members. I'm changing them as you're asking, but I'm crossing my fingers very hard that the UX team will approve them today.

    I do like the general direction of your description/warning, but the "You should not unnecessarily […]" statement is very confusing. And not mentioning entities at all is also making it harder to understand I think.

    So I landed in the middle:

    'Warning: If read operations alone cover your needs, you can choose to limit JSON:API to just that to reduce your exposure to potential security vulnerabilities in the adding, changing or removing of entities (content items, taxonomy terms, …) via JSON:API. <a href=":docs">Learn more about securing your site with JSON:API.</a>'
    
  • Huh?! I didn't even realize that was added as a follow-up. Apparently @xjm did that in #29. I am not opposed to bringing something like https://www.previousnext.com.au/blog/introducing-entity-access-audit-module to core, but it should definitely not be done in a JSON:API-specific context or even a general API context. It's something that's crucial to get right always.

    Same for the status report entry follow-up.

  • I think it's because the route filter allows for the generic error response, which is a DX win? That is indeed a key reason why I went this direction.

#43: already done for #39.

#44: That is the other key reason :) Follow-up filed: #3039687: Add an API read-only mode to Drupal core.

#45: Will look into that later today.
#46: Will look into that later today. It's already in the remaining tasks in the issue summary.

Before
After
e0ipso’s picture

I am certain that this is the link @Wim Leers meant to link for his response to my comment on #44: #3039687: Add an API read-only mode to Drupal core

wim leers’s picture

Issue summary: View changes

#47: cool, let's do that.

These are the follow-ups you added to the IS:

The remaining follow-ups have been created.

#49: yes, I just noticed & fixed that myself. 😆

e0ipso’s picture

Edit: cross posted.

Feedback about the documented follow-ups:

  • Docs gate core blocker: Draft a handbook page (Wim has notes on the details), which we will provide to the sec team for review.
  • Non-blocker, major UX task: Discuss whether the site owner should see a list or table on the page of the resources that are exposed. This is the user-facing complement of what /jsonapi provides developers, except possibly with additional info on whether it is read-only (e.g. config entities) or writable.
  • Non-blocker, major or normal UX task: Discuss adding a status report entry about the setting (helpful for site audits per several people in the meeting). TBD also: whether it's a warning or info.
  • Non-blocker: core critical task for 8.8.x to provide a generalized API in core that will support this for REST etc. too: #2843147: Add JSON:API to core as a stable module.
  • Sounds great ✅
  • Like @gabesullice, I am very hesitant about this. If anythig, I'd be excited to use this as an excuse to start leveraging JSON:API in a progressively decoupled approach inside of core. But let's discuss this in the follow up itself since it's not blocking.
  • I'm 🆗 with this
  • Sounds great ✅✅
seanb’s picture

I don’t feel I can sign off on it, but the field label and radio buttons look very good to me! I like the fact that we now explicitly mention all the operations.

I do think that exposure to potential security vulnerabilities in the adding, changing or removing of entities looks a little bit scary. I would immediately think, why is there an option with potential security vulnerabilities? What are they? In the previous version of the description it stated a bit more what the risk were (adding, changing and removing content), which for some reason sound less scary to me than potential security vulnerabilities.

On the other hand, it might be that we actually want it to look scary so people won't enable the option without knowing what they are doing. In that case, it looks good to me!

larowlan’s picture

+++ b/jsonapi.routing.yml
@@ -1,2 +1,10 @@
+    _permission: 'administer site configuration'

note to self: this is 'restrict access': TRUE

  1. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,74 @@
    +      assert(count($supported_methods) > 0, 'JSON:API routes always have a method specified.');
    +
    +      $is_jsonapi_route = $route->hasDefault(Routes::JSON_API_ROUTE_FLAG_KEY);
    

    we assert before we check the JSON_API_ROUTE_FLAG_KEY? Looking at the parent implementation those without supported methods aren't removed.

  2. +++ b/tests/src/Functional/FileUploadTest.php
    @@ -367,6 +379,7 @@ class FileUploadTest extends ResourceTestBase {
    +    $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE);
    
    @@ -405,6 +418,7 @@ class FileUploadTest extends ResourceTestBase {
    +    $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE);
    
    @@ -434,6 +448,7 @@ class FileUploadTest extends ResourceTestBase {
    +    $this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE);
    

    does this warrant adding a utility method to the base class ... future you would approve when you have to refactor

e0ipso’s picture

Sorry to add to the pile.

My suggestion of the UI:

  1. From:
    'Warning: If read operations alone cover your needs, you can choose to limit JSON:API to just that to reduce your exposure to potential security vulnerabilities in the adding, changing or removing of entities (content items, taxonomy terms, …) via JSON:API. <a href=":docs">Learn more about securing your site with JSON:API.</a>'
    

    to

    'Warning: You can choose to limit JSON:API to read-only mode if you only read from Drupal using JSON:API. That will reduce potential security risks in the adding, changing or removing of content (nodes, taxonomy terms, …) via JSON:API. <a href=":docs">Learn more about securing your site with JSON:API.</a>'
    
  2. Make this description #states based and only appear when read & write is selected. Having a Warning on the secure option seems confusing.
  3. From:
    Accept all JSON:API create, update, and delete operations
    to
    Accept all JSON:API read operations. Accept all create, update, and delete operations for content entities as well.
wim leers’s picture

Issue summary: View changes
StatusFileSize
new246.72 KB
new2.59 KB
new26.71 KB

#52: I agree it's unnecessarily scary now, which is also something @Dries made a remark about in #34. New string, which incorporates @Dries' suggestion:

'Warning: If read operations alone cover your needs, you can choose to limit JSON:API to only reads to harden the security of your: adding, changing or removing of entities (content items, taxonomy terms, …) via JSON:API is then impossible. <a href=":docs">Learn more about securing your site with JSON:API.</a>'

#53:

  1. ✅ Good call! Fixed. I like this much better now :)
  2. I personally don't think so. Core also has $this->config('rest.settings')->set('bc_entity_resource_permissions', TRUE)->save(TRUE); in its test. It ensures that there is no risk of abstraction leading one to reason incorrectly about tests. This one particular piece of configuration is triggering a change in behavior. I don't want that to be abstracted away in my tests.

RE: restrict access: TRUE — yep, and that's also what the similar config pages use :)

Before
After
xjm’s picture

The description is getting too long for people to read. I'd really suggest going back to the description we hashed out last night because it needs to be short and declarative.

xjm’s picture

Status: Needs review » Needs work

Yeah, marking NW, I don't even understand the current description when I read it. =/ It's a run-on sentence and contains so much terminology. (I'm fine with the new labels; they are clearer.) But the less text, the better.

At a minimum, let's provide screenshots of both versions of the description for UX review.

seanb’s picture

To be honest, I agree with @xjm that the description we had last night was a bit better. Less scary, easy to read, and understand. This does not feel like a blocking thing to me though, just a preference.

Warning: When writing is allowed, entities (content items, taxonomy terms, …) can be added, changed, or removed via JSON:API. <a href=":docs">Read more about securing your site with JSON:API.</a>

e0ipso’s picture

#56 the problem is that the shorter description did not explain all the nuances. In my opinion a security flag is not the place where you want to favor succinctness vs precision.

wim leers’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs update path, -Needs update path tests
StatusFileSize
new3.81 KB
new30.46 KB

Update path + tests is done.

xjm’s picture

Thanks @e0ipso. I think the key thing from a usability perspective is that the handbook page is the way to properly explain the nuances, and we want people to go to the handbook page. Any UI description is too short to provide nuances and the current one is simultaneously too long and unfamiliar for site users to actually read.

gabesullice’s picture

The problem with the original description is that it just described a feature of JSON:API. It was like "Warning: this module works as designed." Additionally, it's incomplete. The score security release of a few weeks ago would have been mitigated by this read-only mode even though it had nothing to do with changing entities. The attack just exploited that code path. That's why I removed the entity CRUD language.

Let's try this:

Warning: Accepting only read operations will harden the security of your site. Learn more about security hardening here.

wim leers’s picture

Issue summary: View changes
StatusFileSize
new1.37 KB
new30.4 KB
new242.88 KB

(Ugh I see that #55 contains a string mistake.)

#54:

  1. I like where that is going, but it's not entirely accurate: it doesn't reduce security risks for C/U/D, it eliminates that. That elimination is the risk reduction.
  2. AFAICT #states only works for form items (the #type => something level), not for descriptions of form items.
  3. That seems very long. The current 4 verbs match those in CRUD.

#58: I think the essence of that suggestion is its brevity. It is inaccurate, because it conveys that writing entities itself is a risk, which it is not.

I combined what's in #55 and tried to respect and balance:

  • @Dries' concerns in #34
  • @gabesullice's concerns in #42
  • @e0ipso's concerns in #54.1
  • @seanB's concerns in #58
  • @xjm's concerns in #57
  • … while still respecting the recommendations from the UX team in #10 and #30, which is how we arrived at #36

I ended up with:

'Warning: When you do not need the ability to create, update or delete entities (content items, taxonomy terms, …), limiting JSON:API to only read operations is recommended. <a href=":docs">Learn more about securing your site with JSON:API.</a>'

This incorporates elements of every suggestion so far AFAICT! 🥳🤓

Before
After
xjm’s picture

My proposal is sort of similar to the recent ones:

Warning: You should only enable write access if your site or contributed modules require it. Learn more about securing your site with JSON:API.

I pinged @jhodgdon and @clara for their UI text expertise.

e0ipso’s picture

I can +1 #63 (although I slightly prefer #62, but #63 is has more consensus building). The only part that is missing and we must communicate is that regardless of the option selected, no config entities can be mutated. This is very relevant and very important to this screen.


AFAICT #states only works for form items (the #type => something level), not for descriptions of form items.

Right, but there is nothing stopping us from making that description its own #type => 'html_tag' with that description. If that is something that you think makes sense to do.

jhodgdon’s picture

Wow, lots of action during last night (in my time zone)! And in Slack, @xjm said the help text below the radios is now proposed to be

Warning: Only enable all operations if the application requires it. Learn more about securing sites with JSON:API.

so I'm reviewing that text (not the text in #64, which I think is not as good), the rest of the screenshot in #63, and the Security page that the help text links to at https://www.drupal.org/docs/8/modules/jsonapi/security-considerations -- I have a couple of thoughts...

a) I mostly like the text on the radios. It gets across that this is only the config page for JSON:API operations, and clearly states what the two options mean.

b) On the security page at the bottom, it says that if you use read-only mode, that "completely eliminates" security problems... but is that really true? What if reading data is a possible access violation? Maybe that sentence could be changed to say that it would eliminate security problems that could affect the content of your site.

c) Regarding the help text... I am a bit uncomfortable with "the application", and also with the proposal in #64 saying "your site or contributed modules". And also that the bit explaining about entities has been omitted. Actually, entities are not being mentioned at all.

d) See also https://www.drupal.org/docs/develop/user-interface-standards/interface-text -- we're supposed to use the word "site" not "Drupal" in general, so I think "application" is also not recommended? Also it says to avoid the word "entities", which is desirable, but also in Slack yesterday we discussed that these operations only apply to entities, and people wanted to get that across.

e) Yesterday in Slack there was discussion about a module that would restrict JSON:API permissions to only certain entity types. I don't see that mentioned on the Security page or in this text.

So... Maybe this would be better:

------
Allowed operations
* Accept only JSON:API entity read operations
* Accept all JSON:API entity create, read, update, and delete operations
Warning: Use read-only mode unless the site needs write operations on entities (content items, comments, ...). Learn more about securing sites with JSON:API.
------
And then also address (b) and (e) on the Security page?

wim leers’s picture

Issue summary: View changes
StatusFileSize
new1.19 KB
new30.29 KB
new208.24 KB

#65: Using '#type' => 'html_tag' is problematic for accessibility of a form item's description.

#66:
a) 👍
b) Done.
c+d) People specifically wanted to avoid mentioning "entities", since that's irrelevant for what is being communicated here.
e) restrict JSON:API permissions to only certain entity types will never be a thing; disabling certain entity types in JSON:API is a thing, and that's what https://www.drupal.org/project/jsonapi_extras provides, and that is mentioned in https://www.drupal.org/docs/8/modules/jsonapi/security-considerations.

Based on concerns with “application”, with “contributed modules” and @jhodgdon’s strong recommendation to use “site”:

'Warning: Only enable all operations if the site requires it. <a href=":docs">Learn more about securing your site with JSON:API.</a>'
Before

After

P.S.: Let's not review https://www.drupal.org/docs/8/modules/jsonapi/security-considerations any further. Bikeshedding one thing at a time is already enough. The security team will review https://www.drupal.org/docs/8/modules/jsonapi/security-considerations. Only after that has happened, do we need to bikeshed its precise wording.

jhodgdon’s picture

#67 discussion makes sense to me, and I think the text is clear. +1. (Have not reviewed the code, only the UI screenshots.)

seanb’s picture

+1 from me as well!

xjm’s picture

@Wim Leers, Maybe we can spin off a separate issue for the docs page. I did specifically ask for @jhodgdon's feedback. :) It's not a bikeshed; it's docs gate.

#67 looks good to me!

gabesullice’s picture

Status: Needs review » Reviewed & tested by the community

LGTM too!

gabesullice’s picture

Issue tags: +Needs follow-up

Follow up tag added for the docs, per #70 and the docs needing sec. team review.

gabesullice’s picture

Issue tags: -Needs follow-up +Needs followup

Gah! I hate that tag.

webchick’s picture

Completely OT: Hm. Well, "followup" is not an actual word, so I can see how tag confusion would happen. :)

Reviewed the "after" screenshot from #67: https://www.drupal.org/files/issues/2019-03-13/Screenshot%202019-03-13%2...

Looks good...

1) Uses radios vs. checkboxes to make it clear what each option will do (UX pattern borrowed from private vs. public files)
2) Includes the warning about security implications, but tones it down, per @Dries and some others.

The wording of the options is quite technical. OTOH, it's also pretty technical page, and it's targeted at User 1 vs. a site builder/content author type.

One piece of feedback from the UX call that is not addressed here is the description on the overview page still is "Enable or disable JSON:API's read-only mode." which was cited as overly specific. OTOH, this seems to be a very deliberate choice, per #8, to keep this page as simple as possible.

Changing any of this is a string fix which can happen until RC so I'm not particularly fussed about it. The current version feels "shippable" to me, so +1 from me, as well. Thanks so much for the quick turnaround on this!

wim leers’s picture

StatusFileSize
new2.7 KB
new30.29 KB
+++ b/jsonapi.install
@@ -53,3 +53,13 @@ function jsonapi_requirements($phase) {
+function jsonapi_update_8001() {

@effulgentsia pointed out this should probably be 8701, not 8001 for core. I'm fine with that :)

wim leers’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new4.84 KB
new30.72 KB
new2.15 KB
new6.96 KB
new30.81 KB
+++ b/tests/src/Functional/ResourceTestBase.php
@@ -1898,6 +1899,12 @@ abstract class ResourceTestBase extends BrowserTestBase {
+    // DX: 405 when read-only mode is enabled.
+    $response = $this->request('POST', $url, $request_options);
+    $this->assertResourceErrorResponse(405, sprintf("JSON:API's read-only mode is enabled. Site administrators can enable writes at %s.", Url::fromUri('base:/admin/config/services/jsonapi')->setAbsolute()->toString(TRUE)->getGeneratedUrl()), $url, $response);

@effulgentsia also pointed out that this should assert that the Allow header contains the expected value. Turns out it doesn't yet! Failing tests + fix. This wouldn't have caused significant problems and certainly no risks, but would have needed another minor bug fix in the future. Which we now can avoid!

wim leers’s picture

Status: Needs review » Needs work

The last submitted patch, 76: 3039568-76.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
Issue tags: -Needs followup
StatusFileSize
new1.1 KB
new30.94 KB

HAH! Pesky Message entity weirdness — no, just kidding, it keeps us honest — it always ensures we think about edge cases! Message entities aren't stored so they cannot be retrieved using GET!

Also, forgot to remove the followup tag in #77.

wim leers’s picture

Issue summary: View changes
Issue tags: -Needs change record

Draft change record created: https://www.drupal.org/node/3039960

effulgentsia’s picture

+++ b/src/Form/JsonApiSettingsForm.php
@@ -0,0 +1,60 @@
+        'r' => $this->t('Accept only JSON:API read operations.'),
+        'rw' => $this->t('Accept all JSON:API create, read, update, and delete operations.'),

I like this wording! Given this wording, I wonder if we want to change any of the following:

  1. +++ b/config/schema/jsonapi.schema.yml
    @@ -0,0 +1,7 @@
    +      label: 'Read-only mode enabled'
    

    Where is this label used? Depending on the answer to that, perhaps it should be something like "Restrict JSON:API to only read operations"?

  2. +++ b/jsonapi.links.menu.yml
    @@ -0,0 +1,5 @@
    +  description: "Enable or disable JSON:API's read-only mode."
    

    #74 mentions the UX feedback about making this less specific. However, many of the links on admin/config are very specific. For example, "Change site name, email address, slogan, default front page, and error pages.". But given the labels of the radio buttons, perhaps this could be something like "Configure whether to accept JSON:API write operations." or "Enable or disable JSON:API write operations."?

  3. +++ b/src/Form/JsonApiSettingsForm.php
    @@ -0,0 +1,60 @@
    +      '#title' => $this->t('Allowed operations'),
    

    Should this be "Accepted operations"?

  4. +++ b/src/Form/JsonApiSettingsForm.php
    @@ -0,0 +1,60 @@
    +      '#description' => $this->t('Warning: Only enable all operations if the site requires it. <a href=":docs">Learn more about securing your site with JSON:API.</a>', [':docs' => 'https://www.drupal.org/docs/8/modules/jsonapi/security-considerations']),
    

    Should we change "enable" to "accept"?

  5. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,78 @@
    +    throw new MethodNotAllowedHttpException(array_intersect($all_supported_methods, $read_only_methods), sprintf("JSON:API's read-only mode is enabled. Site administrators can enable writes at %s.", Url::fromRoute('jsonapi.settings')->setAbsolute()->toString(TRUE)->getGeneratedUrl()));
    

    Should this be changed to something like "JSON:API is configured to accept only read operations. Site administrators can enable write operations at %s."?

Anyway, this might have all been discussed in earlier comments (I haven't read through them all). I'm fine with punting these and/or other string changes to followups.

effulgentsia’s picture

Status: Needs review » Reviewed & tested by the community

Other than potential string changes, #79 looks great to me, so back to RTBC.

One other followup we might want:

+++ b/src/Routing/ReadOnlyModeMethodFilter.php
@@ -0,0 +1,78 @@
+    throw new MethodNotAllowedHttpException(array_intersect($all_supported_methods, $read_only_methods), sprintf("JSON:API's read-only mode is enabled. Site administrators can enable writes at %s.", Url::fromRoute('jsonapi.settings')->setAbsolute()->toString(TRUE)->getGeneratedUrl()));

I suspect it's possible that this is thrown in a situation where you're in read-only mode and try to PATCH a config entity. But in that situation, enabling writes won't make it work (even with that enabled, you still can't patch config entities). So in that case, we're giving a misleading error message. Perhaps we need to adjust the error message based on whether we actually filtered out the requested method?

effulgentsia’s picture

Oh wait, #82 might not be an issue, because in that case, core's method filter probably throws its exception first, so perhaps we're all good there.

e0ipso’s picture

I will commit this in about 1h. Any other string refinement will happen in a separate issue.

Please post any additional feedback before then. Anything missed here will be fixed in another commit if necessary.

wim leers’s picture

StatusFileSize
new9.17 KB
new32.11 KB

#81:

  1. ✅ Config schema labels are only ever shown in https://www.drupal.org/project/config_inspector. But sure, changed.
  2. 🙂 That's exactly the argument I made in #10.2.
    🤔 I think the current description is still fine. If you want to change it, I'd be okay with Configure whether to allow only read operations or all operations. For now, left unchanged.
  3. I'd prefer not to start changing the UI strings again.
  4. See previous point.
  5. ✅ That's indeed more consistent 😍, done. Except instead of explicitly mentioning "write", I avoided that, just like we have elsewhere (see above discussion). So I went with "JSON:API is configured to accept only read operations. Site administrators can configure this at %s."

#82: When POSTing a config entity for example, you'll get a 405 response even in JSON:API's current codebase, because there will only be a single route that exists for the URL you're posting to, which the routing system already generates that 405 for: No route found for "POST /jsonapi/node_type/node_type": Method Not Allowed (Allow: GET). So we're already good there 🙂 And yes, refining that can easily be a follow-up, and should be, since it's pre-existing.
EDIT: while I wrote this, @effulgentsia already reached the same conclusion in #83 :D

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 85: 3039568-85.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new31.1 KB
new1.31 KB

Some debug code snuck in there. (Also visible in the interdiff.)

wim leers’s picture

StatusFileSize
new504 bytes
new31.13 KB

Discussed #85.2 with @xjm and @effulgentsia and since this was the last thing to nitpick about, I figured we'd do it.

effulgentsia’s picture

Thanks! RTBC+1.

  • Wim Leers committed 39c29e2 on 8.x-2.x
    Issue #3039568 by Wim Leers, xjm, e0ipso, gabesullice, effulgentsia,...
wim leers’s picture

Status: Reviewed & tested by the community » Fixed

🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢🚢

🥳

e0ipso’s picture

Ha! @Wim Leers beat me to it. However, I will carry on with my plan regardless.


This issue and its predecessor were very stressful. I realize that there are a myriad of factors at play, but I think that collaborator & volunteer feelings could have been better cared for. This is often my most important value in a contrib issue queue. Hence the tradition to credit everyone that bothered to comment in an issue (yes, we've given credit to people commenting dis sux!).

Another tradition is that if an issue is particularly strenuous we'll give extra commit credit. In this case I'd like everyone to pay attention to what Wim Leers did here. He considered every nit pick, had meetings dedicated to a radio button label, posted many patches and iterations, got woken up by a bad-timing landlord after 3h of sleep… and managed to keep his spirit up and constructive while all that happened.

I know that when this is in core I won't have the chance to do this anymore with JSON:API, so here it goes…

  • Wim Leers authored 0d58255 on 8.x-2.x
    Issue #3039568 by Wim Leers: Add a read-only mode to JSON:API
    
  • Wim Leers authored 2a48f01 on 8.x-2.x
    Issue #3039568 by Wim Leers: Add a read-only mode to JSON:API
    
  • Wim Leers authored d0b1ae6 on 8.x-2.x
    Issue #3039568 by Wim Leers: Add a read-only mode to JSON:API
    
  • Wim Leers authored d245cf2 on 8.x-2.x
    Issue #3039568 by Wim Leers: Add a read-only mode to JSON:API
    
  • Wim Leers authored f63f466 on 8.x-2.x
    Issue #3039568 by Wim Leers: Add a read-only mode to JSON:API
    
dww’s picture

Ugh, while I was writing this review, y'all already committed this. Ooops. :/

---

Wow, step away from the fray for a few days and lots of progress! Huzzah. :)

Mostly +1 to RTBC, with a few nits/questions/concerns:

  1. +++ b/src/Form/JsonApiSettingsForm.php
    @@ -0,0 +1,60 @@
    +      '#title' => $this->t('Allowed operations'),
    

    Already mentioned, but it seems weird to use "Allowed" in this label, since the setting doesn't actually determine if the operations are allowed or not. I guess this is into "follow-up string fixes before RC" territory now, since everyone's running out of steam to make any more changes. :/

  2. +++ b/src/Form/JsonApiSettingsForm.php
    @@ -0,0 +1,60 @@
    +      '#description' => $this->t('Warning: Only enable all operations if the site requires it. <a href=":docs">Learn more about securing your site with JSON:API.</a>', [':docs' => 'https://www.drupal.org/docs/8/modules/jsonapi/security-considerations']),
    

    This is the only place "enable" appears on the entire form. Can we say: "Warning: Only accept all..." to match what the choices are? This seems friendly to everyone's concerns, and is a trivial fix. Perhaps still do-able before commit?

  3. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,78 @@
    +    $all_supported_methods = [];
    +    foreach ($collection->all() as $name => $route) {
    +      $all_supported_methods = array_merge($all_supported_methods, $route->getMethods());
    +    }
    +
    +    $collection = $this->inner->filter($collection, $request);
    +
    +    if (!$this->readOnlyModeIsEnabled) {
    +      return $collection;
    +    }
    

    Why do we do all the work to initialize $all_supported_methods if we're not in read-only mode? Shouldn't the check for read-only and the early return be the first thing this method does?

    Can't we then avoid iterating over the entire collection twice? Can't we be building up $all_supported_methods in the later foreach?

    In short: What's the point of remembering one of the "supported" methods from a route that was filtered out already?

  4. +++ b/src/Routing/ReadOnlyModeMethodFilter.php
    @@ -0,0 +1,78 @@
    +      $is_read_only_route = empty(array_diff($supported_methods, $read_only_methods));
    +      if (!$is_read_only_route) {
    +        $collection->remove($name);
    +      }
    

    Not sure we need this $is_read_only_route variable at all. Why not just:

    if (!empty(array_diff(...))) {
      $collection->remove($name);
    }
    

    ?

Thanks!

p.s. Was going to ask "Why is this specific to JSON:API at all? What about REST?" and I see that's already at #3039687: Add an API read-only mode to Drupal core. ;)

  • Wim Leers committed d5abca9 on 8.x-2.x
    Issue #3040186 by Wim Leers: Follow-up for #3039568:...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

rpayanm’s picture

Project: JSON:API » Drupal core
Version: 8.x-2.x-dev » 8.9.x-dev
Component: Code » jsonapi.module

Moving to Drupal core's issue queue.

I'm working on https://www.drupal.org/project/drupal/issues/3122113