When included entities for a request run into a "denied" access check, they are currently represented in the response's Compound Document as an "include" object with a "meta" key. This passes on the information that the entity was not accessible. However, according to the JSON API spec, all Resource Objects (which includes included objects) MUST have "type" and "id" top-level members.
The absence of these keys causes errors in Ember applications that utilize JSON API when communicating with Drupal, and likely other frameworks as well.
Proposed resolution
Output the "type" and "id" top-level members when serializing included Entities that failed access checks.
Comments
Comment #2
hampercm commentedComment #3
hampercm commentedTest-only patch
Comment #4
wim leersComment #5
e0ipsoSetting back to Needs work since we expect tests to fail.
Comment #6
hampercm commentedI'm having a difficult time figuring out how to implement this cleanly. Any ideas?
Comment #7
wim leersI don't know the JSON API normalizers remotely well enough to give any advice at all. Pinged e0ipso on IRC.
Comment #8
hampercm commentedGiving this a 2nd try...
Comment #9
hampercm commentedI still can't figure out a fix for this.
Comment #10
hampercm commentedAnother thing to consider: is this even the right approach for access-denied errors on included/related objects? I definitely see the advantage to reporting that an included object was unavailable, but having the included object in the response, even though that object that has none of its attributes available, will likely cause problems in external applications. For example, for an Ember.js app, I'd need to customize its JSON API adapter to throw out a 403'ed object, so the app doesn't try to continue using it and fail due to not having any attributes to work with. Likely, I'd just error out of whatever operation I was trying to accomplish, so a partial failure would be equivalent to a complete failure.
As an alternative, I could see the JSON API module returning a failure response if any of the includes were inaccessible. This is one possible interpretation of the JSON API spec:
( see http://jsonapi.org/format/#fetching-includes )
In this case, it would be a (conditional) lack of support for including resources from that path. The error object in the response could point to the
includequery parameter that caused the failure using itssource => parameterelement. See http://jsonapi.org/format/#error-objectsThoughts?
Comment #11
e0ipsoThat makes quite a lot of sense. I think this
includedbehavior was an artifact of the normalization and the inclusion process.If anything I think that we should just exclude any entity from the
includedpool and add an entry in the errors section of the metadata. Additionally we'll need to make sure that we maintain full linkage, excluding any possible children entities from the tree. This may or may not happen already with the current implementation.Comment #12
e0ipsoComment #13
wim leersIt sounds like the spec is ambiguous in this respect. Should we not discuss this with the JSON API spec authors to A) clarify this, B) make the spec more specific?
Comment #14
hampercm commentedYes, this is definitely an area where the spec is vague, or left up to the implementation's discretion. I'd be happy to open an issue on the official spec's GitHub.
Note that a response can't contain both a
dataand anerrortop-level member, so the response would need to be either a clear failure or a successful response without any error info.Comment #15
e0ipsoTo avoid that violation the Partial Success specification adds the errors inside of the
metasection. We are doing that already for collections, so we should treat includes the same way.Comment #16
wim leersThis discussion made me think of the
'view label'entity access operation — created #2843922: Show label of inaccessible entities ('view' access denied) when 'view label' access is allowed for that.Comment #17
hampercm commented@e0ipso Includes are being treated with the Partial Success spec on the current HEAD. However, the
idandtypemembers, which are required by spec, are not currently added. That's what this issue was originally written to address. Implementing that fix seemed like it would be difficult and messy, so I had suggested a different approach--dropping Partial Success--and my reasoning behind it in #10.Comment #18
e0ipsoThis is only if we add them in the
includedsection. What I meant in #11.So, that means:
includedsection of the payloadmeta > errorssection of the payload. In there, we need notypenoridto comply with the spec, if I'm not mistaken.Comment #19
hampercm commented@e0ipso got it! #18 makes sense. I'll look into implementing that.
Comment #20
hampercm commentedI'm still having trouble figuring out the normalization code.
Comment #21
e0ipsoI'm proposing this.
The patch will give this output for a request that tries to include 3 related articles, but 2 of them are unpublished.
Outputs:
Comment #22
e0ipsoI created a follow up to improve the contents of the error object: #2844130: Create a custom EntityAccessDeniedHttpException.
Comment #23
wim leersBut what about
Isn't #21 sneakily circumventing that by putting the errors in
meta? I guess there's no other way? I guesserrors= hard errors, andmeta > errors= soft errors?Comment #24
e0ipsoThis is partially discussed in http://discuss.jsonapi.org/t/multi-status-responses-partial-success-in-p...
Short story, the spec would have you fail the whole request if one of the includes is not success (like one item being 403 in a collection or in a list of includes). So yeah, this is correct:
Comment #25
wim leersThanks, that confirms my suspicion.
Leaving it to @hampercm to RTBC.
Comment #26
damienmckennaTherefore, shouldn't the whole request fail instead of giving a partial response? Does this not mean that if the module is to follow the spec that this "needs work"?
Comment #27
e0ipso@DamienMcKenna sorry for the confusion, but I meant that if we wanted to add the errors straight to the
errorssection in the top level we'd have to fail the whole request. I feel very strongly not to fail a request if one included element (via includes or i the collection) has access denied.In any case this module is following the spec strictly with this patch applied.
Comment #28
e0ipsoGiven that:
I'm going to merge this to unblock #2840677: Validate responses against the JSON API specification.
@DamienMcKenna, @hampercm please feel free to create a follow up ticket if you feel we should resolve this problem in some other way. I just want to bring includes and collections to the same situation. If we need to change the approach, it needs to change in both scenarios.
Comment #30
hampercm commentedSorry, I had meant to review this yesterday, and got diverted. This looks good, though it omits the extra functional test I had added in #3, which seems important for validation. I'll file an issue to add that test.