Interaction between JWT, PartyID on Canton

Hi Team,

I have made some tests and observations. Would like to understand more.

Setting: two participant nodes P1, P2 on the same domain. Alice is enabled in P1, Bob in P2. A DAR is uploaded to this setup and a contract is created that Alice and Bob are the stakeholders.

I am creating a “fake” JWT such that it will be used in P1 while the actAs Bob::P2 namespace. Effectively someone “impersonates” Bob and accessing P1.

{
  "https://daml.com/ledger-api": {
    "ledgerId": "P1",
    "applicationId": "HTTP-JSON-API-Gateway",
    "actAs": [
      "Bob::P2 namespace"
    ]
  }
}

With this JWT on P1,
(1) When using v1/query the active contract is received and visible.
(2) When using v1/exercise the transaction fails.

May I know if (1) is a problem that with this JWT, Bob can see contracts on P1 although Bob is not enabled in P1?

Also, for (2), where in the canton setup “fails” the transaction? The submitting participant node, the domain or the target participant node (P2)? Wish to know which part fails that transaction.

Thanks.

kc

1 Like

Hi KC

(1)
Each participant node needs to manage access to its local ledger API (and associated state). The v1/query read query is served only from a participant’s local ledger API. Authorisation for this is documented here: Authorization — Daml SDK 1.18.1 documentation.

In what sense is the JWT token you’re using “fake”? I don’t see anything inherently wrong with the party with ID "Bob::P2 namespace" accessing P1. Canton supports a single party connecting to multiple participants (if that’s authorised).

(2)
A canton domain contains a domain topology manager that keeps an approved topology state for the system. This state will say that P1 is not authorised to act on behalf of Bob. If P1 is behaving honestly then it won’t submit the v1/exercise transaction on behalf of Bob – so in your example, it sounds like P1 is failing the transaction.

Additionally, the other participants (in this case P2) can see the domain topology manager’s approved state. They therefore know that P1 is not authorised to act on behalf of Bob. The other participants should therefore also reject the transaction.

However, note that Canton does not yet fully support malicious participant nodes as per the documentation on known limitations. We don’t yet have guarantees about what will happen if P1 behaves maliciously. However, Canton is designed to give security and consistency guarantees in the presence of malicious nodes. We’re working on filling implementation and testing gaps to realise this design.

You can read more about Canton’s topology management here: Identity Management — Canton 1.0.0-SNAPSHOT documentation.

2 Likes

Hi @kctam that is a great question, and one that we will want in Support knowledge articles … somewhere :grin:

Good to see more in-depth and interesting Canton questions :+1:t2:

1 Like

Hi Phoebe,
Thanks for this detailed explanation.

We are working on a decentralized environment, where a platform owner (domain operator) allows a third-party organization joining this domain. The questions raised here is more from a security perspective.

In short, the domain operator is afraid of impersonation from that third-party participant node. As a result, the ideal case is that, the participant node rejects any initiation of transaction/query by a party not allocated on this participant node. While it’s understood that only contracts relevant to that third-party participant node exist in that participant node, a type of blocking may help a lot.

Sorry for the term. I consider it “fake” as it’s created by that third party impersonating the domain operator. It’s a valid JWT, despite that their participant node shouldn’t accept per my points above.

Thanks… kc

Hi KC,

The scope of the JWT tokens is between the participant node and its applications. P1 and P2 might be configured to use the same JWT provider, or they might use different JWT providers.

If P1 and P2 use different JWT providers, then Bob will not be able to connect to P1 with the token that’s used to connect to P2.

If P1 and P2 use the same JWT provider (perhaps owned by the platform owner), then Bob can use the same token to access P1 and P2. However, if Bob accesses P1 with this token, then Bob will only be able to read data that is:

  1. Stored on P1
  2. And visible to Bob, according to Daml’s privacy rules (docs)

In your example, this means that Bob would be able to read state that’s visible to both Bob and Alice from P1, but nothing more. Additionally, Bob would not be able to write from P1.

Sorry for the term. I consider it “fake” as it’s created by that third party impersonating the domain operator. It’s a valid JWT, despite that their participant node shouldn’t accept per my points above.

Who is the domain operator in this context? As JWT tokens are only between participant nodes their applications, the domain operator may not have anything to do with the token generation or authentication. If all participants share a JWT provider, then all participants must trust that this JWT provider (and associated authentication system) does not allow one party to impersonate another party.

You can read about how to configure the JWT provider for a participant node here: Static Configuration — Daml SDK 2.6.5 documentation

Let me know if that answers your question :slight_smile:

1 Like

As an addition to @Phoebe_Nichols 's answer to (1), note that the participant is specified in the JWT in ledgerId:

That means you can’t take a token that was issued for P2 and just use it for a request on P1. To be able to query P1 as Bob, the IAM operator would have to issue you a token for Bob that is scoped to P1. Daml’s trust model is such that the participant operator and IAM operator for that participant trust each other or are one and the same.

Thus to read as Bob from P1, you need permission from the participant operator to do so. The participant does contain all of Bob’s data that is also available on P1 - ie the intersection of P1’s view of the ledger and Bob’s view. By issuing a token for Bob, the participant operator is granting access to that view.

But note that Daml doesn’t give any good guarantees for such a query. For a participant like P2 that hosts Bob, there is a completeness guarantee that you get all data for Bob. For P1, you get some subset only.

1 Like

@bernhard did you mean to include the participantId in there instead of the ledgerId? Afaik the latter is identical across participants.

1 Like

Ah yes, I probably do.

In Canton, the participant reports its own ID as the ledger ID, i.e., the ledger ID differs across participants.

1 Like

Ah good to know, then this does work indeed.