openwallet-foundation / acapy

ACA-Py is a foundation for building decentralized identity applications and services running in non-mobile environments.
https://aca-py.org
Apache License 2.0
421 stars 515 forks source link

ACA-Py can't publish a private DID to Von-network #1460

Closed yunxi-zhang closed 3 years ago

yunxi-zhang commented 3 years ago

Hello, I've upgraded my local VON-network to its latest version. After turning on multi-tenancy feature in ACA-Py, I can't publish a private DID to VON-network, which was not an issue when I used an old version of VON-network. Below shows the steps of how to reproduce the issue.

Environment: ACA-Py version: 0.6.0

Step 1: Turn on the VON-network by using the ./manage up command. Step 2: Run an ACA-Py agent without giving a seed flag as parameters. Step 3: Call the API "/multitenancy/wallet" to view current wallets in the agent. Step 4: Call the API "/wallet/did/create" for twice to create two sub wallets in the agent and verify two private DIDs have been created successfully. image Step 5: Call the API "wallet/did/public?did=Cv3gHFy7PXbF5agXhv49Hh" to publish a DID, and an error is returned. image

I've created the same ticket in the VON repo, as not sure whether this issue comes from ACA-Py or VON-network. Please see this ticket: https://github.com/bcgov/von-network/issues/186.

Could anyone help here? Thanks!

ianco commented 3 years ago

Hi @yunxi-zhang as @WadeBarnes mentioned on the von-network issue, you need to have a privileged DID on the network before you can write a DID to the network. In a production scenario, you would get one of the trustee nodes to do this for you (for a fee). In development (or testing) you need to start with a privileged DID who can then write the DID's for your new agents.

yunxi-zhang commented 3 years ago

Hello @ianco, my understanding on "a privileged DID" is to have a public DID to be registered as an Endorsor on the ledger? I've created a DID to be an Endorsor on my VON-network and my agent also run with this public DID. However, the same issue still occurs, see screenshot and error below. Any idea?

image

image

2021-10-29 09:17:02,138 indy.libindy.native.indy.commands.pool INFO     src/commands/pool.rs:75 | OpenAck handle 27, pool_id 27, result Ok(())
2021-10-29 09:17:02,141 indy.libindy.native.indy.services.ledger INFO   src/services/ledger/mod.rs:85 | build_get_nym_request() => Ok("{\"reqId\":1635499022141304896,\"identifier\":\"LibindyDid111111111111\",\"operation\":{\"type\":\"105\",\"dest\":\"K4oQGEq9bRg512JdTr35v\"},\"protocolVersion\":2}")
2021-10-29 09:17:02,153 aries_cloudagent.admin.server ERROR Handler error with exception: DID K4oQGEq9bRg512JdTr35v is not posted to the ledger

=================
Traceback (most recent call last):
  File "/home/indy/aries_cloudagent/admin/server.py", line 164, in ready_middleware
    return await handler(request)
  File "/home/indy/aries_cloudagent/admin/server.py", line 201, in debug_middleware
    return await handler(request)
  File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/site-packages/aiohttp_apispec/middlewares.py", line 45, in validation_middleware
    return await handler(request)
  File "/home/indy/aries_cloudagent/admin/server.py", line 317, in check_multitenant_authorization
    return await handler(request)
  File "/home/indy/aries_cloudagent/admin/server.py", line 362, in setup_context
    return await task
  File "/home/indy/aries_cloudagent/wallet/routes.py", line 311, in wallet_set_public_did
    raise web.HTTPNotFound(reason=f"DID {did} is not posted to the ledger")
aiohttp.web_exceptions.HTTPNotFound: DID K4oQGEq9bRg512JdTr35v is not posted to the ledger
2021-10-29 09:17:02,154 aiohttp.access INFO 92.27.176.114 [29/Oct/2021:09:17:02 +0000] "POST /wallet/did/public?did=K4oQGEq9bRg512JdTr35v HTTP/1.1" 404 260 "-" "PostmanRuntime/7.28.4"
ianco commented 3 years ago

I don't think "Endorser" has enough privileges to write a DID to the ledger, you need to use a DID with "Steward" or "Trustee"

swcurran commented 3 years ago

That's not good if that is the case -- perhaps a legacy from Indy's default sandbox setup. It definitely SHOULD have the permissions to write a DID. A Trustee can as well, although a Steward should not be able to.

yunxi-zhang commented 3 years ago

@ianco, Endorsor is the only valid option I can see in the VON-network Web UI. In this case, how can I use Trustee or Steward?

Actually, I don't remember I had to create a public DID as an Endorsor previously to make multi-tenancy work before.

image

WadeBarnes commented 3 years ago

Default Auth Rules (https://github.com/hyperledger/indy-node/blob/master/docs/source/auth_rules.md) to help clarify which roles can perform various operations.

yunxi-zhang commented 3 years ago

Hello @WadeBarnes, not sure how this table could help resolve my issue. By combining below rows together, looks like an Endorsor has a privilege to write a DID to the ledger.

image image

If Endorsor doesn't have this privilege, how can I register a DID with a Trustee/Steward role by using VON-network's web server UI?

WadeBarnes commented 3 years ago

It's actually this line that is relevant to what you are attempting: image

It confirms the default rules allow an ENDOCER to write an unprivileged DID (a DID with NO role) to the ledger.

WadeBarnes commented 3 years ago

Connecting to a locally running instance of von-network using the containerized in indy-cli and running ledger get-auth-rule confirms it's using that same rule:

+---------------------+--------+-------------+---------------+---------------+----------------------------------+
| NYM                 | ADD    | role        | -             |               | {                                |
|                     |        |             |               |               |   "auth_constraints": [          |
|                     |        |             |               |               |     {                            |
|                     |        |             |               |               |       "constraint_id": "ROLE",   |
|                     |        |             |               |               |       "metadata": {},            |
|                     |        |             |               |               |       "need_to_be_owner": false, |
|                     |        |             |               |               |       "role": "0",               |
|                     |        |             |               |               |       "sig_count": 1             |
|                     |        |             |               |               |     },                           |
|                     |        |             |               |               |     {                            |
|                     |        |             |               |               |       "constraint_id": "ROLE",   |
|                     |        |             |               |               |       "metadata": {},            |
|                     |        |             |               |               |       "need_to_be_owner": false, |
|                     |        |             |               |               |       "role": "2",               |
|                     |        |             |               |               |       "sig_count": 1             |
|                     |        |             |               |               |     },                           |
|                     |        |             |               |               |     {                            |
|                     |        |             |               |               |       "constraint_id": "ROLE",   |
|                     |        |             |               |               |       "metadata": {},            |
|                     |        |             |               |               |       "need_to_be_owner": false, |
|                     |        |             |               |               |       "role": "101",             |
|                     |        |             |               |               |       "sig_count": 1             |
|                     |        |             |               |               |     }                            |
|                     |        |             |               |               |   ],                             |
|                     |        |             |               |               |   "constraint_id": "OR"          |
|                     |        |             |               |               | }                                |
+---------------------+--------+-------------+---------------+---------------+----------------------------------+
WadeBarnes commented 3 years ago

This indicates the code should be able to write a DID to the ledger provided it is not being assigned a role. If the DID you are trying to write to the ledger has a role assigned it will fail, as an ENDORCER cannot write a privileged DID to the ledger.

yunxi-zhang commented 3 years ago

@WadeBarnes, when running the commend ledger get-auth-rule in the indy-cli, I've got below error. image

I see a command called pool that can be used, but I don't know where I can get the name-value of my Von-network. image

image

Any guidance online that explains the steps?

WadeBarnes commented 3 years ago

You need to at least register the ledger with the indy-cli; https://github.com/bcgov/von-network/blob/master/docs/Indy-CLI.md#register-the-network-ledger-with-the-indy-cli-environment

and then connect to the pool before issuing the command:

indy> pool connect local_net
pool(local_net):indy> ledger get-auth-rule

Full documentation in how to use the containerized indy-cli can be found here; https://github.com/bcgov/von-network/blob/master/docs/Indy-CLI.md

yunxi-zhang commented 3 years ago

Thanks for the guidance. I can get the table now. However, I don't understand the semantics of each attribute along with its value in the Constraint column and the New Value column. Do you have a doc explaining what they mean? image image

WadeBarnes commented 3 years ago

Roles (from here; https://github.com/hyperledger/indy-node/blob/master/docs/source/requests.md#nym):

WadeBarnes commented 3 years ago

image is saying the same thing as image

WadeBarnes commented 3 years ago

This is just confirming that the auth_rules for your locally running instance of von-network will allow and ENDORCER to write a non-privileged DID to the ledger.

yunxi-zhang commented 3 years ago

@WadeBarnes, how should I understand the relationship amongst Old Value, New Value and Constraint columns for below roles in my table? E.g. - in the Old Value column, 101 in the New value column and have values of 0 and 1 for role attribute in the Constraint column?

image

WadeBarnes commented 3 years ago

This rule indicates you need the signature of either a "0" (TRUSTEE) or a "2" (STEWARD) in order to write a new DID with the role of "101" (ENDORSER) to the ledger. Since it's a new DID ("ADD") the old value is irrelevant (-) since it does not exist.

yunxi-zhang commented 3 years ago

Thanks @WadeBarnes, this makes sense now. If the row does mean any one of the ENDORSER, TRUSTEE AND STEWARD can add a new DID with no role to the ledger, it somehow contradicts to what I've tested so far. Could you or your team help test this multi-tenancy feature by publishing a private DID to a public one on the VON-network and see if it works?

WadeBarnes commented 3 years ago

@ianco, are you able to help a bit from here?

yunxi-zhang commented 3 years ago

Hello @ianco, could you and your team to help test if this is an issue in the current ACA-Py implementation?

ianco commented 3 years ago

@yunxi-zhang I was able to test this successfully in aca-py multitenant mode:

Note that the endpoints execute within the context of the current sub-wallet, so the ledger operation won't work unless the sub-wallet already has a DID with appropriate role. If you are creating a new sub-wallet with a new DID you need another agent with privileges to publish to the ledger

yunxi-zhang commented 3 years ago

Thanks for the response @ianco. I see the API you use to publish a private DID to be a public one is /ledger/register-nym, but the one I've used is wallet/did/public?did=Cv3gHFy7PXbF5agXhv49Hh. Is the api I used not the right one any more, or does it become deprecated?

ianco commented 3 years ago

Hi @yunxi-zhang , the wallet/did/public?did=.. api registers which DID in the wallet will be used as the public DID. In order to use this API you first have to publish the DID to the ledger (this API doesn't do that). Do creating a new public DID in a wallet is a 3 step process:

  1. Create the new DID
  2. Publish the DID to the ledger
  3. Register the DID in the wallet as the public DID

In order to do step 2, you need to already have a DID published on the ledger (with appropriate role). So typically a wallet owner can do set 1 themself, then they need to get someone to do step 2 for them, and then they can do step 3 themself.

yunxi-zhang commented 3 years ago

Thanks @ianco. I'm not sure how I should do for this step (note that the public DID for faber's sub-wallet is created with ENDORSER role) as mentioned in your answer.

I put my understanding to creating a public DID for a sub wallet by using general an ACA-Py (not the faber demo) as shown in steps below,

  1. Create a public DID (with an endorsor role) for the base wallet in an ACA-Py agent - by registering a wallet seed with an Endorsor role in the VON-network. Can verify this public DID - VV9pK5ZrLPRwYmotgACPkC is available at the agent level, see below picture image
  2. Turn on multi-tenancy feature by creating a first sub wallet in the ACA-Py agent, this auto makes the base wallet to become a relaying wallet only - call a POST API /multitenancy/wallet 3. No DIDs in the sub wallet - call a GET API /wallet/did
  3. Create a private DID in the sub wallet - call a POST API /wallet/did/create
  4. See this private DID in the sub wallet - call a GET API /wallet/did
  5. Publish the private DID in the sub wallet to the ledger - call a POST API ledger /register-nym I've got an error in the response 403: Cannot register NYM to ledger: wallet AuthorityOneWallet has no public DID.

What's wrong in my steps?

ianco commented 3 years ago
  1. Publish the private DID in the sub wallet to the ledger - call a POST API ledger /register-nym I've got an error in the response 403: Cannot register NYM to ledger: wallet AuthorityOneWallet has no public DID.

What's wrong in my steps?

Just like the error message says, you need to have a public DID in your wallet, i.e. registered on the ledger with appropriate role (ENDORSER or higher) in order to write a DID to the ledger. This is a ledger constraint, not an aca-py constraint.

yunxi-zhang commented 3 years ago

I did register a public DID in my agent's wallet as shown in step 1, is this not the right way?

ianco commented 3 years ago

Step 1 creates the "base wallet", but your step 5 is executing in the context of the sub-wallet, which has no public DID.

yunxi-zhang commented 3 years ago

Thanks for your answer @ianco. Think the bit I'm struggling with is how I can create a public DID for the sub-wallet. My goal here is to create a public DID for each sub wallet assuming I'll have multiple sub wallets in an Issuer agent, and each sub wallet will be a different issuer.

ianco commented 3 years ago

You need to have an agent that has the authority to write DID's on the ledger. You can create a sub-wallet for this purpose, or use a separate instance of aca-py. We often use a separate instance of aca-py (separate from the multi-tenant instance) as this instance can also act as an Endosrer. (You could do this with another sub-wallet, but we find it's easier to manage this with a separate aca-py instance.)

If your sub-wallets will be issuers, then you will also need an agent to act as Endoser, to endorse schema and credential definition transactions that will be written to the ledger. Your separate aca-py instance can also be the endorser agent.

yunxi-zhang commented 3 years ago

Following your suggestions @ianco, I've tested with two agents. Agent 1 runs an Endorsor which has a public DID, as this DID has been registered with an endorsor role in the VON-network's Web UI. image Agent 2 runs a multi-tenancy ACA-Py with a sub wallet 1 (please ignore its name as a Holder). image

However, after creating a private DID in the sub wallet 1 in Agent 2, I still failed to publish this private DID to a public one. The error is still 403: Cannot register NYM to ledger: wallet subWallet1 has no public DID.. Think my question is how my Agent 2 can use Agent 1's public DID to endorse this publishing the private DID transaction? What's missing here?

ianco commented 3 years ago

Agent 2 can't publish their own DID transaction. They need another agent to publish their DID. Once the DID is published on the ledger then Agent 2 can make it their public DID. Once Agent 2 has a public DID then they can either (depending on their DID role) write their own transactions to the ledger (schema, cred def etc) or they can ask an Endorser to endorse their transactions and then publish them.

yunxi-zhang commented 3 years ago

Thanks for your answer @ianco, this makes sense and it works. Really appreciate all your help here :-).