Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discoverability of supported update methods on resources without read permission #497

Open
surilindur opened this issue Jan 31, 2023 · 7 comments

Comments

@surilindur
Copy link

This is not necessarily an issue, but more of a request for clarification inspired by an actual use case - whether misuse or valid, I do not know, hence why I am asking. If this is not the correct place to ask, I would appreciate any pointers to the appropriate location.

Are there any guidelines in the specification for how a client can discover supported update methods (or, in general, any write/delete/append support) on resources on a Solid server, when the client has write or append permissions but no read permission?

An example use case could maybe be an inbox, to which everyone has append permission but only the owner has read permission. So whenever a client wants to write to that inbox, the client would either know that the server supports specific types or updates (or updates in general) or just blindly send some form of update and hope it works.

Is there an existing way for a client to determine whether they can do updates on a resource without read permissions? Or if there is no way for a client to do that (without trying an update first), could something be done with response headers to indicate support for updates without read permission?

I tried to look through the open issues, but did not find anything addressing that.

Thank you in advance for your time, and apologies if this has been answered before.

@rubensworks
Copy link

To make the question more precise: following this part of the spec, are servers supposed to return Accept-Patch, Accept-Post, or Accept-Put headers, when the client does a HEAD/GET request and the server replies with a 401 Unauthorized error, if that client only has write/append permissions (so no read)?

@csarven
Copy link
Member

csarven commented Jan 31, 2023

The WAC-Allow header is defined here https://solidproject.org/TR/wac#wac-allow . See also https://solidproject.org/TR/wac#client-wac-allow ).

An example use case could maybe be an inbox, to which everyone has append permission but only the owner has read permission.

HEAD /inbox/

204
WAC-Allow: public="append", user="read control"

As mentions above, requirements reading resources and communication options are in https://solidproject.org/ED/protocol#reading-resources (allowed HTTP methods and media types).

Is there an existing way for a client to determine whether they can do updates on a resource without read permissions?

OPTIONS /inbox/

204
Allow: POST
Allow-Post: application/ld+json, text/turtle
WAC-Allow: public="append", user="read control"

Clients should not expect the server to include the Allow-* headers on rejected requests.


If you're satisfied with the responses, can we close the issue? We can update the Solid Protocol to clarify clients finding access permissions.

You're also welcome to ask questions in chat: https://gitter.im/solid/specification . Note the upcoming move from Gitter->Matrix: https://gitter.im/solid/specification?at=63d817920c94855213d77fb4

@joachimvh
Copy link

I'll join in here as this issue is a consequence of some questions about CSS behaviour. This does already answer the question of whether the Accept-* headers should be present on rejected requests, but I have a follow-up question based on your reply.

OPTIONS /inbox/

204
Allow: POST
Allow-Post: application/ld+json, text/turtle
WAC-Allow: public="append", user="read control"

Is this an example of what the unauthenticated client would receive on an OPTIONS request? The reason that I ask is because that was the initial question, but this response contains user="read control" in the WAC-Allow header which implies that the request is authenticated.

So specifically, if a client only has append permissions on /inbox/, and no read permissions, and sends an OPTIONS request to /inbox/, should it receive a response with the Allow/Allow-* headers? Should it also contain the WAC-Allow header? CSS currently does neither. The spec only mentions GET/HEAD requests for the Allow headers, but the editor's draft seems to have removed that requirement. It is also quite relevant as that would potentially require the server to do several checks twice in case of a preflight OPTIONS call.

@csarven
Copy link
Member

csarven commented Jan 31, 2023

Is this an example of what the unauthenticated client would receive on an OPTIONS request?

As per https://solidproject.org/ED/protocol#server-accept-headers , the server includes Accept-* headers when client is authorized. The example assumes authorized for user, but for public, that particular header would not be included. Allow is included to advertise allowed HTTP methods on target resource - it does not entail that the target resource exists or that a request will receive a successful response.

No auth is expected for CORS-preflights. Server can include the WAC-Allow header with public access permissions but not user.

@joachimvh
Copy link

joachimvh commented Feb 1, 2023

My apologies if it might seem that I'm being difficult, but I want to make sure I'm fully correct about the details. I might have also caused some confusion due to not taking the "authorized request" part into account, so I'll ask some very specific questions. (I also just noticed I used Allow-* in my previous comment which also did not help).

What exactly is an "authorized request"?

  • Is it any request where the Authorization header is not empty?
  • Is it a request that is allowed according to the server authorization methods, such as WebACL/ACP?
  • Is it both of the above options combined?

My guess is the first option, but I want to make sure.

Are the contents of the Allow header and the presence of Accept-* headers dependent on the permissions granted to an authorized client? Take a situation where a client only has append permissions on a document, no read. It then sends an authorized OPTIONS request to that document. Which of the following sets of headers does it receive in response?

  • Allow: GET, PUT, PATCH, Accept-Put: */* and Accept-Patch: text/n3 (as these are all the accepted operations for any document)
  • Allow: PATCH and Accept-Patch: text/n3 (as append would only potentially allow PATCH)
  • None of these (as it doesn't have read permissions).

@csarven
Copy link
Member

csarven commented Feb 13, 2023

My apologies if it might seem that I'm being difficult

No need to apologise. You're not being difficult. I take it as input to consider improvements. It partly follows #378 (comment) , so thanks for asking.

All, please interpret the following as what's intended with the wording of the current text. Implementation feedback, corrections, and other considerations are welcome.


What exactly is an "authorized request"?

Generally a 2xx, and especially not a 401/403.

Is it any request where the Authorization header is not empty?

That doesn't guarantee an authorised response.

Is it a request that is allowed according to the server authorization methods, such as [WAC]/ACP?

Yes.

Is it both of the above options combined?

Currently yes.

Take a situation where a client only has append permissions on a document, no read. It then sends an authorized OPTIONS request to that document.

To be clear, an "authorized OPTIONS request" entails that the request was not a CORS preflight request. Regarding the role of 405 or 501, see #353 (comment) .

Allow: GET, PUT, PATCH, Accept-Put: / and Accept-Patch: text/n3 (as these are all the accepted operations for any document)
Allow: PATCH and Accept-Patch: text/n3 (as append would only potentially allow PATCH)
None of these (as it doesn't have read permissions).

I find the first to be most accurate and useful but let me respond this way:

The HTTP methods listed by the Allow header does not entail the access permissions that a client has on the target resource, e.g., whether subsequent PUT or PATCH requests would be authorised. Including the Accept-* headers require write-level access permissions. See also [1] [2].

When a response to GET, HEAD, and OPTIONS (with the exception of CORS preflight) is 2xx, the Allow and Accept-* headers are expected. The Authorization header (if present) in the CORS preflight request (OPTIONS) is not taken into account by the server, i.e., the server is not verifying access permissions. Hence, Accept-* headers are not included in the response of a CORS preflight request.


Happy to try to further clarify the above. Once clear and there are no technical objections, I can look for ways to clarify the Solid Protocol.

[1] Some of the underlying considerations are categorically the same as in #311 or maybe just philosophical ramblings.

[2] Accept-* essentially reveals the formats accepted by the server when used with a particular HTTP method for write-level operations. If a server were to not include the Accept-* headers when no read permission is given to the client for the target resource, the header would be essentially useless. Having append permission on a particular resource entails that the client can on some level know about the semantics of the target resource (e.g., when targetting a container or a non-container) or ways in which it can be updated with the help of the Allow and Accept-* headers. It does not entail that the client can know about the description of the resource. If a client has read permission on target resource, revealing Accept-* (if a server wishes to) would not be an issue - famous last words.

@joachimvh
Copy link

To be clear, an "authorized OPTIONS request" entails that the request was not a CORS preflight request.

I also found #378 (comment) while searching for an answer, and assumed that the implication was that the authorization header should be used to determine if a request is a preflight request or not, but perhaps I misinterpreted that. The CORS library that CSS uses actually assumes that all OPTIONS requests are preflight requests, so we will need to disable that behaviour and have our own custom check. Checking the presence of the Access-Control-Request-Method/Headers headers might be sufficient instead then.

My current interpretation of the expected server behaviour for an OPTIONS request is then:

  1. Check if preflight. If yes return standard preflight response, if not go to step 2.
  2. Do standard Solid authentication/authorization steps using WAC/ACP. On failure return 4xx, else go to step 3.
  3. Return similar headers as a preflight request, and the Allow/Accept-* headers.

Is this correct? If yes, how do you authorize an OPTIONS request? Going back to #14 (comment) which I originally used to implement responses for the status codes the assumption is that the same permissions as for a GET/HEAD request should be used? So acl:Read?

If the answer to the previous question is no this can be ignored, but if it is yes, then the original issue of this thread becomes a problem again. Specifically: there is a container where you only have append/write permissions on. How do you know that you can send data there and what the format of that data should be? Since you can't do an OPTIONS request to determine the Allow and Accept-* headers as you would get a 403.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants