How do readAs/actAs claims translate to authorization?
My best guess is that when checking that a transaction is well-authorized, the authorizers change depending on the node type:
- Fetch and NoSuchKey : Union of
readAsandactAs - Create and Exercise:
actAs
Is this somewhat accurate, or is it totally off-base?
To understand the exact meaning of readAs and actAs, you need to think of off-ledger identity and authorization and on-ledger authorization and identity separately. readAs and actAs are off-ledger authorization concepts (“User Rights”) whereas Fetch, NoSuchKey, Create and Exercise have on-ledger authorization rules (“Required Authorizers”).
Let’s illustrate using a template
tempalte Foo
with
sig : Party
obs : Party
usr : Party
where
signatory sig
observer obs
nonconsuming choice PublicFetch : Foo
with
con : Party
controller con
do return this
nonconsuming choice DelegatedFetch : Foo
controller usr
do return this
nonconsuming choice FetchOther : Foo
with
other : ContractId Foo
controller usr
do fetch other
nonconsuming choice DelegatedFetchOther : Foo
with
other : ContractId Foo
controller usr
do exercise other DelegatedFetch
nonconsuming choice PublicFetchOther : Foo
with
other : ContractId Foo
controller usr
do exercise other PublicFetch with con = usr
Let’s say there are instances foo1, foo2, foo3, all with sig = operator, but with users usr1, usr2, usr3 and observers obs1, obs2, obs3 respectively. obs1, obs2, usr1, usr2 are on participant1, obs3, usr3 on participant2.
Alice wants to submit these commands via the API on participant1 as user Alice:
exercise foo1 PublicFetch with con = usr1exercise foo1 DelegatedFetchexercise foo1 FetchOther with other = foo2exercise foo1 DelegatedFetchOther with other = foo2exercise foo1 PublicFetchOther with other = foo2exercise foo1 FetchOther with other = foo3exercise foo1 DelegatedFetchOther with other = foo3exercise foo1 PublicFetchOther with other = foo3
Before I go on, think about it… Are these possible in terms of on-ledger authorization and what off-ledger “rights” does Alice need for this?
When the API request hits participant 1, the first thing the participant needs to do is to load foo1 to make sense of the root action exercise foo1 .... So Alice needs to have the right to read foo1. The only two stakeholder parties of foo1 are operator and obs1. So Alice needs a readAs right of one of those two. Let’s pick readAs obs1.
Ok, having been able to load foo1, the participant can apply the choice arguments to the arguments of foo1 to calculate the exercise node and with that the required authorizers, which for an Exercise are the controllers. That (conveniently) happens to be usr1 in all cases. So Alice needs the right actAs usr1.
For commands 1 and 2 we are done. The command succeeds.
For the other commands, participant1 next encounters an exercise foo2 ..., an exercise foo3 ... or a fetch foo2 or fetch foo3. As before, to make sense of those, it needs to load that contract. So Alice, needs the right to load foo2 and foo3. For foo2 we can solve that as before by adding a readAs obs2 right. For foo3, adding readAs obs3 won’t help as obs3 is not hosted on participant1. Technically you could add readAs operator, but assuming that’s off-limit, we are stuck. 6-8 will not work.
Having loaded foo2, the participant can now evaluate the required authorizers.
The required authorizers for a fetch are any stakeholders. So operator OR obs2. Now fortunately, operator is a signatory of foo1 so we have that authority in the context of exercise foo1 FetchOther. Therefore 3 will go through.
The required authorizers of an exercise are the controllers. In case of 4, that’s usr2. We do not have that authority in the context of exercise foo1 DelegatedFetchOther We only have operator and usr1 there. Adding a right actAs usr2 will not help as it does not change the authority we have in the context of that choice.
In case of 5, the controller is usr1. We have that authority so 5 will go through.
In conclusion:
- actAs authorizes a user to act as a controller on commands
- readAs authorizes a user to fetch contracts from the participant’s database for the purpose of acting on those contracts.
- Neither impact the on-ledger required authorizers or available authority.
-
- and 2. work with
[actAs usr1, readAs obs1]
- and 2. work with
- 3 and 5 also work with an addition of
readAs obs2. - 4 fails due to on-ledger authorization issues
- 6-8 fail because there is no
readAsright that allows Alice to get her hands onfoo3.
Thanks for the explanation. I’m trying to nail down the distinction between the “on-ledger” and “off-ledger” here:
The ledger model says what it means for a transaction to be well-authorized given the requesters on the commit and the required authorizers for each action (integrity). It also says who the stakeholders are and what they can see (privacy).
But in practice one has to compute the transaction in the first place (and thereby the required authorizers and stakeholders), and the ledger model doesn’t say anything about this process because the model is an abstraction, so we need an off-ledger notion of authorization (“rights”) to fill the gap.
Is this an accurate summary of the situation?
But in practice one has to compute the transaction in the first place (and thereby the required authorizers and stakeholders), and the ledger model doesn’t say anything about this process because the model is an abstraction, so we need an off-ledger notion of authorization (“rights”) to fill the gap.
I don’t quite agree with this summary. In my mind the ledger authorization and privacy models do define how the transaction is computed. The user rights serve a different purpose. They provide the mapping between off-ledger identity (user) and on-ledger identity (party). This mapping is many to many (and also separate for authorization and privacy purposes). A single user can be mapped to a set of parties. Multiple users can be mapped to the same set of parties.
The rationale for having the off-ledger identity separate from on-ledger identity is to provide ledger client applications flexibility beyond fairly rigid on-ledger identity. E.g. if a bank wanted to have multiple users of a Daml app, each with their own credentials but all acting on behalf of the bank and having the same on-ledger privileges, it would be impractical to represent these users as parties on the ledger, as this would require for example upgrading the app every time a new user is added. With users mapped to parties as many to many you can have multiple employees of an organization (or multiple people performing the same role in an organization) each have a separate off-ledger identity and credentials, all mapped to the same on-ledger identity. In other words you can have multiple employees of a bank or multiple purchase managers in provisioning department of a company all act as the bank party or purchase manager party on the ledger. And this is just one of the innumerable use cases the separation of on-ledger and off-ledger identities serves.
But in practice one has to compute the transaction in the first place (and thereby the required authorizers and stakeholders), and the ledger model doesn’t say anything about this process because the model is an abstraction, so we need an off-ledger notion of authorization (“rights”) to fill the gap.
I don’t quite agree with this summary. In my mind the ledger authorization and privacy models do define how the transaction is computed.
Consider an alternate participant implementation that takes a command with a list of requesters, and allows unrestricted access during the first interpretation, and only once the candidate transaction has been computed does the participant check that the transaction is well-authorized.
AFAICT, this would be permitted by the ledger model.
The user rights serve a different purpose. They provide the mapping between off-ledger identity (user) and on-ledger identity (party). This mapping is many to many (and also separate for authorization and privacy purposes). A single user can be mapped to a set of parties. Multiple users can be mapped to the same set of parties.
But, to my knowledge, the readAs and actAs claims discussed here predated user management, and one would want an off-ledger mechanism to restrict access regardless of the ability to name persistent sets of claims (user management).
The rationale for having the off-ledger identity separate from on-ledger identity is to provide ledger client applications flexibility beyond fairly rigid on-ledger identity. E.g. if a bank wanted to have multiple users of a Daml app, each with their own credentials but all acting on behalf of the bank and having the same on-ledger privileges, it would be impractical to represent these users as parties on the ledger, as this would require for example upgrading the app every time a new user is added. With users mapped to parties as many to many you can have multiple employees of an organization (or multiple people performing the same role in an organization) each have a separate off-ledger identity and credentials, all mapped to the same on-ledger identity. In other words you can have multiple employees of a bank or multiple purchase managers in provisioning department of a company all act as the bank party or purchase manager party on the ledger. And this is just one of the innumerable use cases the separation of on-ledger and off-ledger identities serves.
I completely agree, but @bernhard 's example primarily addresses off-ledger authority, not identity.