Beispiel #1
0
    def _delegate(self, delegating_secrets: KeyPairSecrets, delegating_did: str,
                  subject_secrets: KeyPairSecrets, subject_did: str, delegation_name: str,
                  proof_type: DelegationProofType, delegation_proof_add_method: Callable):
        delegating_doc = self.get_register_document(delegating_did)
        subject_doc = self.get_register_document(subject_did)
        delegating_key_pair = KeyPairSecretsHelper.get_key_pair(delegating_secrets)
        delegating_issuer = AdvancedIdentityLocalApi.get_issuer_by_public_key(delegating_doc,
                                                                              delegating_key_pair.public_base58)
        if proof_type == DelegationProofType.GENERIC:
            subject_issuer, proof = AdvancedIdentityLocalApi.create_generic_delegation_proof(subject_doc,
                                                                                             subject_secrets)
        else:
            subject_issuer, proof = AdvancedIdentityLocalApi.create_delegation_proof(delegating_issuer,
                                                                                     subject_doc,
                                                                                     subject_secrets)

        existing_delegation = RegisterDocumentHelper.get_register_delegation_proof_by_controller(subject_issuer,
                                                                                                 delegating_doc,
                                                                                                 True)
        if existing_delegation and (
                not delegation_name or delegation_name == existing_delegation.name
        ):
            # Found an existing delegation with matching controller and name. Nothing to do.
            return

        if not delegation_name:
            delegation_name = RegisterDocumentHelper.new_random_name_for_document(subject_doc)

        delegation_proof_add_method(proof, subject_issuer, delegation_name,
                                    delegating_issuer, delegating_key_pair)
Beispiel #2
0
def test_can_get_issuer_from_auth_keys(auth_keys, min_doc_owner_pub_key):
    doc = get_doc_with_keys(auth_keys=auth_keys.values(),
                            public_keys=[min_doc_owner_pub_key])
    issuer_name = '#AuthKey2'
    issuer_key = RegisterDocumentHelper.get_issuer_register_key(
        issuer_name, doc, include_auth=True)
    assert issuer_key == auth_keys[issuer_name]
    def verify_authentication(resolver_client: ResolverClient, token: str) -> dict:
        """
        Verify if the authentication token is allowed for authentication.
        :param resolver_client: resolver client interface
        :param token: jwt authentication token
        :return: decoded verified authentication token

        :raises:
            IdentityAuthenticationFailed: if not allowed for authentication
        """
        try:
            unverified_token = JwtTokenHelper.decode_token(token)
            for field in ('iss', 'sub', 'aud', 'iat', 'exp'):
                if field not in unverified_token:
                    raise IdentityValidationError(f'Invalid token, missing {field} field')
            issuer = Issuer.from_string(unverified_token['iss'])
            doc = resolver_client.get_document(issuer.did)
            get_controller_doc = resolver_client.get_document
            issuer_key = RegisterDocumentHelper.get_valid_issuer_key_for_auth(doc, issuer.name, get_controller_doc)
            if not issuer_key:
                raise IdentityInvalidRegisterIssuerError(f'Invalid issuer {issuer}')
            verified_token = JwtTokenHelper.decode_and_verify_token(token, issuer_key.public_key_base58,
                                                                    unverified_token['aud'])

            IdentityAuthValidation.validate_allowed_for_auth(resolver_client, issuer_key.issuer, verified_token['sub'])

            return {'iss': verified_token['iss'],
                    'sub': verified_token['sub'],
                    'aud': verified_token['aud'],
                    'iat': verified_token['iat'],
                    'exp': verified_token['exp']}
        except (IdentityValidationError, IdentityResolverError,
                IdentityInvalidRegisterIssuerError, IdentityNotAllowed) as err:
            raise IdentityAuthenticationFailed('Not authenticated') from err
Beispiel #4
0
    def from_challenge_token(resolver_client: ResolverClient,
                             challenge_token: str) -> 'Proof':
        """
        Build proof from challenge token.
        :param resolver_client: resolver client to get the registered documents
        :param challenge_token: jwt challenge token
        :return: valid proof

        :raises:
            IdentityValidationError: if invalid challenge token
        """
        decoded_token = JwtTokenHelper.decode_token(challenge_token)
        iss = decoded_token.get('iss')
        aud = decoded_token.get('aud')
        if not iss or not aud:
            raise IdentityValidationError(
                'Invalid challenge token, missing \'iss\' or \'aud\'')

        issuer = Issuer.from_string(iss)
        doc = resolver_client.get_document(issuer.did)
        get_controller_doc = resolver_client.get_document
        issuer_key = RegisterDocumentHelper.get_valid_issuer_key_for_control_only(
            doc, issuer.name, get_controller_doc)
        if not issuer_key:
            raise IdentityInvalidRegisterIssuerError(
                f'Invalid issuer {issuer}')
        verified_token = JwtTokenHelper.decode_and_verify_token(
            challenge_token, issuer_key.public_key_base58, aud)
        return Proof(issuer_key.issuer, aud.encode('ascii'),
                     verified_token['proof'])
Beispiel #5
0
    def get_valid_doc_from_token(
            token: str,
            get_controller_doc: GetControllerDocFunc) -> RegisterDocument:
        """
        Get a valid RegisterDocument from a resolver token.
        :param token: resolver token
        :param get_controller_doc: get controller register document function
        :return: valid register document

        :raises:
            IdentityResolverError: if invalid token
            IdentityResolverError: if invalid document
        """
        try:
            unverified = JwtTokenHelper.decode_token(token)
            doc = RegisterDocumentBuilder().build_from_dict(unverified['doc'])
            issuer = Issuer.from_string(unverified['iss'])
            issuer_key = RegisterDocumentHelper.get_valid_issuer_key_for_control_only(
                doc, issuer.name, get_controller_doc)
            if not issuer_key:
                raise IdentityInvalidRegisterIssuerError(
                    f'Invalid issuer {issuer}')
            JwtTokenHelper.decode_and_verify_token(
                token, issuer_key.public_key_base58, unverified['aud'])
            return doc
        except (KeyError, ValueError, IdentityValidationError,
                IdentityInvalidRegisterIssuerError) as exc:
            raise IdentityResolverError(
                f'Can not deserialized invalid resolver token: \'{exc}\''
            ) from exc
Beispiel #6
0
def test_get_issuer_from_auth_keys_returns_none_if_not_found(
        auth_keys, min_doc_owner_pub_key):
    doc = get_doc_with_keys(auth_keys=auth_keys.values(),
                            public_keys=[min_doc_owner_pub_key])
    issuer_name = '#DoesNotExist'
    issuer_key = RegisterDocumentHelper.get_issuer_register_key(
        issuer_name, doc, include_auth=True)
    assert not issuer_key
Beispiel #7
0
def test_can_get_issuer_from_auth_delegation(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_name = '#DelegAuthKey2'
    issuer_key = RegisterDocumentHelper.get_issuer_register_delegation_proof(
        issuer_name, doc, include_auth=True)
    assert issuer_key == auth_deleg_proof[issuer_name]
Beispiel #8
0
def test_get_issuer_from_control_delegation_returns_none_if_not_found(
        control_deleg_proof, min_doc_owner_pub_key):
    doc = get_doc_with_keys(deleg_control=control_deleg_proof.values(),
                            public_keys=[min_doc_owner_pub_key])
    issuer_name = '#DoesNotExist'
    issuer_key = RegisterDocumentHelper.get_issuer_register_delegation_proof(
        issuer_name, doc, include_auth=False)
    assert not issuer_key
Beispiel #9
0
def test_can_get_auth_delegation_by_controller(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])
    delegation_name = '#DelegAuthKey2'
    expected_deleg_proof = auth_deleg_proof[delegation_name]
    deleg_proof = RegisterDocumentHelper.get_register_delegation_proof_by_controller(
        expected_deleg_proof.controller, doc, include_auth=True)
    assert deleg_proof == expected_deleg_proof
Beispiel #10
0
def test_get_issuer_from_auth_delegation_returns_none_if_in_auth_keys_but_auth_not_included(
        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_name = '#DelegAuthKey2'
    assert issuer_name in doc.auth_delegation_proof
    issuer_key = RegisterDocumentHelper.get_issuer_register_delegation_proof(
        issuer_name, doc, include_auth=False)
    assert not issuer_key
Beispiel #11
0
def test_get_issuer_from_auth_keys_returns_none_if_in_auth_keys_but_auth_not_included(
        auth_keys, min_doc_owner_pub_key):
    doc = get_doc_with_keys(auth_keys=auth_keys.values(),
                            public_keys=[min_doc_owner_pub_key])
    issuer_name = '#AuthKey2'
    assert issuer_name in doc.auth_keys
    issuer_key = RegisterDocumentHelper.get_issuer_register_key(
        issuer_name, doc, include_auth=False)
    assert not issuer_key
Beispiel #12
0
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
Beispiel #13
0
def test_get_valid_issuer_for_auth_returns_none_if_not_found(
        issuer_name, register_doc_and_deleg_doc):
    def get_ctrl_doc(did: str):
        assert did.startswith(did)
        return deleg_doc

    doc, deleg_doc = register_doc_and_deleg_doc
    issuer_key = RegisterDocumentHelper.get_valid_issuer_key_for_auth(
        doc, issuer_name, get_ctrl_doc)
    assert not issuer_key
Beispiel #14
0
def test_get_owner_public_key_returns_none_if_not_found(
        valid_key_pair, other_key_pair):
    doc_id = make_identifier(valid_key_pair.public_bytes)
    doc = RegisterDocumentBuilder() \
        .add_public_key_obj(RegisterPublicKey('#NotOwner', other_key_pair.public_base58, revoked=False)) \
        .build(doc_id,
               DIDType.TWIN,
               proof='a proof, does not matter here',
               revoked=False)
    key = RegisterDocumentHelper.get_owner_register_public_key(doc)
    assert not key
Beispiel #15
0
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 is_allowed_for(issuer: Issuer, issuer_doc: RegisterDocument, subject_doc: RegisterDocument,
                       include_auth: bool) -> bool:
        """
        Check if the issuer is allowed for control (authentication if include_auth = True) on the subject register
        document.
        Issuer is allowed if both the issuer and subject register document are not revoked
        AND (
             ( the issuer is the owner of the subject register document
             OR
              if a include_auth=True the issuer is in the authentication public keys of the subject register document
             )
             OR
             the issuer is delegated for control (authentication if include_auth = True) with a valid delegation proof
             on the subject registered document
        )

        :param issuer: issuer
        :param issuer_doc: issuer register document
        :param subject_doc: subject register document
        :param include_auth: include authentication keys and delegation proof is set to True
        :return: True is allowed else False
        """
        if issuer_doc.revoked or subject_doc.revoked:
            return False

        if is_same_identifier(issuer.did, subject_doc.did):  # it is the same document
            issuer_key = RegisterDocumentHelper.get_issuer_register_key(issuer.name, subject_doc, include_auth)
            if issuer_key and not issuer_key.revoked:
                return True

        delegation_proof = RegisterDocumentHelper.get_register_delegation_proof_by_controller(issuer, subject_doc,
                                                                                              include_auth)
        if delegation_proof:
            try:
                DelegationValidation.validate_delegation_from_doc(subject_doc.did, issuer_doc, delegation_proof)
            except IdentityInvalidDocumentDelegationError:
                return False
            return not delegation_proof.revoked
        return False
Beispiel #17
0
    def get_issuer_by_public_key(doc: RegisterDocument, public_base58: str) -> Issuer:
        """
        Get issuer matching the public key from a register document public keys.
        :param doc: register document
        :param public_base58: issuer public key base 58
        :return: corresponding issuer

        :raises:
            IdentityRegisterIssuerNotFoundError: if the issuer matching the public key is not found
        """
        issuer = RegisterDocumentHelper.get_issuer_from_public_key(doc, public_base58)
        if not issuer:
            raise IdentityRegisterIssuerNotFoundError(f'User secrets not allowed to update \'{doc.did}\'')
        return issuer
Beispiel #18
0
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
Beispiel #19
0
    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
Beispiel #20
0
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
Beispiel #21
0
def test_is_issuer_in_keys_returns_true_if_issuer_in_auth_keys(
        public_keys, auth_keys, issuer_name, include_auth, expected_res):
    doc = get_doc_with_keys(public_keys.values(), auth_keys.values())
    assert RegisterDocumentHelper.is_issuer_in_keys(
        issuer_name, doc, include_auth) == expected_res
Beispiel #22
0
def test_can_get_issuer_from_public_keys(public_keys):
    doc = get_doc_with_keys(public_keys=public_keys.values())
    issuer_name = '#Key2'
    issuer_key = RegisterDocumentHelper.get_issuer_register_key(
        issuer_name, doc, include_auth=False)
    assert issuer_key == public_keys[issuer_name]
Beispiel #23
0
def test_get_issuer_from_public_keys_returns_none_if_not_found(public_keys):
    doc = get_doc_with_keys(public_keys=public_keys.values())
    issuer_name = '#DoesNotExist'
    issuer_key = RegisterDocumentHelper.get_issuer_register_key(
        issuer_name, doc, include_auth=False)
    assert not issuer_key