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 readAs and actAs
  • 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:

  1. exercise foo1 PublicFetch with con = usr1
  2. exercise foo1 DelegatedFetch
  3. exercise foo1 FetchOther with other = foo2
  4. exercise foo1 DelegatedFetchOther with other = foo2
  5. exercise foo1 PublicFetchOther with other = foo2
  6. exercise foo1 FetchOther with other = foo3
  7. exercise foo1 DelegatedFetchOther with other = foo3
  8. exercise 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.
    1. and 2. work with [actAs usr1, readAs obs1]
  • 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 readAs right that allows Alice to get her hands on foo3.
3 Likes

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.

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.

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).

I completely agree, but @bernhard 's example primarily addresses off-ledger authority, not identity.