spruceid / cacao-zcap-rs

CACAO-ZCAP Rust implementation
Apache License 2.0
0 stars 0 forks source link

Representing allowedActions #9

Open clehner opened 2 years ago

clehner commented 2 years ago

@chunningham wrote in https://github.com/spruceid/cacao-zcap/pull/6#discussion_r839508234:

https://github.com/spruceid/cacao-zcap/blob/158613b784c189685cdf22203bccebc62419f935/index.html#L220 when we delegate, we often delegate multiple capabilities at once (e.g. read + write) for multiple resources. this is currently represented in the siwe message as a set of resources <resourceUri>#<action>. in zcaps it seems that restricting to a single URI is common, but allowing for multiple actions via allowedActions: string[]. this would again map to a set of resources with a common base. if we interpret only the first resource as the invocationTarget without additional context like allowedActions, we will need more SIWE flows per login/initial session key delegation (e.g. 5 for space drop, read + write + delete + list + metadata)

I also see that zCaps are using a single invocationTarget; although it doesn't look like that is required (maybe an array could be used for invocationTarget); there is just one allowedActions property though, not a per-invocationTarget allowedActions, so I would assume if there are multiple invocation targets that the allowed actions intended to apply to all of them. That should still work with attenuation.

Currently allowedActions is not mentioned in CACAO-ZCAP. Since delegations attenuate capabilities, I would interpret it that by default all actions allowed (unless the application requires the allowed actions to be listed explicitly, in which case this doesn't work). So a delegation without allowedActions could be subdelegated with a non-CACAO ZCAP using allowedActions. But that does not help if the goal is to delegate only specific allowed actions in the first delegation.

Using action strings as fragments in the resources array looks like a possible solution; but it doesn't look to me like a correct use of URIs. The meaning of the fragment is supposed to be specific to the media type of de-referenced resource: https://datatracker.ietf.org/doc/html/rfc8820#section-2.5. Typically it refers to a subset of the resource. But the resources we are referring to as invocation targets I assume could be arbitrary file types. We would also have to exclude resources with fragments from being themselves invocation targets (as multiple fragments is not valid in a URI).

With the resources array being used for the capability chain (root delegation id, embedded parent delegation (#6), other previous delegation ids, and possibly a type/specification identifier (#7))... we could possibly detect a repeated invocation target URI with different fragment identifiers corresponding to actions, but I'm not sure it would be good idea, for the reasons above. Alternatively, actions could be represented elsewhere in the resources array and/or in the statement. Some possibilities:

  1. Reserve the array entry following the invocation target to be for a list of actions
    • A list as a URI seems non-idiomatic. What would the URI scheme be?
  2. Each array entry following the invocation target up to the next delegation could be an action URI.
    • The next delegation is detected by its use of a UUID URN (and/or data URL in #6). Action URIs could then be defined to be not UUIDs or data URLs.
  3. Each N resources following the invocation target could be action URIs, where N is mentioned in the statement in some structured way.
  4. Represent allowed actions fully in the statement string.
    • The statement string should probably then not be passed through into the ZCAP but would need a syntax defined (generically, or per-application, or in an extensible way?)
chunningham commented 2 years ago

If the direct parent delegation is always expected to be embedded (embedding its ancestors, recursively), can we skip the non-parent delegation ID resources? I agree the URI #fragment action representation is an improper use of URIs, in my mental model I was treating the kepler: URI as referencing a virtual document which describes the resource and it's available actions instead of the referencing the content itself. Part of the reason this isn't immediately inconsistent is because the key/path and version is as granular as we can get w.r.t. resource authorisation because we allow any structured or unstructured content, so I think we can't say READ kepler:.../kv/my_doc#intro as a capability, only READ kepler:.../kv/my_doc. Allowed actions could be represented together in one action URI with params of some kind, e.g. target resource is kepler:...://orbit0/kv/images/ and action uri is kepler:...://orbit0/kv/?actions=get+put+delete. Thinking about it, we could also put those params on the target resource directly (but I think we might use those in future, as they would affect app behaviour e.g. byte-ranges)

clehner commented 2 years ago

If the direct parent delegation is always expected to be embedded (embedding its ancestors, recursively), can we skip the non-parent delegation ID resources?

Yes, this would be possible. Non-parent previous delegations could be unfurled into the capabilityChain array from the recursively-nested parent delegation. Should the root/target should still be its own value in the resources array in that case?

Possibly other applications than Kepler could have fragment granularity for resources?

There is some info about capability attenuation via invocation target query string in https://github.com/w3c-ccg/zcap-spec/issues/39... that is suggesting that adding a query string parameter would be an attenuation. If we use actions=... for allowedActions, that might be able to not conflict with this other use of the query string, since the actions query string parameter would be removed as part of the mapping to zCap.

An alternative that may be simpler would be to put the actions in the statement string, e.g. "Authorize actions (read, write): [...]".

cobward commented 2 years ago

I have a strong preference for using the statement, as it is a massive UX improvement. What would we do about localization though?

clehner commented 2 years ago

For localization of a structured statement string, I think the pattern of SIWE would have to be followed for; i.e. wallets/apps can detect the format and localize it. Actions "read" and "write" are mentioned specifically in https://github.com/w3c-ccg/zcap-spec/issues/39; for other actions, I'm not sure... it's another semantic extensibility problem.