def build_from_dict(self, data: dict) -> RegisterDocument: """ Build a valid immutable register document from dict. :param data: register document as dict :return: valid register document :raises: IdentityInvalidDocumentError: if invalid dict data IdentityInvalidDocumentError: if invalid document IdentityRegisterDocumentKeyConflictError: if key name is not unique """ try: for k in data['publicKey']: self.add_public_key_obj(RegisterPublicKey.from_dict(k)) for k in data.get('authentication', []): self.add_authentication_key_obj(RegisterAuthenticationPublicKey.from_dict(k)) for k in data.get('delegateAuthentication', []): self.add_authentication_delegation_obj(RegisterDelegationProof.from_dict(k)) for k in data.get('delegateControl', []): self.add_control_delegation_obj(RegisterDelegationProof.from_dict(k)) raw_controller = data.get('controller') controller = Issuer.from_string(raw_controller) if raw_controller else None return self.build(data['id'], DIDType(data['ioticsDIDType']), data['proof'], data.get('revoked', False), Metadata.from_dict(data.get('metadata', {})), data.get('creator'), data['ioticsSpecVersion'], data['updateTime'], controller) except (TypeError, KeyError, ValueError) as err: raise IdentityInvalidDocumentError(f'Can not parse invalid register document: \'{err}\'') from err
def test_build_register_delegation_proof_raises_validation_error_if_invalid_name( a_proof, a_controller): with pytest.raises(IdentityValidationError): RegisterDelegationProof.build(name='InvalidName', controller=a_controller, proof=a_proof, revoked=False)
def test_can_revoke_delegation_proof(base_doc_issuer, valid_key_pair, get_api_call, doc_deleg_set, deleg_doc_did, deleg_name): doc = get_doc_with_keys(deleg_control=[ RegisterDelegationProof.build('#Deleg1', controller=Issuer( deleg_doc_did, '#plop2'), proof='proof', revoked=False) ], deleg_auth=[ RegisterDelegationProof.build( '#Deleg2', controller=Issuer(deleg_doc_did, '#plop2'), proof='proof', revoked=False) ], public_keys=[ RegisterPublicKey.build('#MandatoryKey', 'base58Key1', revoked=False) ], did=base_doc_issuer.did) resolver_client = ResolverClientTest(docs={base_doc_issuer.did: doc}) assert not doc_deleg_set(doc)[deleg_name].revoked api = AdvancedIdentityRegisterApi(resolver_client) get_api_call(api)(deleg_name, revoked=True, doc_owner_issuer=base_doc_issuer, doc_owner_key_pair=valid_key_pair) updated_doc = resolver_client.docs[base_doc_issuer.did] assert doc_deleg_set(updated_doc)[deleg_name].revoked
def test_can_build_register_delegation_proof_from_dict_with_missing_proof_type( valid_key_name, a_proof, a_controller): key = RegisterDelegationProof(name=valid_key_name, controller=a_controller, proof=a_proof, revoked=False) as_dict = key.to_dict() as_dict.pop('proofType') from_dict_key = RegisterDelegationProof.from_dict(as_dict) assert from_dict_key.proof_type == DelegationProofType.DID
def test_can_build_register_delegation_proof_from_dict(valid_key_name, a_proof, a_controller, proof_type): key = RegisterDelegationProof(name=valid_key_name, controller=a_controller, proof=a_proof, revoked=False, proof_type=proof_type) from_dict_key = RegisterDelegationProof.from_dict(key.to_dict()) assert key == from_dict_key
def test_build_register_delegation_proof_from_dict_raises_validation_error_if_invalid_proof_type( valid_key_name, a_proof, a_controller): key = RegisterDelegationProof(name=valid_key_name, controller=a_controller, proof=a_proof, revoked=False) as_dict = key.to_dict() as_dict['proofType'] = 'invalid' with pytest.raises(IdentityValidationError): RegisterDelegationProof.from_dict(as_dict)
def test_not_is_equal_register_delegation_proof(valid_key_name, a_proof, a_controller, b_controller): key1 = RegisterDelegationProof(name=valid_key_name, controller=a_controller, proof=a_proof, revoked=False) key2 = RegisterDelegationProof(name=valid_key_name, controller=b_controller, proof='difference_ignored', revoked=False) assert not key1.is_equal(key2)
def test_can_build_register_delegation_proof(valid_key_name, a_proof, a_controller, proof_type): key = RegisterDelegationProof(name=valid_key_name, controller=a_controller, proof=a_proof, revoked=False, proof_type=proof_type) assert key.name == valid_key_name assert key.controller == a_controller assert key.proof == a_proof assert not key.revoked assert key.to_dict() == { 'id': valid_key_name, 'controller': str(a_controller), 'proof': a_proof, 'proofType': proof_type.value, 'revoked': False }
def doc_keys(a_controller): return { '#pub_key1': RegisterPublicKey(name='#pub_key1', base58=get_public_base_58_key(), revoked=False), '#pub_key2': RegisterPublicKey(name='#pub_key2', base58=get_public_base_58_key(), revoked=True), '#auth_key1': RegisterAuthenticationPublicKey(name='#auth_key1', base58=get_public_base_58_key(), revoked=False), '#auth_key2': RegisterAuthenticationPublicKey(name='#auth_key2', base58=get_public_base_58_key(), revoked=True), '#deleg_control_key1': RegisterDelegationProof( name='#deleg_control_key1', controller=a_controller, proof='a_deleg_proof_validated_by_the_resolver', revoked=False), '#deleg_control_key2': RegisterDelegationProof( name='#deleg_control_key2', controller=a_controller, proof='a_deleg_proof_validated_by_the_resolver', revoked=True), '#deleg_auth_key1': RegisterDelegationProof( name='#deleg_auth_key1', controller=a_controller, proof='a_deleg_proof_validated_by_the_resolver', revoked=False), '#deleg_auth_key2': RegisterDelegationProof( name='#deleg_auth_key2', controller=a_controller, proof='a_deleg_proof_validated_by_the_resolver', revoked=True), }
def test_building_a_register_doc_raises_if_same_delegation_is_added_twice( doc_keys): duplicate_deleg_control_key1 = RegisterDelegationProof( name=doc_keys['#deleg_control_key1'].name, controller=Issuer('did:iotics:iotHjrmKpPGWyEC4FFo4d6oyzVVk6MXFFFFF', '#AController'), proof=doc_keys['#deleg_control_key1'].proof, revoked=doc_keys['#deleg_control_key1'].revoked) with pytest.raises(IdentityRegisterDocumentKeyConflictError): RegisterDocumentBuilder() \ .add_control_delegation_obj(doc_keys['#deleg_control_key1']) \ .add_control_delegation_obj(duplicate_deleg_control_key1)
def doc_delegating_authentication(delegating_issuer_name, delegating_secrets, allowed_issuer_secrets, allowed_issuer): doc = get_valid_document_from_secret(delegating_secrets, delegating_issuer_name) delegating_issuer = Issuer.build(doc.did, delegating_issuer_name) proof = Proof.build(allowed_issuer_secrets, allowed_issuer, content=delegating_issuer.did.encode()) return RegisterDocumentBuilder() \ .add_authentication_delegation_obj(RegisterDelegationProof.build('#ADeleg', controller=allowed_issuer, proof=proof.signature)) \ .build_from_existing(doc)
def auth_deleg_proof(): issuer1 = Issuer.from_string( 'did:iotics:iotHHHHKpPGWyEC4FFo4d6oyzVVk6MXLmEgY#ctrl1') issuer2 = Issuer.from_string( 'did:iotics:iotHHHHKpPGWyEC4FFo4d6oyzVVk6MXLmEgY#ctrl2') issuer3 = Issuer.from_string( 'did:iotics:iotHHHHKpPGWyEC4FFo4d6oyzVVk6MXLmEgY#ctrl3') return { '#DelegAuthKey1': RegisterDelegationProof.build('#DelegAuthKey1', issuer1, proof='proof', revoked=False), '#DelegAuthKey2': RegisterDelegationProof.build('#DelegAuthKey2', issuer2, proof='proof', revoked=False), '#DelegAuthKey3': RegisterDelegationProof.build('#DelegAuthKey3', issuer3, proof='proof', revoked=False), }
def get_delegation_register_proof( subject_key_pair_secrets: KeyPairSecrets, subject_issuer: Issuer, content: bytes, p_type: DelegationProofType, deleg_key_name='#DelegKey') -> RegisterDelegationProof: proof = Proof.build(subject_key_pair_secrets, subject_issuer, content=content) return RegisterDelegationProof.build(deleg_key_name, controller=subject_issuer, proof=proof.signature, p_type=p_type, revoked=False)
def add_control_delegation(self, name: str, controller: Issuer, proof: str, revoked: Optional[bool] = False) -> 'RegisterDocumentBuilder': """ Add control delegation public key to document under build. :param name: key name :param controller: control delegation controller :param proof: control delegation proof :param revoked: is revoked (default=False) :return: self :raises: IdentityValidationError: if invalid control delegation public key IdentityRegisterDocumentKeyConflictError: if key name is not unique """ key = RegisterDelegationProof.build(name, controller, proof, revoked) self._check_and_update_map(name, key, self.control_delegations, 'Control delegation name') return self
def get_docs_for_issuer_key_from_auth_delegation( doc_did: str, deleg_doc_did: str, issuer: Issuer) -> Dict[str, RegisterDocument]: """ The issuer is in the auth delegation of the provided doc And the issuer is in the auth keys of the delegation doc """ doc = get_doc_with_keys(deleg_control=[ RegisterDelegationProof.build(issuer.name, controller=Issuer( 'deleg_doc_did', '#plop'), proof='proof', revoked=False), ]) deleg_doc = get_doc_with_keys(public_keys=[ RegisterPublicKey.build(issuer.name, 'base58Key1', revoked=False) ]) return {doc_did: doc, deleg_doc_did: deleg_doc}
def test_validate_delegation_raises_validation_error_if_invalid_proof_type( doc_did, deleg_doc_did, valid_issuer_key): controller_name = '#AController' deleg_proof = RegisterDelegationProof(name='#DelegKey', controller=Issuer.build( deleg_doc_did, controller_name), proof='a signature', proof_type='not existing type', revoked=False) deleg_doc = get_delegation_doc_for( controller_name=controller_name, doc_id=deleg_doc_did, public_base58=valid_issuer_key.public_key_base58) resolver_client = ResolverClientTest(docs={deleg_doc_did: deleg_doc}) with pytest.raises(IdentityInvalidDocumentDelegationError) as wrapper: DelegationValidation.validate_delegation(resolver_client, doc_id=doc_did, deleg_proof=deleg_proof) assert "Invalid proof: invalid type" in str(wrapper.value)
def add_control_delegation_proof_to_document(self, proof: APIProof, subject_issuer: Issuer, delegation_name: str, doc_owner_issuer: Issuer, doc_owner_key_pair: KeyPair): """ Add register control delegation proof to a register document. :param proof: proof :param subject_issuer: subject/delegated issuer :param delegation_name: register control delegation proof name :param doc_owner_key_pair: register document owner key pair :param doc_owner_issuer: register document owner issuer :raises: IdentityValidationError: if invalid register control delegation proof name IdentityRegisterDocumentKeyConflictError: if control delegation proof name is not unique within the register document IdentityInvalidDocumentError: if invalid register document IdentityResolverError: if resolver error """ key = RegisterDelegationProof.build(delegation_name, subject_issuer, proof.signature, p_type=get_proof_type(proof)) self._update_doc(doc_owner_key_pair, doc_owner_issuer, get_updated_doc=self.ctrl_deleg_api.add_doc_key, key=key)
def doc_with_doc_deleg(valid_issuer_key, doc_did, deleg_doc_did): doc = get_doc_with_keys( did=doc_did, public_keys=[ RegisterPublicKey.build('#Key1', 'base58Key1', revoked=False) ], deleg_control=[ RegisterDelegationProof.build(valid_issuer_key.issuer.name, controller=Issuer.build( deleg_doc_did, '#plop1'), proof='aproof', revoked=False), ], ) deleg_doc = get_doc_with_keys(did=deleg_doc_did, public_keys=[ RegisterPublicKey.build( valid_issuer_key.issuer.name, valid_issuer_key.public_key_base58, revoked=False), ]) return doc, deleg_doc
def test_can_build_a_register_doc_from_an_other_doc_overriding_values( full_doc): existing_doc = full_doc new_creator = 'did:iotics:iotEEEEKpPGWyEC4FFo4d6oyzVVk6MEEEEgY' new_controller = Issuer.build( 'did:iotics:iotEEEEKpPGWyEC4FFo4d6oyzHHHHMEEEEgY', '#NewController') new_metadata = Metadata(label='a label') new_version = SUPPORTED_VERSIONS[0] new_pub_key = RegisterPublicKey(name='#new_pub_key1', base58=get_public_base_58_key(), revoked=False) new_auth_key = RegisterAuthenticationPublicKey( name='#new_auth_key1', base58=get_public_base_58_key(), revoked=False) a_controller = Issuer.from_string( 'did:iotics:iotHjrmKpPGWyEC4FFo4d6oyzVVk6MXEEEEE#AController') new_control_deleg_proof = RegisterDelegationProof( name='#new_deleg_control_key1', controller=a_controller, proof='a_deleg_proof_validated_by_the_resolver', revoked=False) new_auth_deleg_key = RegisterDelegationProof( name='#new_deleg_auth_key1', controller=a_controller, proof='a_deleg_proof_validated_by_the_resolver', revoked=False) new_doc = RegisterDocumentBuilder() \ .add_public_key_obj(new_pub_key) \ .add_authentication_key_obj(new_auth_key) \ .add_control_delegation_obj(new_control_deleg_proof) \ .add_authentication_delegation_obj(new_auth_deleg_key) \ .build_from_existing(existing_doc, revoked=True, metadata=new_metadata, creator=new_creator, spec_version=new_version, controller=new_controller) # Can not change assert new_doc.did == existing_doc.did assert new_doc.purpose == existing_doc.purpose assert new_doc.proof == existing_doc.proof # Overridden values assert new_doc.revoked assert new_doc.metadata == new_metadata assert new_doc.creator == new_creator assert new_doc.spec_version == new_version assert new_doc.controller == new_controller assert new_doc.public_keys == { **existing_doc.public_keys, **{ new_pub_key.name: new_pub_key } } assert new_doc.auth_keys == { **existing_doc.auth_keys, **{ new_auth_key.name: new_auth_key } } assert new_doc.control_delegation_proof == { **existing_doc.control_delegation_proof, **{ new_control_deleg_proof.name: new_control_deleg_proof } } assert new_doc.auth_delegation_proof == { **existing_doc.auth_delegation_proof, **{ new_auth_deleg_key.name: new_auth_deleg_key } } assert new_doc.update_time >= existing_doc.update_time
def register_doc_and_deleg_doc( doc_did: str, deleg_doc_did: str) -> Tuple[RegisterDocument, RegisterDocument]: """ Creates a document and a delegation document with all the key combinations (See KEY_NAMES) for the "get issuer from" tests with and without delegation and with and without included authentication """ doc = get_doc_with_keys( did=doc_did, public_keys=[ RegisterPublicKey.build(KEYS_NAMES.key_only_in_doc_pub_keys, 'base58Key1', revoked=False) ], auth_keys=[ RegisterAuthenticationPublicKey.build( KEYS_NAMES.key_only_in_doc_auth_keys, 'base58Key2', revoked=False) ], deleg_control=[ RegisterDelegationProof.build( KEYS_NAMES.key_in_doc_control_deleg_and_deleg_doc_pub_keys, controller=Issuer('deleg_doc_did', '#plop1'), proof='aproof', revoked=False), RegisterDelegationProof.build( KEYS_NAMES.key_in_doc_control_deleg_and_deleg_doc_auth_keys, controller=Issuer('deleg_doc_did', '#plop2'), proof='aproof', revoked=False), RegisterDelegationProof.build( KEYS_NAMES.key_in_doc_control_deleg_and_not_in_deleg_doc, controller=Issuer('deleg_doc_did', '#plop3'), proof='aproof', revoked=False), ], deleg_auth=[ RegisterDelegationProof.build( KEYS_NAMES.key_in_doc_auth_deleg_and_deleg_doc_pub_keys, controller=Issuer('deleg_doc_did', '#plop4'), proof='aproof', revoked=False), RegisterDelegationProof.build( KEYS_NAMES.key_in_doc_auth_deleg_and_deleg_doc_auth_keys, controller=Issuer('deleg_doc_did', '#plop5'), proof='aproof', revoked=False), RegisterDelegationProof.build( KEYS_NAMES.key_in_doc_auth_deleg_and_not_in_deleg_doc, controller=Issuer('deleg_doc_did', '#plop6'), proof='aproof', revoked=False), ], ) deleg_doc = get_doc_with_keys( did=deleg_doc_did, public_keys=[ RegisterPublicKey.build( KEYS_NAMES.key_in_doc_control_deleg_and_deleg_doc_pub_keys, 'base58K11', revoked=False), RegisterPublicKey.build( KEYS_NAMES.key_in_doc_auth_deleg_and_deleg_doc_pub_keys, 'base58K12', revoked=False) ], auth_keys=[ RegisterAuthenticationPublicKey.build( KEYS_NAMES.key_in_doc_control_deleg_and_deleg_doc_auth_keys, 'base58K13', revoked=False), RegisterAuthenticationPublicKey.build( KEYS_NAMES.key_in_doc_auth_deleg_and_deleg_doc_auth_keys, 'base58K14', revoked=False) ]) return doc, deleg_doc
def test_build_register_delegation_proof_from_dict_raises_validation_error_if_invalid_dict( ): with pytest.raises(IdentityValidationError): RegisterDelegationProof.from_dict({'invalid': 'data'})