示例#1
0
def get_trusted_service(service_url=None,
                        service_uid=None,
                        service_type=None,
                        autofetch=True):
    """Return the trusted service info for the service with specified
       service_url or service_uid"""
    if service_url is not None:
        from Acquire.Service import Service as _Service
        service_url = _Service.get_canonical_url(service_url,
                                                 service_type=service_type)

    from Acquire.Service import is_running_service as _is_running_service

    if _is_running_service():
        from Acquire.Service import get_this_service as _get_this_service
        from Acquire.Service import Service as _Service
        from Acquire.Service import get_service_account_bucket as \
            _get_service_account_bucket
        from Acquire.ObjectStore import ObjectStore as _ObjectStore
        from Acquire.ObjectStore import url_to_encoded as \
            _url_to_encoded

        service = _get_this_service()

        if service_url is not None and service.canonical_url() == service_url:
            # we trust ourselves :-)
            return service

        if service_uid is not None and service.uid() == service_uid:
            # we trust ourselves :-)
            return service

        bucket = _get_service_account_bucket()
        uidkey = None
        data = None

        if service_uid is not None:
            uidkey = "_trusted/uid/%s" % service_uid
            try:
                data = _ObjectStore.get_object_from_json(bucket, uidkey)
            except:
                pass
        elif service_url is not None:
            urlkey = "_trusted/url/%s" % _url_to_encoded(service_url)
            try:
                uidkey = _ObjectStore.get_string_object(bucket, urlkey)
                if uidkey is not None:
                    data = _ObjectStore.get_object_from_json(bucket, uidkey)
            except:
                pass

        if data is not None:
            remote_service = _Service.from_data(data)

            if remote_service.should_refresh_keys():
                # need to update the keys in our copy of the service
                remote_service.refresh_keys()

                if uidkey is not None:
                    _ObjectStore.set_object_from_json(bucket, uidkey,
                                                      remote_service.to_data())

            return remote_service

        if not autofetch:
            from Acquire.Service import ServiceAccountError
            if service_uid is not None:
                raise ServiceAccountError(
                    "We do not trust the service with UID '%s'" % service_uid)
            else:
                raise ServiceAccountError(
                    "We do not trust the service at URL '%s'" % service_url)

        # we can try to fetch this data - we will ask our own
        # registry
        from Acquire.Registry import get_trusted_registry_service \
            as _get_trusted_registry_service
        registry = _get_trusted_registry_service(service_uid=service.uid())
        service = registry.get_service(service_uid=service_uid,
                                       service_url=service_url)

        from Acquire.Service import trust_service as _trust_service
        _trust_service(service)
        return service
    else:
        # this is running on the client
        from Acquire.Client import Wallet as _Wallet
        wallet = _Wallet()
        service = wallet.get_service(service_uid=service_uid,
                                     service_url=service_url,
                                     service_type=service_type,
                                     autofetch=autofetch)
        return service
示例#2
0
    def get_service(self, service_uid=None, service_url=None):
        """Load and return the service with specified url or uid
           from the registry. This will consult with other
           registry services to find the matching service
        """
        from Acquire.ObjectStore import ObjectStore as _ObjectStore
        from Acquire.Service import Service as _Service
        from Acquire.ObjectStore import string_to_encoded \
            as _string_to_encoded
        from Acquire.Service import get_this_service as _get_this_service

        this_service = _get_this_service(need_private_access=False)

        if service_url is not None:
            from Acquire.Service import Service as _Service
            service_url = _Service.get_canonical_url(service_url)

        if this_service.uid() == service_uid:
            return this_service
        elif this_service.canonical_url() == service_url:
            return this_service

        bucket = self.get_bucket()

        service_key = self.get_service_key(service_uid=service_uid,
                                           service_url=service_url)

        service = None

        if service_key is not None:
            try:
                data = _ObjectStore.get_object_from_json(bucket=bucket,
                                                         key=service_key)
                service = _Service.from_data(data)
            except:
                pass

        if service is not None:
            must_write = False

            if service.uid() == "STAGE1":
                # we need to directly ask the service for its info
                service = self.challenge_service(service)

                if service.uid() == "STAGE1":
                    from Acquire.Service import MissingServiceError
                    raise MissingServiceError(
                        "Service %s|%s not available as it is still under "
                        "construction!" % (service_uid, service))

                # we can now move this service from pending to active
                uidkey = self._get_key_for_uid(service.uid())
                domain = self._get_domain(service.service_url())
                domainroot = self._get_root_key_for_domain(domain=domain)

                pending_key = "%s/pending/%s" % (domainroot, service.uid())
                active_key = "%s/active/%s" % (domainroot, service.uid())

                try:
                    _ObjectStore.delete_object(bucket=bucket,
                                               key=pending_key)
                except:
                    pass

                try:
                    _ObjectStore.set_string_object(bucket=bucket,
                                                   key=active_key,
                                                   string_data=uidkey)
                except:
                    pass

                must_write = True
            elif service.should_refresh_keys():
                service.refresh_keys()
                must_write = True

            if must_write:
                data = service.to_data()
                _ObjectStore.set_object_from_json(bucket=bucket,
                                                  key=service_key,
                                                  data=data)
            return service

        # we only get here if we can't find the service on this registry.
        # In the future, we will use the initial part of the UID of
        # the service to ask its registering registry for its data.
        # For now, we just raise an error
        from Acquire.Service import MissingServiceError
        raise MissingServiceError(
            "No service available: service_url=%s  service_uid=%s" %
                                  (service_url, service_uid))
def register_service(service, registry_uid):
    """Call this function to register the passed new service with
       the specified registry_uid. This function will complete
       registration and construction of the service
    """
    from Acquire.Service import Service as _Service
    if not isinstance(service, _Service):
        raise TypeError("You can only register Service objects")

    if not service.uid().startswith("STAGE1"):
        raise PermissionError(
            "You can only register services that are at STAGE1 of "
            "construction")

    if service.service_type() == "registry":
        from Acquire.Registry import get_registry_details \
            as _get_registry_details

        details = _get_registry_details(registry_uid=registry_uid)

        from Acquire.Service import Service as _Service
        canonical_url = _Service.get_canonical_url(details["canonical_url"])

        # make sure that everything matches what was specified
        if canonical_url != service.canonical_url():
            raise PermissionError(
                "Cannot change the canonical URL. I expect %s, but "
                "you are trying to set to %s" %
                (service.canonical_url(), details["canonical_url"]))

        from Acquire.Registry import update_registry_keys_and_certs \
            as _update_registry_keys_and_certs

        _update_registry_keys_and_certs(
            registry_uid=registry_uid,
            public_key=service.public_key(),
            public_certificate=service.public_certificate())

        service.create_stage2(service_uid=registry_uid, response=service._uid)
        return service

    # get the trusted registry
    from Acquire.Registry import get_trusted_registry_service \
        as _get_trusted_registry_service
    registry_service = _get_trusted_registry_service(service_uid=registry_uid)

    if not registry_service.is_registry_service():
        raise PermissionError(
            "You can only register new services on an existing and valid "
            "registry service. Not %s" % registry_service)

    from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
    pubkey = registry_service.public_key()
    challenge = pubkey.encrypt(service.uid())

    args = {
        "service": service.to_data(),
        "challenge": _bytes_to_string(challenge),
        "fingerprint": pubkey.fingerprint()
    }

    result = registry_service.call_function(function="register_service",
                                            args=args)

    service_uid = result["service_uid"]
    response = result["response"]

    service.create_stage2(service_uid=service_uid, response=response)

    return service
示例#4
0
def setup_this_service(service_type, canonical_url, registry_uid, username,
                       password):
    """Call this function to setup a new
       service that will serve at 'canonical_url', will be of
       the specified service_type. This will be registered at the
       registry at UID registry_uid

        (1) Delete the object store value "_service" if you want to reset
            the actual Service. This will assign a new UID for the service
            which would reset the certificates and keys. This new service
            will need to be re-introduced to other services that need
            to trust it
    """
    assert_running_service()

    from Acquire.Service import get_service_account_bucket as \
        _get_service_account_bucket

    from Acquire.ObjectStore import Mutex as _Mutex
    from Acquire.ObjectStore import ObjectStore as _ObjectStore
    from Acquire.Service import Service as _Service

    bucket = _get_service_account_bucket()

    # ensure that this is the only time the service is set up
    mutex = _Mutex(key=_service_key, bucket=bucket, lease_time=120)

    try:
        service_info = _ObjectStore.get_object_from_json(bucket, _service_key)
    except:
        service_info = None

    service = None
    service_password = _get_service_password()

    user_uid = None
    otp = None

    if service_info:
        try:
            service = _Service.from_data(service_info, service_password)
        except Exception as e:
            from Acquire.Service import ServiceAccountError
            raise ServiceAccountError(
                "Something went wrong reading the Service data. You should "
                "either debug the error or delete the data at key '%s' "
                "to allow the service to be reset and constructed again. "
                "The error was %s" % (_service_key, str(e)))

        if service.uid().startswith("STAGE1"):
            from Acquire.Service import ServiceAccountError
            raise ServiceAccountError(
                "The service is currently under construction. Please "
                "try again later...")

    if service is None:
        # we need to create the new service
        if (service_type is None) or (canonical_url is None):
            from Acquire.Service import ServiceAccountError
            raise ServiceAccountError(
                "You need to supply both the service_type and canonical_url "
                "in order to initialise a new Service")

        # we need to build the service account - first stage 1
        service = _Service.create(service_url=canonical_url,
                                  service_type=service_type)

        # write the stage1 service data, encrypted using the service password.
        # This will be needed to answer the challenge from the registry
        service_data = service.to_data(service_password)
        _ObjectStore.set_object_from_json(bucket, _service_key, service_data)

        # now we can register the service with a registry - this
        # will return the stage2-constructed service
        from Acquire.Registry import register_service as _register_service
        service = _register_service(service=service, registry_uid=registry_uid)

    canonical_url = _Service.get_canonical_url(canonical_url)

    if service.service_type() != service_type or \
            service.canonical_url() != canonical_url:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "The existing service has a different type or URL to that "
            "requested at setup. The request type and URL are %s and %s, "
            "while the actual service type and URL are %s and %s." %
            (service_type, canonical_url, service.service_type(),
             service.canonical_url()))

    # we can add the first admin user
    service_uid = service.uid()
    skelkey = service.skeleton_key().public_key()

    # now register the new admin user account - remembering to
    # encode the password
    from Acquire.Client import Credentials as _Credentials
    password = _Credentials.encode_password(password=password,
                                            identity_uid=service_uid)

    from Acquire.Identity import UserAccount as _UserAccount
    (user_uid, otp) = _UserAccount.create(username=username,
                                          password=password,
                                          _service_uid=service_uid,
                                          _service_public_key=skelkey)

    add_admin_user(service, user_uid)

    # write the service data, encrypted using the service password
    service_data = service.to_data(service_password)
    # reload the data to check it is ok, and also to set the right class
    service = _Service.from_data(service_data, service_password)
    # now it is ok, save this data to the object store
    _ObjectStore.set_object_from_json(bucket, _service_key, service_data)

    mutex.unlock()

    from Acquire.Service import clear_service_cache as _clear_service_cache
    _clear_service_cache()

    return (service, user_uid, otp)