fabric-sdk-py icon indicating copy to clipboard operation
fabric-sdk-py copied to clipboard

Incompatibility with Fabric CA 1.5.14+

Open davidabinbev opened this issue 9 months ago • 3 comments

Due updates related to the authentication on fabric ca service, now, we are unable to register identities using Python Fabric SDK.

In our case, we are using the Fabric Ansible Galaxy Collection for provisioning fabric network,

Error:

TASK [peer-organization-role : Register the organization admin] ****************
task path: /opt/app/playbooks/peer/peer-organization-role/tasks/create.yml:108

<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: uwazi
<127.0.0.1> EXEC /bin/sh -c 'echo ~uwazi && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/uwazi/.ansible/tmp `"&& mkdir "` echo /home/uwazi/.ansible/tmp/ansible-tmp-1742423051.6323547-202-57634863004878 `" && echo ansible-tmp-1742423051.6323547-202-57634863004878="` echo /home/uwazi/.ansible/tmp/ansible-tmp-1742423051.6323547-202-57634863004878 `" ) && sleep 0'
Using module file /home/uwazi/.ansible/collections/ansible_collections/hyperledger/fabric_ansible_collection/plugins/modules/registered_identity.py
<127.0.0.1> PUT /home/uwazi/.ansible/tmp/ansible-local-39ur5wj1ab/tmpvhimgvgi TO /home/uwazi/.ansible/tmp/ansible-tmp-1742423051.6323547-202-57634863004878/AnsiballZ_registered_identity.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/uwazi/.ansible/tmp/ansible-tmp-1742423051.6323547-202-57634863004878/ /home/uwazi/.ansible/tmp/ansible-tmp-1742423051.6323547-202-57634863004878/AnsiballZ_registered_identity.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3 /home/uwazi/.ansible/tmp/ansible-tmp-1742423051.6323547-202-57634863004878/AnsiballZ_registered_identity.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/uwazi/.ansible/tmp/ansible-tmp-1742423051.6323547-202-57634863004878/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
  File "/tmp/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload_9nho7kmv/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload.zip/ansible_collections/hyperledger/fabric_ansible_collection/plugins/modules/registered_identity.py", line 298, in main
    identity_registered = connection.is_registered(registrar, enrollment_id)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload_9nho7kmv/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload.zip/ansible_collections/hyperledger/fabric_ansible_collection/plugins/module_utils/certificate_authorities.py", line 284, in is_registered
    return self._run_with_retry(lambda: self._is_registered(registrar, enrollment_id))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload_9nho7kmv/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload.zip/ansible_collections/hyperledger/fabric_ansible_collection/plugins/module_utils/certificate_authorities.py", line 376, in _run_with_retry
    raise e
  File "/tmp/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload_9nho7kmv/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload.zip/ansible_collections/hyperledger/fabric_ansible_collection/plugins/module_utils/certificate_authorities.py", line 361, in _run_with_retry
    result = func()
             ^^^^^^
  File "/tmp/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload_9nho7kmv/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload.zip/ansible_collections/hyperledger/fabric_ansible_collection/plugins/module_utils/certificate_authorities.py", line 284, in <lambda>
    return self._run_with_retry(lambda: self._is_registered(registrar, enrollment_id))
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload_9nho7kmv/ansible_hyperledger.fabric_ansible_collection.registered_identity_payload.zip/ansible_collections/hyperledger/fabric_ansible_collection/plugins/module_utils/certificate_authorities.py", line 293, in _is_registered
    raise CertificateAuthorityException(result['errors'][0]['code'], result['errors'][0]['message'])
fatal: [localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "affiliation": "",
            "api_authtype": "basic",
            "api_endpoint": "https://fabric-console.government.xxxxx-local.test",
            "api_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "api_secret": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "api_timeout": 60,
            "api_token_endpoint": "https://iam.cloud.ibm.com/identity/token",
            "attributes": [],
            "certificate_authority": "ca",
            "enrollment_id": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "enrollment_secret": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "hsm": null,
            "max_enrollments": -1,
            "registrar": "/opt/app/artifacts/wallet/ca-admin.json",
            "state": "present",
            "type": "admin"
        }
    },
    "msg": "{'code': 20, 'message': 'Authentication failure'}"
}

The fabric CA respose when we try to register an identity:

2025/03/19 22:28:38 [INFO] 10.244.0.8:56746 GET /api/v1/identities/orgadmin?ca=ca 401 25 "Invalid token in authorization header: Token signature validation failed"

davidabinbev avatar Mar 19 '25 22:03 davidabinbev

fabric-sdk-py appears to still use the old Fabric CA v1.3 authorization header format that requires a signature over request body and client cert.

Starting in Fabric CA v1.4 clients should update to the more secure authorization format that requires a signature over the HTTP method, path, request body, and client cert.

Fabric CA v1.4 through v1.5.13 tolerates the less secure v1.3 format with a compatibility mode by default. To make Fabric CA secure by default, starting in Fabric CA v1.5.14 if you want the old less secure compatibility mode you must enable it with environment variable FABRIC_CA_SERVER_COMPATIBILITY_MODE_V1_3=true.

See the Fabric CA v1.5.14 release notes for more information.

The Java, Go, and Node SDK clients were updated to the new format back in 2019, but it looks like fabric-sdk-py never got updated to the more secure connection.

The fabric-sdk-py Fabric CA client auth header code that needs to be updated can be found here: https://github.com/hyperledger/fabric-sdk-py/blob/161eff3dff1cac299dfc0c4c20ca2a9f63dc606a/hfc/fabric_ca/caservice.py#L228-L241

For comparison, the fabric-operations-console Fabric CA client auth header was also recently updated to fix the same issue, see commit: https://github.com/hyperledger-labs/fabric-operations-console/commit/a403629875cd3491f9aa1592d6614edcbffe5be0

denyeart avatar Mar 20 '25 01:03 denyeart

@denyeart Thanks. Specifically, whats was changed? Only the function:

function generateCaAuthToken(opts: { client_prv_key_b64pem: string, client_cert_b64pem: string, body_obj: any, path: string, method: string }, ?

So, in fabric-sdk-py we should add the request path and the used http method for generating the token?

davidfdr avatar Mar 22 '25 22:03 davidfdr

@denyeart Thanks. Specifically, whats was changed? Only the function:

function generateCaAuthToken(opts: { client_prv_key_b64pem: string, client_cert_b64pem: string, body_obj: any, path: string, method: string }, ?

So, in fabric-sdk-py we should add the request path and the used http method for generating the token?

Yes. Let's see if we can get #198 to work.

denyeart avatar Mar 25 '25 04:03 denyeart