Exemplo n.º 1
0
    def to_data(self):
        """Return this object serialised to a json-encoded dictionary"""
        data = {}

        if self.is_null():
            return data

        from Acquire.ObjectStore import datetime_to_string \
            as _datetime_to_string
        from Acquire.ObjectStore import bytes_to_string \
            as _bytes_to_string

        data["user_uid"] = str(self._user_uid)
        data["session_uid"] = str(self._session_uid)
        data["identity_url"] = str(self._identity_url)
        data["identity_uid"] = str(self._identity_uid)
        data["uid"] = self._uid
        data["signature"] = _bytes_to_string(self._signature)
        data["siguid"] = _bytes_to_string(self._siguid)

        try:
            data["is_testing"] = self._is_testing
        except:
            pass

        return data
Exemplo n.º 2
0
    def to_data(self, pubkey=None):
        """Return a json-serialisable dictionary of the object. If
           'pubkey' is supplied, then sensitive data used by the
           uploader is encrypted
        """
        if self.is_null():
            return {}

        data = {}

        data["drive_uid"] = self._drive_uid
        data["file_uid"] = self._file_uid
        data["secret"] = self._secret
        data["uid"] = self._uid

        if pubkey is not None:
            from Acquire.Crypto import PublicKey as _PublicKey
            from Acquire.ObjectStore import bytes_to_string \
                as _bytes_to_string
            import json as _json

            if not isinstance(pubkey, _PublicKey):
                raise TypeError("pubkey must be type PublicKey")

            d = _bytes_to_string(pubkey.encrypt(_json.dumps(data)))

            data = {}
            data["is_encrypted"] = True
            data["data"] = d

        return data
Exemplo n.º 3
0
    def logout(self):
        """Log out from the current session"""
        if self.is_logged_in() or self.is_logging_in():
            service = self.identity_service()

            args = {"session_uid": self._session_uid}

            if self.is_logged_in():
                from Acquire.Client import Authorisation as _Authorisation
                authorisation = _Authorisation(
                                    resource="logout %s" % self._session_uid,
                                    user=self)
                args["authorisation"] = authorisation.to_data()
            else:
                # we are not fully logged in so cannot generate an
                # authorisation for the logout
                from Acquire.ObjectStore import bytes_to_string \
                    as _bytes_to_string
                resource = "logout %s" % self._session_uid
                signature = self.signing_key().sign(resource)
                args["signature"] = _bytes_to_string(signature)

            result = service.call_function(function="logout", args=args)

            self._status = _LoginStatus.LOGGED_OUT

            return result
Exemplo n.º 4
0
    def validate_password(self, password, otpcode, remember_device=False,
                          device_secret=None):
        """Validate that the passed password and one-time-code are valid.
           If they are, then do nothing. Otherwise raise an exception.
           If 'remember_device' is true, then this returns the provisioning
           uri needed to initialise the OTP code for this account
        """
        if not self.is_active():
            raise UserValidationError(
                "Cannot validate against an inactive account")

        # see if we can decrypt the private key using the password
        privkey = _PrivateKey.read_bytes(self._privkey, password)

        if device_secret:
            # decrypt the passed device secret and check the supplied
            # otpcode for that...
            otp = _OTP.decrypt(_string_to_bytes(device_secret), privkey)
            otp.verify(otpcode)
        else:
            # now decrypt the secret otp and validate the supplied otpcode
            otp = _OTP.decrypt(self._otp_secret, privkey)
            otp.verify(otpcode)

        if remember_device:
            # create a new OTP that is unique for this device and return
            # this together with the provisioning code
            otp = _OTP()
            otpsecret = _bytes_to_string(otp.encrypt(privkey.public_key()))
            return (otpsecret, otp.provisioning_uri(self.username()))
Exemplo n.º 5
0
    def to_data(self):
        """Return a json-serialisable dictionary for this object. Note
           that this does not contain any information about the local
           file itself - just the name it should be called on the
           object store and the size, checksum and acl. If the file
           (or compressed file) is sufficiently small then this
           will also contain the packed version of that file data

           Returns:
                dict: JSON serialisable dictionary of object
        """
        data = {}

        if not self.is_null():
            from Acquire.ObjectStore import datetime_to_string \
                as _datetime_to_string
            data["filename"] = self.filename()
            data["filesize"] = self.filesize()
            data["checksum"] = self.checksum()

            if self._aclrules is not None:
                data["aclrules"] = self._aclrules.to_data()

            data["drive_uid"] = self.drive_uid()

            if self._local_filedata is not None:
                from Acquire.ObjectStore import bytes_to_string \
                    as _bytes_to_string
                data["filedata"] = _bytes_to_string(self._local_filedata)

            if self._compression is not None:
                data["compression"] = self._compression

        return data
Exemplo n.º 6
0
    def logout(self):
        """Log out from the current session"""
        if self.is_logged_in() or self.is_logging_in():
            identity_url = self.identity_service_url()

            if identity_url is None:
                return

            # create a permission message that can be signed
            # and then validated by the user
            permission = "Log out request for %s" % self._session_uid
            signature = self.signing_key().sign(permission)

            print("Logging out %s from session %s" %
                  (self._username, self._session_uid))

            result = _call_function(
                identity_url,
                "logout",
                args_key=self.identity_service().public_key(),
                username=self._username,
                session_uid=self._session_uid,
                permission=permission,
                signature=_bytes_to_string(signature))
            print(result)

            self._status = _LoginStatus.LOGGED_OUT

            return result
Exemplo n.º 7
0
def pack_return_value(result, key=None, response_key=None, public_cert=None):
    """Pack the passed result into a json string, optionally
       encrypting the result with the passed key, and optionally
       supplying a public response key, with which the function
       being called should encrypt the response. If public_cert is
       provided then we will ask the service to sign their response.
       Note that you can only ask the service to sign their response
       if you provide a 'reponse_key' for them to encrypt it with too
    """

    try:
        sign_result = key["sign_with_service_key"]
    except:
        sign_result = False

    key = _get_key(key)
    response_key = _get_key(response_key)

    if response_key:
        result["encryption_public_key"] = _bytes_to_string(
            response_key.bytes())

        if public_cert:
            result["sign_with_service_key"] = True

    elif public_cert:
        raise PackingError(
            "You cannot ask the service to sign the response "
            "without also providing a key to encrypt it with too")

    result = _json.dumps(result).encode("utf-8")

    if key:
        response = {}

        result_data = key.encrypt(result)

        if sign_result:
            # sign using the signing certificate for this service
            signature = _get_signing_certificate().sign(result_data)
            response["signature"] = _bytes_to_string(signature)

        response["data"] = _bytes_to_string(result_data)
        response["encrypted"] = True
        result = _json.dumps(response).encode("utf-8")

    return result
Exemplo n.º 8
0
 def end_profile(pr, results):
     pr.disable()
     t = _tempfile.mktemp()
     pr.dump_stats(t)
     with open(t, "rb") as FILE:
         data = FILE.read()
     _os.unlink(t)
     results["profile_data"] = _bytes_to_string(data)
Exemplo n.º 9
0
    def to_data(self):
        """Return a data representation of this object (dictionary)"""
        if self._username is None:
            return None

        data = {}
        data["username"] = self._username
        data["status"] = self._status
        data["uuid"] = self._uuid

        # the keys and secret are arbitrary binary data.
        # These need to be base64 encoded and then turned into strings
        data["private_key"] = _bytes_to_string(self._privkey)
        data["public_key"] = _bytes_to_string(self._pubkey)
        data["otp_secret"] = _bytes_to_string(self._otp_secret)

        return data
Exemplo n.º 10
0
 def end_profile(pr, results):
     pr.disable()
     import tempfile as _tempfile
     from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
     t = _tempfile.mktemp()
     pr.dump_stats(t)
     with open(t, "rb") as FILE:
         data = FILE.read()
     _os.unlink(t)
     results["profile_data"] = _bytes_to_string(data)
Exemplo n.º 11
0
    def to_data(self, password=None):
        """Serialise this key to a dictionary, using the supplied
           password to encrypt the private key and certificate"""

        data = {}

        data["uuid"] = self._uuid
        data["service_type"] = self._service_type
        data["service_url"] = self._service_url

        # keys are binary and need to be encoded
        data["public_certificate"] = self._pubcert.to_data()
        data["public_key"] = self._pubkey.to_data()

        if password:
            # only serialise private data if a password was provided
            data["private_certificate"] = self._privcert.to_data(password)
            data["private_key"] = self._privkey.to_data(password)
            data["otpsecret"] = _bytes_to_string(self._otpsecret)
            data["admin_password"] = _bytes_to_string(self._admin_password)

        return data
Exemplo n.º 12
0
    def create(user_uid, password, primary_password,
               device_uid=None):
        """Create the credentials for the user with specified
           user_uid, optionally logging in via the specified
           device_uid, using the specified password, to protect
           the passed "primary_password"

           This returns the OTP that has been created to be
           associated with these credentials
        """
        from Acquire.Crypto import PrivateKey as _PrivateKey
        from Acquire.Crypto import OTP as _OTP
        from Acquire.ObjectStore import ObjectStore as _ObjectStore
        from Acquire.Service import get_service_account_bucket \
            as _get_service_account_bucket
        from Acquire.ObjectStore import bytes_to_string as _bytes_to_string

        if device_uid is None:
            device_uid = user_uid

        privkey = _PrivateKey(name="user_creds_key %s" % user_uid)
        otp = _OTP()
        otpsecret = otp.encrypt(privkey.public_key())
        primary_password = privkey.encrypt(primary_password)

        data = {"primary_password": _bytes_to_string(primary_password),
                "private_key": privkey.to_data(passphrase=password),
                "otpsecret": _bytes_to_string(otpsecret)
                }

        key = "%s/credentials/%s/%s" % (_user_root, user_uid, device_uid)

        bucket = _get_service_account_bucket()
        _ObjectStore.set_object_from_json(bucket=bucket,
                                          key=key,
                                          data=data)

        return otp
Exemplo n.º 13
0
    def _set_userinfo(self, userinfo, user_uid, service_uid):
        """Save the userfile for the passed user_uid logging into the
           passed identity service with service_uid
        """
        from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
        import json as _json
        filename = self._get_userinfo_filename(user_uid=user_uid,
                                               service_uid=service_uid)
        key = self._get_wallet_key().public_key()
        data = _bytes_to_string(key.encrypt(_json.dumps(userinfo)))

        userinfo = {"username": userinfo["username"],
                    "user_uid": user_uid,
                    "data": data}

        _write_json(data=userinfo, filename=filename)
Exemplo n.º 14
0
    def to_data(self, passphrase=None):
        """Return a json-serialisable dictionary that contains all data
           for this object

           Args:
                passphrase (str, default=None): Passphrase to use to
                encrypt OSPar
           Returns:
                dict: JSON serialisable dictionary
        """
        data = {}

        if self._url is None:
            return data

        from Acquire.ObjectStore import datetime_to_string \
            as _datetime_to_string
        from Acquire.ObjectStore import bytes_to_string \
            as _bytes_to_string

        data["url"] = _bytes_to_string(self._url)
        data["uid"] = self._uid
        data["key"] = self._key
        data["expires_datetime"] = _datetime_to_string(self._expires_datetime)
        data["is_readable"] = self._is_readable
        data["is_writeable"] = self._is_writeable

        try:
            if self._service_url is not None:
                data["service_url"] = self._service_url
        except:
            pass

        try:
            privkey = self._privkey
        except:
            privkey = None

        if privkey is not None:
            if passphrase is not None:
                data["privkey"] = privkey.to_data(passphrase)

        # note that we don't save the driver details as these
        # are stored separately on the service

        return data
Exemplo n.º 15
0
    def encrypt_data(self, data):
        """Encrypt the passed data so that only the daemon running on
           the cluster can decrypt it. This will be encrypted as;

           data = {"cluster_uid" : "CLUSTER_UID",
                   "fingerprint" : "KEY_FINGERPRINT",
                   "encrypted_data" : "ENCRYPTED_DATA"}
        """
        if self.is_null():
            raise PermissionError("You cannot encrypt using a null cluster!")

        from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
        import json as _json
        return {"cluster_uid": str(self.uid()),
                "fingerprint": str(self.public_key().fingerprint()),
                "encrypted_data": _bytes_to_string(
                                 self.public_key().encrypt(_json.dumps(data)))
                }
Exemplo n.º 16
0
    def to_data(self):
        """Return this object serialised to a json-encoded dictionary"""
        data = {}

        if self.is_null():
            return data

        data["user_uid"] = str(self._user_uid)
        data["session_uid"] = str(self._session_uid)
        data["identity_url"] = str(self._identity_url)
        data["auth_timestamp"] = self._auth_timestamp
        data["signature"] = _bytes_to_string(self._signature)

        try:
            data["is_testing"] = self._is_testing
        except:
            pass

        return data
Exemplo n.º 17
0
    def upload(self, chunk):
        """Upload the next chunk of the file"""
        if self.is_null():
            raise PermissionError("Cannot upload a chunk to a null uploader!")

        service = self.service()

        if service is None:
            raise PermissionError("Cannot upload a chunk to a null service!")

        # first, compress the chunk
        from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
        from Acquire.Crypto import Hash as _Hash
        import bz2 as _bz2

        if isinstance(chunk, str):
            chunk = chunk.encode("utf-8")

        chunk = _bz2.compress(chunk)
        md5 = _Hash.md5(chunk)
        chunk = _bytes_to_string(chunk)

        if self._chunk_idx is None:
            self._chunk_idx = 0
        else:
            self._chunk_idx = self._chunk_idx + 1

        secret = _Hash.multi_md5(
            self._secret,
            "%s%s%d" % (self._drive_uid, self._file_uid, self._chunk_idx))

        args = {}
        args["drive_uid"] = self._drive_uid
        args["file_uid"] = self._file_uid
        args["chunk_index"] = self._chunk_idx
        args["secret"] = secret
        args["data"] = chunk
        args["checksum"] = md5

        service.call_function(function="upload_chunk", args=args)
Exemplo n.º 18
0
    def challenge_service(self, service):
        """Send a challenge to the passed service, returning the actual
           service returned. This will only pass if our copy of the
           service matches us with the copy returned from the actual
           service. This verifies that there is a real service sitting
           at that URL, and that we have the right keys and certs
        """
        from Acquire.Crypto import PrivateKey as _PrivateKey
        from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
        from Acquire.Service import Service as _Service

        challenge = _PrivateKey.random_passphrase()
        pubkey = service.public_key()
        encrypted_challenge = pubkey.encrypt(challenge)

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

        if service.uid().startswith("STAGE"):
            # we cannot call using the service directly, as it is
            # not yet fully constructed
            from Acquire.Service import get_this_service as _get_this_service
            from Acquire.Service import call_function as _call_function
            this_service = _get_this_service(need_private_access=True)
            result = _call_function(service_url=service.service_url(),
                                    function=None,
                                    args=args,
                                    args_key=service.public_key(),
                                    response_key=this_service.private_key(),
                                    public_cert=service.public_certificate())
        else:
            result = service.call_function(function=None, args=args)

        if result["response"] != challenge:
            raise PermissionError(
                "Failure of the service %s to correctly respond "
                "to the challenge!" % service)

        return _Service.from_data(result["service_info"])
Exemplo n.º 19
0
    def create(username,
               password,
               _service_uid=None,
               _service_public_key=None):
        """Create a new account with username 'username', which will
           be secured using the passed password.

           Note that this will create an account with a specified
           user UID, meaning that different users can have the same
           username. We identify the right user via the combination
           of username, password and OTP code.

           Normally the UID of the service, and the skeleton key
           used to encrypt the backup password are obtained
           directly from the service. However, when initialising
           a new service we must pass these directly. In those
           cases, pass the object using _service_uid and
           _service_public_key

           This returns a tuple of the user_uid and OTP for the
           newly-created account
        """
        from Acquire.ObjectStore import create_uuid as _create_uuid
        from Acquire.Crypto import PrivateKey as _PrivateKey
        from Acquire.Crypto import PublicKey as _PublicKey
        from Acquire.ObjectStore import ObjectStore as _ObjectStore
        from Acquire.Service import get_service_account_bucket \
            as _get_service_account_bucket
        from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
        from Acquire.Identity import UserCredentials as _UserCredentials
        from Acquire.ObjectStore import get_datetime_now_to_string \
            as _get_datetime_now_to_string

        if _service_public_key is None:
            from Acquire.Service import get_this_service as _get_this_service
            service_pubkey = _get_this_service().public_skeleton_key()
            assert (service_pubkey is not None)
        else:
            service_pubkey = _service_public_key

        if not isinstance(service_pubkey, _PublicKey):
            raise TypeError("The service public key must be type PublicKey")

        if _service_uid is None:
            from Acquire.Service import get_this_service \
                as _get_this_service
            service_uid = _get_this_service(need_private_access=False).uid()
        else:
            service_uid = _service_uid

        # create a UID for this new user
        user_uid = _create_uuid()

        # now create the primary password for this user and use
        # this to encrypt the special keys for this user
        privkey = _PrivateKey(name="user_secret_key %s %s" %
                              (username, user_uid))
        primary_password = _PrivateKey.random_passphrase()

        bucket = _get_service_account_bucket()

        # now create the credentials used to validate a login
        otp = _UserCredentials.create(user_uid=user_uid,
                                      password=password,
                                      primary_password=primary_password)

        # create the user account
        user = UserAccount(username=username,
                           user_uid=user_uid,
                           private_key=privkey,
                           status="active")

        # now save a lookup from the username to this user_uid
        # (many users can have the same username). Use this lookup
        # to hold a recovery password for this account
        recovery_password = _bytes_to_string(
            service_pubkey.encrypt(primary_password))

        key = "%s/names/%s/%s" % (_user_root, user.encoded_name(), user_uid)
        _ObjectStore.set_string_object(bucket=bucket,
                                       key=key,
                                       string_data=recovery_password)

        # now save a lookup from the hashed username+password
        # to the user_uid, so that we can
        # quickly find matching user_uids (expect few people will have
        # exactly the same username and password). This will
        # save the exact time this username-password combination
        # was set
        encoded_password = _UserCredentials.hash(username=username,
                                                 password=password,
                                                 service_uid=service_uid)

        key = "%s/passwords/%s/%s" % (_user_root, encoded_password, user_uid)
        _ObjectStore.set_string_object(
            bucket=bucket, key=key, string_data=_get_datetime_now_to_string())

        # finally(!) save the account itself to the object store
        key = "%s/uids/%s" % (_user_root, user_uid)
        data = user.to_data(passphrase=primary_password)
        _ObjectStore.set_object_from_json(bucket=bucket, key=key, data=data)

        # return the OTP and user_uid
        return (user_uid, otp)
Exemplo n.º 20
0
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
Exemplo n.º 21
0
    def send_password(self,
                      url,
                      username=None,
                      remember_password=True,
                      remember_device=None,
                      dryrun=None):
        """Send a password and one-time code to the supplied login url"""

        self._manual_password = False
        self._manual_otpcode = False

        if not remember_password:
            remember_device = False

        # the login URL is of the form "server/code"
        words = url.split("/")
        identity_service = "/".join(words[0:-1])
        short_uid = words[-1]

        # get the public key of this identity service
        service_key = self._get_service_key(identity_service)
        service_cert = self._get_service_cert(identity_service)

        if not username:
            # choose a username from any existing files...
            username = self._get_username()

        print("Logging in using username '%s'" % username)
        password = self._get_user_password(username)
        otpcode = self._get_otpcode(username)

        print("\nLogging in to '%s', session '%s'..." %
              (identity_service, short_uid),
              end="")
        _sys.stdout.flush()

        if dryrun:
            print("Calling %s with username=%s, password=%s, otpcode=%s, "
                  "remember_device=%s, device_uid=%s, short_uid=%s" %
                  (identity_service, username, password, otpcode,
                   remember_device, self._device_uid, short_uid))
            return

        try:
            key = _PrivateKey()
            response = _call_function(identity_service,
                                      "login",
                                      args_key=service_key,
                                      response_key=key,
                                      public_cert=service_cert,
                                      username=username,
                                      password=password,
                                      otpcode=otpcode,
                                      remember_device=remember_device,
                                      device_uid=self._device_uid,
                                      short_uid=short_uid)
            print("SUCCEEDED!")
            _sys.stdout.flush()
        except Exception as e:
            print("FAILED!")
            _sys.stdout.flush()
            raise LoginError("Failed to log in: %s" % str(e))

        if remember_password:
            try:
                provisioning_uri = response["provisioning_uri"]
            except:
                provisioning_uri = None

            try:
                device_uid = response["device_uid"]
            except:
                device_uid = None

            otpsecret = None

            if provisioning_uri:
                try:
                    otpsecret = _re.search(r"secret=([\w\d+]+)&issuer",
                                           provisioning_uri).groups()[0]
                except:
                    pass

            try:
                user_info = self._read_userinfo(username)
            except:
                user_info = {}

            if user_info is None:
                user_info = {}

            pubkey = self._wallet_key.public_key()

            must_write = self._manual_password

            if otpsecret:
                if self._manual_otpcode:
                    must_write = True

            if must_write:
                user_info["username"] = username.encode("utf-8").decode(
                    "utf-8")
                user_info["password"] = _bytes_to_string(
                    pubkey.encrypt(password.encode("utf-8")))

                if otpsecret:
                    user_info["otpsecret"] = _bytes_to_string(
                        pubkey.encrypt(otpsecret.encode("utf-8")))
                    user_info["device_uid"] = device_uid

                packed_data = _pack_arguments(user_info)

                with open(Wallet._get_userfile(username), "wb") as FILE:
                    FILE.write(packed_data)

        self._manual_password = False
        self._manual_otpcode = False

        return response
Exemplo n.º 22
0
    def call_admin_function(self,
                            function,
                            args={},
                            service_url=None,
                            remember_password=True,
                            remember_device=None):
        """Call the admin function 'function' using supplied arguments 'args',
           on the service at 'service_url'
        """

        self._manual_password = False
        self._manual_otpcode = False

        if not remember_password:
            remember_device = False

        if not service_url:
            # choose a service_url from any existing files...
            service_url = self._get_service_url()

        # get the public key of this identity service
        service_key = self._get_service_key(service_url)
        service_cert = self._get_service_cert(service_url)

        password = self._get_admin_password(service_url)
        otpcode = self._get_otpcode(service_url)

        strargs = str(args)

        args["password"] = password
        args["otpcode"] = otpcode
        args["remember_device"] = remember_device

        print("\nCalling '%s' with %s... " % (function, strargs), end="")
        _sys.stdout.flush()

        try:
            key = _PrivateKey()
            response = _call_function(service_url,
                                      function,
                                      args_key=service_key,
                                      response_key=key,
                                      public_cert=service_cert,
                                      args=args)
            print("SUCCEEDED!")
            _sys.stdout.flush()
        except Exception as e:
            print("FAILED!")
            _sys.stdout.flush()
            raise LoginError("Failed to log in: %s" % str(e))

        if remember_password:
            try:
                provisioning_uri = response["provisioning_uri"]
            except:
                provisioning_uri = None

            otpsecret = None

            if provisioning_uri:
                try:
                    otpsecret = _re.search(r"secret=([\w\d+]+)&issuer",
                                           provisioning_uri).groups()[0]
                except:
                    pass

            try:
                service_info = self._read_service_info(service_url)
            except:
                service_info = {}

            if service_info is None:
                service_info = {}

            pubkey = self._wallet_key.public_key()

            must_write = self._manual_password

            if otpsecret:
                if self._manual_otpcode:
                    must_write = True

            if must_write:
                service_info["service_url"] = service_url.encode(
                    "utf-8").decode("utf-8")
                service_info["password"] = _bytes_to_string(
                    pubkey.encrypt(password.encode("utf-8")))

                if otpsecret:
                    service_info["otpsecret"] = _bytes_to_string(
                        pubkey.encrypt(otpsecret.encode("utf-8")))

                packed_data = _pack_arguments(service_info)

                with open(ServiceWallet._get_service_file(service_url),
                          "wb") as FILE:
                    FILE.write(packed_data)

        self._manual_password = False
        self._manual_otpcode = False

        return response
Exemplo n.º 23
0
def run(args):
    """Call this function to initiate the two-step file-download process.

       Step 1: download - tells the service to download the file. If the
               file is small then the file will be in the response.
               Otherwise a OSPar will be returned that will let you
               download the file. If this is the case, then you must
               call step 2...

       Step 2: downloaded - after you have downloaded the file from the OSPar
               call OSPar.close() so that the service knows that the OSPar
               is no longer needed and can be deleted
    """

    drive_uid = args["drive_uid"]
    filename = args["filename"]

    try:
        authorisation = Authorisation.from_data(args["authorisation"])
    except:
        authorisation = None

    try:
        par_uid = args["par_uid"]
    except:
        par_uid = None

    try:
        secret = args["secret"]
    except:
        secret = None

    public_key = PublicKey.from_data(args["encryption_key"])

    if "version" in args:
        version = str(args["version"])
    else:
        version = None

    if "force_par" in args:
        force_par = args["force_par"]
    else:
        force_par = None

    if "must_chunk" in args:
        must_chunk = args["must_chunk"]
    else:
        must_chunk = False

    if must_chunk:
        must_chunk = True

    if force_par:
        force_par = True

    if par_uid is not None:
        registry = PARRegistry()
        (par, identifiers) = registry.load(par_uid=par_uid, secret=secret)
    else:
        par = None
        identifiers = None

    drive = DriveInfo(drive_uid=drive_uid)

    return_value = {}

    (filemeta, filedata, par,
     downloader) = drive.download(filename=filename,
                                  version=version,
                                  authorisation=authorisation,
                                  encrypt_key=public_key,
                                  force_par=force_par,
                                  must_chunk=must_chunk,
                                  par=par,
                                  identifiers=identifiers)

    if filemeta is not None:
        return_value["filemeta"] = filemeta.to_data()

    if filedata is not None:
        from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
        return_value["filedata"] = _bytes_to_string(filedata)

    if par is not None:
        return_value["download_par"] = par.to_data()

    if downloader is not None:
        return_value["downloader"] = downloader.to_data(pubkey=public_key)

    return return_value
def get_trusted_registry_service(registry_uid=None,
                                 service_uid=None,
                                 service_url=None):
    """Return the trusted service info for the registry with specified
       registry_uid, or get any trusted registry service using either
       'service_uid' or 'service_url' as a starting hint to
       locate a suitable registry
    """
    if service_uid is not None:
        # for the moment, just try to get one registry. Eventually we should
        # try to get several in case this one is down
        registry_uid = get_primary_registry_uid(service_uid)
        return get_trusted_registry_service(registry_uid=registry_uid)

    if service_url is not None:
        if service_url.find(".") != -1:
            # try the main acquire registry first
            return get_trusted_registry_service(registry_uid="a0-a0")
        else:
            # this must be testing...
            return get_trusted_registry_service(registry_uid="Z9-Z9")

    if registry_uid is None:
        raise PermissionError(
            "You must specify one of registry_uid, service_uid "
            "or service_url")

    from Acquire.Service import get_trusted_service as _get_trusted_service

    try:
        registry_service = _get_trusted_service(service_uid=registry_uid,
                                                autofetch=False)
    except:
        registry_service = None

    if registry_service is not None:
        if not registry_service.is_registry_service():
            from Acquire.Service import ServiceError
            raise ServiceError("The requested service (%s) for %s is NOT a "
                               "registry service!" %
                               (registry_service, registry_uid))

        if registry_service.uid() != registry_uid:
            from Acquire.Service import ServiceError
            raise ServiceError(
                "Disagreement of UID (%s) is NOT the right registry service!" %
                registry_service)

        # everything is ok - we have seen this registry before
        return registry_service

    # boostrapping
    from Acquire.Registry import get_registry_details \
        as _get_registry_details

    details = _get_registry_details(registry_uid)

    from Acquire.Service import call_function as _call_function
    from Acquire.Service import Service as _Service
    from Acquire.Crypto import get_private_key as _get_private_key
    from Acquire.Crypto import PrivateKey as _PrivateKey
    from Acquire.Crypto import PublicKey as _PublicKey
    from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
    from Acquire.ObjectStore import string_to_bytes as _string_to_bytes

    privkey = _get_private_key(key="registry")

    pubkey = _PublicKey.from_data(details["public_key"])
    pubcert = _PublicKey.from_data(details["public_certificate"])

    # ask the registry to return to us their latest details - use
    # a challenge-response to make sure that the response is
    # properly returned
    challenge = _PrivateKey.random_passphrase()
    encrypted_challenge = _bytes_to_string(pubkey.encrypt(challenge))
    args = {
        "challenge": encrypted_challenge,
        "fingerprint": pubkey.fingerprint()
    }

    result = _call_function(service_url=details["canonical_url"],
                            function=None,
                            args=args,
                            args_key=pubkey,
                            response_key=privkey,
                            public_cert=pubcert)

    if result["response"] != challenge:
        from Acquire.Service import ServiceError
        raise ServiceError(
            "The requested service (%s) failed to respond to the challenge!" %
            registry_service)

    registry_service = _Service.from_data(result["service_info"])

    if not registry_service.is_registry_service():
        from Acquire.Service import ServiceError
        raise ServiceError(
            "The requested service (%s) is NOT a registry service!" %
            registry_service)

    if registry_service.uid() != details["uid"]:
        from Acquire.Service import ServiceError
        raise ServiceError(
            "Disagreement of UID (%s) is NOT the right registry service!" %
            registry_service)

    # ok - we've got the registry - add this to the set of
    # trusted services so that we don't need to bootstrap from
    # the registry details again
    from Acquire.Service import trust_service as _trust_service
    _trust_service(registry_service)

    return registry_service
Exemplo n.º 25
0
def pack_return_value(function=None,
                      payload=None,
                      key=None,
                      response_key=None,
                      public_cert=None,
                      private_cert=None):
    """Pack the passed result into a json string, optionally
       encrypting the result with the passed key, and optionally
       supplying a public response key, with which the function
       being called should encrypt the response. If public_cert is
       provided then we will ask the service to sign their response.
       Note that you can only ask the service to sign their response
       if you provide a 'reponse_key' for them to encrypt it with too
    """
    try:
        sign_result = key["sign_with_service_key"]
    except:
        sign_result = False

    key = _get_key(key)
    response_key = _get_key(response_key)

    from Acquire.ObjectStore import bytes_to_string as _bytes_to_string
    from Acquire.ObjectStore import get_datetime_now_to_string \
        as _get_datetime_now_to_string

    result = {}

    if function is None and "function" in payload:
        function = payload["function"]

    if response_key:
        result["encryption_public_key"] = _bytes_to_string(
            response_key.bytes())

        if public_cert:
            result["sign_with_service_key"] = public_cert.fingerprint()

    elif sign_result and (key is None):
        from Acquire.Service import PackingError
        raise PackingError(
            "You cannot ask the service to sign the response "
            "without also providing a key to encrypt it with too")

    result["payload"] = payload
    now = _get_datetime_now_to_string()
    result["synctime"] = now
    result["function"] = function

    if key is None:
        if sign_result:
            from Acquire.Service import PackingError
            raise PackingError(
                "The service must encrypt the response before it "
                "can be signed.")
    else:
        response = {}

        result_data = key.encrypt(_json.dumps(result).encode("utf-8"))

        if sign_result:
            # sign using the signing certificate for this service
            signature = _get_signing_certificate(
                fingerprint=sign_result,
                private_cert=private_cert).sign(result_data)
            response["signature"] = _bytes_to_string(signature)

        response["data"] = _bytes_to_string(result_data)
        response["encrypted"] = True
        response["fingerprint"] = key.fingerprint()
        response["synctime"] = now
        result = response

    result = _json.dumps(result).encode("utf-8")

    return result