def new_registered_identity(self, purpose: DIDType, key_pair_secrets: KeyPairSecrets, name: str = None, override_doc: bool = False) -> RegisteredIdentity: """ Create and register a new registered identity and its associated register document against the resolver. :param key_pair_secrets: new registered identity owner secrets :param name: Optional new registered identity name (default: '#<purpose>-0') following this pattern: '#[a-zA-Z\\-\\_0-9]{1, 24}' :param purpose: registered identity purpose (HOST, TWIN, USER or AGENT) :param override_doc: override registered identity document if already exist (default False) :return: registered identity :raises: IdentityValidationError: if invalid secrets IdentityValidationError: if invalid name IdentityInvalidDocumentError: if document build error IdentityResolverConflictError: register document already exists with different owners IdentityResolverError: if can not interact with the resolver IdentityDependencyError: if incompatible library dependency """ key_pair = KeyPairSecretsHelper.get_key_pair(key_pair_secrets) did = AdvancedIdentityLocalApi.create_identifier(key_pair.public_bytes) name = name or f'{ISSUER_SEPARATOR}{purpose}-0' issuer = Issuer.build(did, name) if override_doc: self.register_new_doc(key_pair_secrets, issuer, purpose) return RegisteredIdentity(key_pair_secrets, issuer) issuer_key = IssuerKey.build(issuer.did, issuer.name, key_pair.public_base58) return self.register_new_identity_if_not_exists(issuer_key, key_pair_secrets, purpose)
def test_get_auth_delegation_by_controller_returns_none_if_not_found( auth_deleg_proof, min_doc_owner_pub_key): doc = get_doc_with_keys(deleg_auth=auth_deleg_proof.values(), public_keys=[min_doc_owner_pub_key]) issuer = Issuer.build('did:iotics:iotHHHHKpPGWyEC4FFo4d6oyzVVk6MXLmEgY', '#DoesNotExist') deleg_proof = RegisterDocumentHelper.get_register_delegation_proof_by_controller( issuer, doc, include_auth=True) assert not deleg_proof
def test_register_doc_raises_resolver_error_if_can_not_register( valid_key_pair_secrets, valid_key_pair): resolver_client = ResolverClientTestWithError( register_err=IdentityResolverError('an error')) api = AdvancedIdentityRegisterApi(resolver_client) issuer = Issuer.build(make_identifier(valid_key_pair.public_bytes), '#NewIssuer') with pytest.raises(IdentityResolverError): api.register_new_doc(valid_key_pair_secrets, issuer, DIDType.AGENT)
def test_get_valid_doc_from_token_raises_invalid_issuer_if_can_not_find_issuer( simple_doc, valid_private_key): not_in_doc_issuer = Issuer.build(simple_doc.did, '#NotInDoc') token = get_inconsistent_token(str(not_in_doc_issuer), simple_doc.to_dict(), valid_private_key) with pytest.raises(IdentityResolverError) as err_wrapper: ResolverSerializer.get_valid_doc_from_token( token, get_controller_doc=raise_if_called) assert isinstance(err_wrapper.value.__cause__, IdentityInvalidRegisterIssuerError)
def get_valid_delegated_doc_and_deleg_proof(seed: bytes, issuer_name: str, delegating_doc_id: str, deleg_name: str): secrets = KeyPairSecrets.build(seed, 'iotics/0/something/twindeleg') public_base58 = KeyPairSecretsHelper.get_public_key_base58_from_key_pair_secrets( secrets) public_bytes = base58.b58decode(public_base58) doc_id = make_identifier(public_bytes) issuer = Issuer.build(doc_id, issuer_name) proof = Proof.build(secrets, issuer, content=doc_id.encode()) deleg_key = get_delegation_register_proof( subject_key_pair_secrets=secrets, content=delegating_doc_id.encode(), p_type=DelegationProofType.DID, subject_issuer=Issuer.build(doc_id, issuer_name), deleg_key_name=deleg_name) delegated_doc = RegisterDocumentBuilder() \ .add_public_key_obj(RegisterPublicKey(issuer_name, public_base58, revoked=False)) \ .build(doc_id, DIDType.TWIN, proof=proof.signature, revoked=False) return delegated_doc, deleg_key
def test_build_proof_from_challenge_token_raises_issuer_error_if_issuer_not_in_doc( register_doc, valid_private_key, valid_key_pair_secrets): other_issuer = Issuer.build(register_doc.did, '#OtherIssuer') proof = Proof.build(valid_key_pair_secrets, other_issuer, content=b'a content') challenge_token = build_new_challenge_token(proof, valid_private_key) resolver_client = ResolverClientTest(docs={register_doc.did: register_doc}) with pytest.raises(IdentityInvalidRegisterIssuerError): Proof.from_challenge_token(resolver_client, challenge_token)
def test_can_get_issuer_by_public_key(valid_key_pair): doc_did = make_identifier(valid_key_pair.public_bytes) key_issuer = Issuer.build(doc_did, '#AnIssuer') doc = RegisterDocumentBuilder() \ .add_public_key_obj(RegisterPublicKey(key_issuer.name, valid_key_pair.public_base58, revoked=False)) \ .build(key_issuer.did, DIDType.TWIN, proof='a proof, does not matter here', revoked=False) issuer = RegisterDocumentHelper.get_issuer_from_public_key( doc, valid_key_pair.public_base58) assert issuer == key_issuer
def test_can_register_a_doc(valid_key_pair_secrets, valid_key_pair): resolver_client = ResolverClientTest(docs={}) api = AdvancedIdentityRegisterApi(resolver_client) did = make_identifier(valid_key_pair.public_bytes) issuer = Issuer.build(did, '#NewIssuer') api.register_new_doc(valid_key_pair_secrets, issuer, DIDType.AGENT) registered_doc = resolver_client.docs.get(issuer.did) assert registered_doc owner_key = registered_doc.public_keys.get(issuer.name) assert owner_key.name == issuer.name assert owner_key.base58 == valid_key_pair.public_base58 assert not owner_key.revoked
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 test_validate_delegation_raises_validation_error_if_delegation_to_self( deleg_doc_did, valid_key_pair_secrets): deleg_proof = get_delegation_register_proof( subject_key_pair_secrets=valid_key_pair_secrets, # parent and delegated doc are the same content=deleg_doc_did.encode(), p_type=DelegationProofType.DID, subject_issuer=Issuer.build(deleg_doc_did, '#AController')) resolver_client = ResolverClientTest() with pytest.raises(IdentityInvalidDocumentDelegationError): DelegationValidation.validate_delegation(resolver_client, doc_id=deleg_doc_did, deleg_proof=deleg_proof)
def test_validate_delegation_raises_validation_error_if_resolver_error( doc_did, deleg_doc_did, valid_key_pair_secrets, resolver_err): controller_name = '#AController' deleg_proof = get_delegation_register_proof( subject_key_pair_secrets=valid_key_pair_secrets, content=doc_did.encode(), p_type=DelegationProofType.DID, subject_issuer=Issuer.build(deleg_doc_did, controller_name)) resolver_client = ResolverClientWithError(error_to_raise=resolver_err()) with pytest.raises(IdentityInvalidDocumentDelegationError) as err_wrapper: DelegationValidation.validate_delegation(resolver_client, doc_id=doc_did, deleg_proof=deleg_proof) assert isinstance(err_wrapper.value.__cause__, resolver_err)
def get_issuer_from_public_key(doc: RegisterDocument, public_base58: str) -> Optional[Issuer]: """ Find a register key by issuer and returns True/False if found. Lookup in the register document public keys (and authentication keys if include_auth is set to True). :param doc: existing register document :param public_base58: public key to search for as base58 string :return: Issuer or None :raises: IdentityValidationError: if invalid name or did """ for key in doc.public_keys.values(): if key.base58 == public_base58: return Issuer.build(doc.did, key.name) return None
def test_can_get_valid_issuer_for_control_only(issuer_name, register_doc_and_deleg_doc): doc, deleg_doc = register_doc_and_deleg_doc def get_ctrl_doc(did: str): assert did.startswith(did) return deleg_doc assert issuer_name in doc.public_keys or issuer_name in deleg_doc.public_keys issuer_key = RegisterDocumentHelper.get_valid_issuer_key_for_control_only( doc, issuer_name, get_ctrl_doc) assert issuer_key.issuer == Issuer.build(doc.did, issuer_name) expected_base58 = doc.public_keys.get( issuer_name, deleg_doc.public_keys.get(issuer_name)) assert expected_base58, f'test setup error, {issuer_name} should be in one of the docs public keys' assert issuer_key.public_key_base58 == expected_base58.base58
def test_validate_delegation_raises_validation_error_if_invalid_delegation_proof( doc_did, deleg_doc_did, valid_issuer_key, other_key_pair_secrets): controller_name = '#AController' corrupted_deleg_proof = get_delegation_register_proof( subject_key_pair_secrets=other_key_pair_secrets, content=doc_did.encode(), p_type=DelegationProofType.DID, subject_issuer=Issuer.build(deleg_doc_did, controller_name)) 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 err_wrapper: DelegationValidation.validate_delegation( resolver_client, doc_id=doc_did, deleg_proof=corrupted_deleg_proof) assert isinstance(err_wrapper.value.__cause__, IdentityInvalidProofError)
def test_verify_authentication_raises_auth_error_if_issuer_not_in_doc_keys_or_deleg( authentication_subject_doc, valid_private_key): not_auth_issuer = Issuer.build(authentication_subject_doc.did, '#OtherIssuer') token_from_not_auth_issuer = JwtTokenHelper.create_auth_token( iss=str(not_auth_issuer), sub=authentication_subject_doc.did, aud='http://audience/', duration=360, private_key=valid_private_key) resolver_client = ResolverClientTest( docs={authentication_subject_doc.did: authentication_subject_doc}) with pytest.raises(IdentityAuthenticationFailed) as err_wrapper: IdentityAuthValidation.verify_authentication( resolver_client, token=token_from_not_auth_issuer) assert isinstance(err_wrapper.value.__cause__, IdentityInvalidRegisterIssuerError)
def get_valid_document_from_secret(secrets: KeyPairSecrets, issuer_name: str, controller: Issuer = None): public_base58 = KeyPairSecretsHelper.get_public_key_base58_from_key_pair_secrets( secrets) public_bytes = base58.b58decode(public_base58) doc_id = make_identifier(public_bytes) proof = Proof.build(secrets, Issuer.build(doc_id, issuer_name), content=doc_id.encode()) return RegisterDocumentBuilder() \ .add_public_key_obj(RegisterPublicKey(issuer_name, public_base58, revoked=False)) \ .build(doc_id, DIDType.TWIN, proof=proof.signature, revoked=False, controller=controller)
def test_can_validate_delegation(doc_did, deleg_doc_did, valid_issuer_key, valid_key_pair_secrets, proof_type, get_content): controller_name = '#AController' deleg_proof = get_delegation_register_proof( subject_key_pair_secrets=valid_key_pair_secrets, content=get_content(doc_did), p_type=proof_type, subject_issuer=Issuer.build(deleg_doc_did, controller_name)) 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}) assert is_validator_run_success(DelegationValidation.validate_delegation, resolver_client, doc_id=doc_did, deleg_proof=deleg_proof)
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 test_can_validate_allowed_for_auth_with_controller_doc( allowed_issuer, allowed_issuer_doc): controller_issuer_doc = allowed_issuer_doc controller_issuer = Issuer.build(controller_issuer_doc.did, '#Plop') a_doc_with_controller_allowed_for_auth = get_valid_document( new_seed(), '#ASubject', controller=controller_issuer) resolver_docs = { controller_issuer.did: controller_issuer_doc, a_doc_with_controller_allowed_for_auth.did: a_doc_with_controller_allowed_for_auth } resolver_client = ResolverClientTest(docs=resolver_docs) assert is_validator_run_success( IdentityAuthValidation.validate_allowed_for_auth, resolver_client, allowed_issuer, subject_id=a_doc_with_controller_allowed_for_auth.did)
def remove_authentication_key_from_document(self, name: str, doc_owner_key_pair: KeyPair, doc_owner_issuer: Issuer) -> Issuer: """ Remove a register authentication public key from a register document. :param name: authentication public key name :param doc_owner_key_pair: register document owner key pair :param doc_owner_issuer: register document owner issuer :return: new key issuer :raises: IdentityValidationError: if invalid authentication public key name IdentityInvalidDocumentError: if invalid register document IdentityResolverError: if resolver error """ self._update_doc(doc_owner_key_pair, doc_owner_issuer, get_updated_doc=self.auth_key_api.remove_doc_key, key_name=name) return Issuer.build(doc_owner_issuer.did, name)
def test_can_get_valid_issuer_for_auth(issuer_name, register_doc_and_deleg_doc): doc, deleg_doc = register_doc_and_deleg_doc def get_ctrl_doc(did: str): assert did.startswith(did) return deleg_doc all_keys = list(doc.public_keys) + list(doc.auth_keys) + list( deleg_doc.public_keys) + list(deleg_doc.auth_keys) assert issuer_name in all_keys issuer_key = RegisterDocumentHelper.get_valid_issuer_key_for_auth( doc, issuer_name, get_ctrl_doc) assert issuer_key.issuer == Issuer.build(doc.did, issuer_name) exp_base58 = doc.public_keys.get(issuer_name, doc.auth_keys.get(issuer_name)) exp_base58 = exp_base58 or deleg_doc.public_keys.get( issuer_name, deleg_doc.auth_keys.get(issuer_name)) assert exp_base58, f'test setup error, {issuer_name} should be in one of the docs public or auth keys' assert issuer_key.public_key_base58 == exp_base58.base58
def validate_new_document_proof(doc: RegisterDocument): """ Validate register document proof. :param doc: register document. :raises: IdentityInvalidDocumentError: if register document initial owner public key has been removed IdentityInvalidDocumentError: if register document proof is invalid """ try: key = RegisterDocumentHelper.get_owner_register_public_key(doc) if not key: raise IdentityInvalidDocumentError( f'Invalid document \'{doc.did}\', no owner public key') ProofValidation.validate_proof( Proof(Issuer.build(doc.did, key.name), doc.did.encode('ascii'), doc.proof), key.base58) except IdentityInvalidProofError as err: raise IdentityInvalidDocumentError( f'Invalid document \'{doc.did}\' proof: {err}') from err
def test_validate_delegation_raises_validation_error_if_content_does_not_match_proof_type( doc_did, deleg_doc_did, valid_issuer_key, valid_key_pair_secrets, wrong_type, get_content): controller_name = '#AController' deleg_proof = get_delegation_register_proof( subject_key_pair_secrets=valid_key_pair_secrets, content=get_content(doc_did), p_type=wrong_type, subject_issuer=Issuer.build(deleg_doc_did, controller_name)) 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 err_wrapper: DelegationValidation.validate_delegation(resolver_client, doc_id=doc_did, deleg_proof=deleg_proof) assert isinstance(err_wrapper.value.__cause__, IdentityInvalidProofError)
def revoke_authentication_key_from_document(self, name: str, revoked: bool, doc_owner_key_pair: KeyPair, doc_owner_issuer: Issuer) -> Issuer: """ Set register authentication public key revoke field. :param name: authentication public key name :param revoked: is revoked :param doc_owner_key_pair: register document owner key pair :param doc_owner_issuer: register document owner issuer :return: new key issuer :raises: IdentityValidationError: if invalid authentication public key name IdentityRegisterDocumentKeyNotFoundError: if register authentication public key not found IdentityInvalidDocumentError: if invalid register document IdentityResolverError: if resolver error """ self._update_doc(doc_owner_key_pair, doc_owner_issuer, get_updated_doc=self.auth_key_api.revoke_doc_key, key_name=name, revoked=revoked) return Issuer.build(doc_owner_issuer.did, name)
def test_validate_delegation_raises_validation_error_if_public_key_not_in_deleg_controller_doc( doc_did, deleg_doc_did, valid_issuer_key, valid_key_pair_secrets): controller_name = '#AController' deleg_proof = get_delegation_register_proof( subject_key_pair_secrets=valid_key_pair_secrets, content=doc_did.encode(), p_type=DelegationProofType.DID, subject_issuer=Issuer.build(deleg_doc_did, controller_name)) deleg_doc = get_doc_with_keys(did=doc_did, public_keys=[ RegisterPublicKey.build( '#NotMatchingTheController', valid_issuer_key.public_key_base58, revoked=False), ]) resolver_client = ResolverClientTest({deleg_doc_did: deleg_doc}) with pytest.raises(IdentityInvalidDocumentDelegationError) as err_wrapper: DelegationValidation.validate_delegation(resolver_client, doc_id=doc_did, deleg_proof=deleg_proof) assert isinstance(err_wrapper.value.__cause__, IdentityValidationError)
def add_public_key_to_document(self, name: str, new_public_key_base58: str, doc_owner_key_pair: KeyPair, doc_owner_issuer: Issuer) -> Issuer: """ Add a new register public key to a register document. :param name: new public key name :param new_public_key_base58: public key base 58 :param doc_owner_key_pair: register document owner key pair :param doc_owner_issuer: register document owner issuer :return: new register document owner issuer :raises: IdentityValidationError: if invalid new public key name IdentityRegisterDocumentKeyConflictError: if public key name is not unique within the register document IdentityInvalidDocumentError: if invalid register document IdentityResolverError: if resolver error """ new_key = RegisterPublicKey.build(name, new_public_key_base58) self._update_doc(doc_owner_key_pair, doc_owner_issuer, get_updated_doc=self.public_key_api.add_doc_key, key=new_key) return Issuer.build(doc_owner_issuer.did, name)
def test_can_delegate_control(base_doc, valid_key_pair_secrets, other_key_pair_secrets): subject_doc = get_valid_document_from_secret(other_key_pair_secrets, '#DelegatedDoc') resolver_client = ResolverClientTest(docs={ base_doc.did: base_doc, subject_doc.did: subject_doc }) api = AdvancedIdentityRegisterApi(resolver_client) assert not resolver_client.docs[base_doc.did].control_delegation_proof api.delegate_control(delegating_secrets=valid_key_pair_secrets, delegating_did=base_doc.did, subject_secrets=other_key_pair_secrets, subject_did=subject_doc.did, delegation_name='#NewControlDeleg') control_deleg = resolver_client.docs[ base_doc.did].control_delegation_proof.get('#NewControlDeleg') assert control_deleg assert control_deleg.name == '#NewControlDeleg' assert not control_deleg.revoked assert control_deleg.proof assert control_deleg.controller == Issuer.build(subject_doc.did, '#DelegatedDoc')
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 base_doc_issuer(base_doc, base_doc_issuer_name): return Issuer.build(base_doc.did, base_doc_issuer_name)
def other_doc_issuer(other_doc_did): return Issuer.build(other_doc_did, '#DelegatedDoc')