def test_authorisation():
    key = PrivateKey()

    resource = uuid.uuid4()

    auth = Authorisation(resource=resource, testing_key=key)

    auth.verify(resource=resource, testing_key=key.public_key())

    wrong_key = PrivateKey()

    with pytest.raises(PermissionError):
        auth.verify(resource=resource, testing_key=wrong_key.public_key())

    wrong_resource = uuid.uuid4()

    with pytest.raises(PermissionError):
        auth.verify(resource=wrong_resource, testing_key=key.public_key())

    data = auth.to_data()

    new_auth = Authorisation.from_data(data)

    new_auth.verify(resource=resource, testing_key=key.public_key())

    with pytest.raises(PermissionError):
        new_auth.verify(resource=resource, testing_key=wrong_key.public_key())

    with pytest.raises(PermissionError):
        new_auth.verify(resource=wrong_resource, testing_key=key.public_key())
def test_filewriterequest():
    basedir = os.path.dirname(os.path.abspath(__file__))

    filenames = [os.path.abspath(__file__),
                 os.path.abspath("%s/../Accounting/test_account.py" % basedir)]

    testkey = PrivateKey()

    r = FileWriteRequest(source=filenames, testing_key=testkey)

    data = r.to_data()

    r2 = Request.from_data(data)

    assert(r == r2)
    assert(r.uid() == r2.uid())

    for i, filename in enumerate(filenames):
        md5sum = hashlib.md5(open(filename, "rb").read()).hexdigest()
        assert(md5sum == r.checksums()[i])

    r.authorisation().verify(r.resource_key(),
                             testing_key=testkey.public_key())

    r2.authorisation().verify(r2.resource_key(),
                              testing_key=testkey.public_key())

    testkey2 = PrivateKey()

    r2 = FileWriteRequest(source=filenames, testing_key=testkey2)

    assert(r != r2)
    assert(r.uid() != r2.uid())

    for i, filename in enumerate(filenames):
        md5sum = hashlib.md5(open(filename, "rb").read()).hexdigest()
        assert(md5sum == r2.checksums()[i])

    r2.authorisation().verify(r2.resource_key(),
                              testing_key=testkey2)

    with pytest.raises(PermissionError):
        r.authorisation().verify(r.resource_key(),
                                 testing_key=testkey2)

    with pytest.raises(PermissionError):
        r.authorisation().verify(r2.resource_key(),
                                 testing_key=testkey)

    with pytest.raises(PermissionError):
        r2.authorisation().verify(r.resource_key(),
                                  testing_key=testkey2)

    with pytest.raises(PermissionError):
        r2.authorisation().verify(r2.resource_key(),
                                  testing_key=testkey)
Esempio n. 3
0
def authenticated_user(aaai_services):
    from Acquire.Crypto import PrivateKey, OTP
    from Acquire.Client import User, Service, Wallet

    username = str(uuid.uuid4())
    password = PrivateKey.random_passphrase()

    result = User.register(username=username,
                           password=password,
                           identity_url="identity")

    otpsecret = result["otpsecret"]
    otp = OTP(otpsecret)

    # now log the user in
    user = User(username=username, identity_url="identity", auto_logout=False)

    result = user.request_login()

    assert (type(result) is dict)

    wallet = Wallet()

    wallet.send_password(url=result["login_url"],
                         username=username,
                         password=password,
                         otpcode=otp.generate(),
                         remember_password=False,
                         remember_device=False)

    user.wait_for_login()

    assert (user.is_logged_in())

    return user
Esempio 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()))
Esempio n. 5
0
    def _get_wallet_key(self):
        """Return the private key used to encrypt everything in the wallet.
           This will ask for the users password
        """
        if self._wallet_key:
            return self._wallet_key

        wallet_dir = ServiceWallet._wallet_dir()

        keyfile = "%s/wallet_key.pem" % wallet_dir

        if not _os.path.exists(keyfile):
            self._wallet_key = self._create_wallet_key(keyfile)
            return self._wallet_key

        # read the keyfile and decrypt
        with open(keyfile, "rb") as FILE:
            bytes = FILE.read()

        # get the user password
        wallet_key = None
        while not wallet_key:
            password = _getpass.getpass(
                prompt="Please enter your wallet password: "******"Invalid password. Please try again.")

        self._wallet_key = wallet_key
        return wallet_key
Esempio n. 6
0
    def from_data(data, password=None):
        """Deserialise this object from the passed data. This will
           only deserialise the private key, private certificate,
           and OTP if a valid password and passcode is supplied
        """

        service = Service()

        if password:
            # get the private info...
            service._privkey = _PrivateKey.from_data(data["private_key"],
                                                     password)

            service._privcert = _PrivateKey.from_data(
                                                data["private_certificate"],
                                                password)

            service._otpsecret = _string_to_bytes(data["otpsecret"])

            service._admin_password = _string_to_bytes(data["admin_password"])
        else:
            service._privkey = None
            service._privcert = None
            service._otpsecret = None

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

        service._pubkey = _PublicKey.from_data(data["public_key"])
        service._pubcert = _PublicKey.from_data(data["public_certificate"])

        if service.is_identity_service():
            from Acquire.Identity import IdentityService as _IdentityService
            return _IdentityService(service)
        elif service.is_access_service():
            from Acquire.Access import AccessService as _AccessService
            return _AccessService(service)
        elif service.is_accounting_service():
            from Acquire.Accounting import AccountingService \
                                        as _AccountingService
            return _AccountingService(service)
        else:
            return service
def test_json_keys():
    privkey = PrivateKey()
    pubkey = privkey.public_key()

    args = {
        "message": "Hello, this is a message",
        "status": 0,
        "long": [random.random() for _ in range(1000)]
    }

    packed = pack_arguments(args)

    crypted = pubkey.encrypt(packed)

    uncrypted = privkey.decrypt(crypted)

    unpacked = unpack_arguments(uncrypted)

    assert (args == unpacked)
Esempio n. 8
0
def run(args):
    """This function is used to request access to a bucket for
       data in the object store. The user can request read-only
       or read-write access. Access is granted based on a permission
       list
    """

    status = 0
    message = None

    access_token = None

    user_uuid = args["user_uuid"]
    identity_service_url = args["identity_service"]

    # log into the central access account
    bucket = login_to_service_account()

    # is the identity service supplied by the user one that we trust?
    identity_service = Service.from_data(
        ObjectStore.get_object_from_json(bucket,
                                         "services/%s" % identity_service_url))

    if not identity_service:
        raise RequestBucketError(
            "You cannot request a bucket because "
            "this access service does not know or trust your supplied "
            "identity service (%s)" % identity_service_url)

    if not identity_service.is_identity_service():
        raise RequestBucketError(
            "You cannot request a bucket because "
            "the passed service (%s) is not an identity service. It is "
            "a %s" % (identity_service_url, identity_service.service_type()))

    # Since we trust this identity service, we can ask it to give us the
    # public certificate and signing certificate for this user.
    key = PrivateKey()

    response = call_function(identity_service_url,
                             "get_user_keys",
                             args_key=identity_service.public_key(),
                             response_key=key,
                             user_uuid=user_uuid)

    status = 0
    message = "Success: Status = %s" % str(response)

    return_value = create_return_value(status, message)

    if access_token:
        return_value["access_token"] = access_token

    return return_value
Esempio n. 9
0
def test_service_object(tmpdir_factory):
    bucket = tmpdir_factory.mktemp("test_service")
    push_testing_objstore(bucket)
    push_is_running_service()

    try:
        service = Service.create(service_type="identity",
                                 service_url="identity")

        assert(service.uid() is not None)
        assert(service.uid().startswith("STAGE1"))

        service.create_stage2(service_uid="Z9-Z8", response=service.uid())

        assert(service.is_identity_service())
        assert(not service.should_refresh_keys())
        assert(service.is_unlocked())
        assert(not service.is_locked())

        passphrase = PrivateKey.random_passphrase()

        data = service.to_data(passphrase)

        service2 = IdentityService.from_data(data, passphrase)

        assert(service2.uid() == service.uid())
        assert(service2.is_unlocked())
        assert(not service2.is_locked())
        assert(service2.is_identity_service())
        assert(service.canonical_url() == service2.canonical_url())
        assert(not service2.should_refresh_keys())

        keys = service.dump_keys()

        keys = service.load_keys(keys)

        assert(keys[service.private_key().fingerprint()] ==
               service.private_key())
        assert(keys[service.private_certificate().fingerprint()] ==
               service.private_certificate())

        service.refresh_keys()

        assert(service.last_key_update() > service2.last_key_update())
        assert(service.last_certificate().public_key() ==
               service2.public_certificate())
        assert(service.last_key() == service2.private_key())
    except:
        pop_is_running_service()
        pop_testing_objstore()
        raise

    pop_is_running_service()
    pop_testing_objstore()
Esempio n. 10
0
    def __init__(self, drive_uid=None, file_uid=None):
        """Create a new ChunkUploader that uploads the specified
           file to the specified drive
        """
        self._drive_uid = None
        self._file_uid = None
        self._chunk_idx = None
        self._service = None

        if drive_uid is not None:
            self._drive_uid = str(drive_uid)
            self._file_uid = str(file_uid)
            from Acquire.Crypto import PrivateKey as _PrivateKey
            self._secret = _PrivateKey.random_passphrase()
Esempio n. 11
0
    def reset_admin_password(self, password, otpcode, new_password):
        """Change the admin password for this service. Note that
           you must pass in a valid password and otpcode to make the change"""

        self.verify_admin_user(password, otpcode)

        if password == new_password:
            return

        key = _PrivateKey.read_bytes(self._admin_password, password)
        otp = _OTP.decrypt(self._otpsecret, key)
        otp.verify(otpcode)

        newkey = _PrivateKey()
        self._admin_password = newkey.bytes(new_password)
        self._otpsecret = otp.encrypt(newkey.public_key())
Esempio n. 12
0
    def from_data(data, passphrase=None):
        """Return a OSPar constructed from the passed json-deserliased
           dictionary

           Args:
                data (dict): JSON-deserialised dictionary from which to
                create OSPar
            Returns:
                OSPar: OSPar object created from dict
        """
        if data is None or len(data) == 0:
            return OSPar()

        from Acquire.ObjectStore import string_to_datetime \
            as _string_to_datetime
        from Acquire.ObjectStore import string_to_bytes \
            as _string_to_bytes

        par = OSPar()

        par._url = _string_to_bytes(data["url"])
        par._key = data["key"]
        par._uid = data["uid"]

        if par._key is not None:
            par._key = str(par._key)

        par._expires_datetime = _string_to_datetime(data["expires_datetime"])
        par._is_readable = data["is_readable"]
        par._is_writeable = data["is_writeable"]

        if "service_url" in data:
            par._service_url = data["service_url"]

        if "privkey" in data:
            if passphrase is not None:
                from Acquire.Crypto import PrivateKey as _PrivateKey
                par._privkey = _PrivateKey.from_data(data["privkey"],
                                                     passphrase)

        # note that we don't load the driver details as this
        # is stored and loaded separately on the service

        return par
Esempio n. 13
0
    def from_data(data, passphrase, mangleFunction=None):
        """Return a UserAccount constructed from the passed
           data (dictionary)
        """

        user = UserAccount()

        if data is not None and len(data) > 0:
            from Acquire.Crypto import PrivateKey as _PrivateKey

            user._username = data["username"]
            user._status = data["status"]
            user._uid = data["uid"]
            user._privkey = _PrivateKey.from_data(
                data=data["private_key"],
                passphrase=passphrase,
                mangleFunction=mangleFunction)

        return user
Esempio n. 14
0
    def verify_admin_user(self, password, otpcode, remember_device=False):
        """Verify that we are the admin user verifying that
           the passed password and otpcode are correct. This does
           nothing if they are correct, but raises an exception
           if they are wrong. If 'remember_device' this this returns
           the provisioning_uri for the OTP generator"""

        try:
            key = _PrivateKey.read_bytes(self._admin_password, password)
        except Exception as e:
            raise ServiceError("Could not log into admin account: %s" % str(e))

        try:
            otp = _OTP.decrypt(self._otpsecret, key)
            otp.verify(otpcode)
            if remember_device:
                return otp.provisioning_uri("admin", self.service_url())
        except Exception as e:
            raise ServiceError("Could not log into admin account: %s" % str(e))
Esempio n. 15
0
    def __init__(self, drive_uid=None, file_uid=None):
        """Create a new ChunkDowloader that downloads the specified
           file from the specified drive
        """
        self._uid = None
        self._drive_uid = None
        self._file_uid = None
        self._service = None

        self._next_index = None
        self._last_filename = None
        self._downloaded_filename = None
        self._FILE = None

        if drive_uid is not None:
            self._drive_uid = str(drive_uid)
            self._file_uid = str(file_uid)
            from Acquire.Crypto import PrivateKey as _PrivateKey
            self._secret = _PrivateKey.random_passphrase()

            from Acquire.ObjectStore import create_uid as _create_uid
            self._uid = _create_uid(short_uid=True)
Esempio n. 16
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"])
Esempio n. 17
0
def aaai_services(tmpdir_factory):
    """This function creates mocked versions of all of the main services
       of the system, returning the json describing each service as
       a dictionary (which is passed to the test functions as the
       fixture)
    """
    from Acquire.Identity import Authorisation
    from Acquire.Crypto import PrivateKey, OTP
    from Acquire.Service import call_function, Service

    _services = {}
    _services["registry"] = tmpdir_factory.mktemp("registry")
    _services["identity"] = tmpdir_factory.mktemp("identity")
    _services["accounting"] = tmpdir_factory.mktemp("accounting")
    _services["access"] = tmpdir_factory.mktemp("access")
    _services["storage"] = tmpdir_factory.mktemp("storage")
    _services["userdata"] = tmpdir_factory.mktemp("userdata")
    _services["compute"] = tmpdir_factory.mktemp("compute")
    _services["hugs"] = tmpdir_factory.mktemp("hugs")

    wallet_dir = tmpdir_factory.mktemp("wallet")
    wallet_password = PrivateKey.random_passphrase()

    _set_services(_services, wallet_dir, wallet_password)

    password = PrivateKey.random_passphrase()
    args = {"password": password}

    responses = {}

    os.environ["SERVICE_PASSWORD"] = "******"
    os.environ["STORAGE_COMPARTMENT"] = str(_services["userdata"])

    args["canonical_url"] = "registry"
    args["service_type"] = "registry"
    args["registry_uid"] = "Z9-Z9"  # UID of testing registry
    response = call_function("registry", function="admin/setup", args=args)

    registry_service = Service.from_data(response["service"])
    registry_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    registry_user = _login_admin("registry", "admin", password, registry_otp)
    responses["registry"] = {
        "service": registry_service,
        "user": registry_user,
        "response": response,
    }

    assert registry_service.registry_uid() == registry_service.uid()
    service_uids = [registry_service.uid()]

    args["canonical_url"] = "identity"
    args["service_type"] = "identity"
    response = call_function("identity", function="admin/setup", args=args)

    identity_service = Service.from_data(response["service"])
    identity_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    identity_user = _login_admin("identity", "admin", password, identity_otp)
    responses["identity"] = {
        "service": identity_service,
        "user": identity_user,
        "response": response,
    }

    assert identity_service.registry_uid() == registry_service.uid()
    assert identity_service.uid() not in service_uids
    service_uids.append(identity_service.uid())

    args["canonical_url"] = "accounting"
    args["service_type"] = "accounting"
    response = call_function("accounting", function="admin/setup", args=args)
    accounting_service = Service.from_data(response["service"])
    accounting_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    accounting_user = _login_admin("accounting", "admin", password,
                                   accounting_otp)
    responses["accounting"] = {
        "service": accounting_service,
        "user": accounting_user,
        "response": response,
    }

    assert accounting_service.registry_uid() == registry_service.uid()
    assert accounting_service.uid() not in service_uids
    service_uids.append(accounting_service.uid())

    args["canonical_url"] = "access"
    args["service_type"] = "access"
    response = call_function("access", function="admin/setup", args=args)
    responses["access"] = response
    access_service = Service.from_data(response["service"])
    access_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    access_user = _login_admin("access", "admin", password, access_otp)
    responses["access"] = {
        "service": access_service,
        "user": access_user,
        "response": response,
    }

    assert access_service.registry_uid() == registry_service.uid()
    assert access_service.uid() not in service_uids
    service_uids.append(access_service.uid())

    args["canonical_url"] = "compute"
    args["service_type"] = "compute"
    response = call_function("compute", function="admin/setup", args=args)
    responses["compute"] = response
    compute_service = Service.from_data(response["service"])
    compute_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    compute_user = _login_admin("compute", "admin", password, compute_otp)
    responses["compute"] = {
        "service": compute_service,
        "user": compute_user,
        "response": response,
    }

    assert compute_service.registry_uid() == registry_service.uid()
    assert compute_service.uid() not in service_uids
    service_uids.append(compute_service.uid())

    args["canonical_url"] = "storage"
    args["service_type"] = "storage"
    response = call_function("storage", function="admin/setup", args=args)
    storage_service = Service.from_data(response["service"])
    storage_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    storage_user = _login_admin("storage", "admin", password, storage_otp)
    responses["storage"] = {
        "service": storage_service,
        "user": storage_user,
        "response": response,
    }

    assert storage_service.registry_uid() == registry_service.uid()
    assert storage_service.uid() not in service_uids
    service_uids.append(storage_service.uid())

    args["canonical_url"] = "hugs"
    args["service_type"] = "hugs"
    response = call_function("hugs", function="admin/setup", args=args)
    responses["hugs"] = response
    hugs_service = Service.from_data(response["service"])
    hugs_otp = OTP(OTP.extract_secret(response["provisioning_uri"]))
    hugs_user = _login_admin("hugs", "admin", password, hugs_otp)
    responses["hugs"] = {
        "service": hugs_service,
        "user": hugs_user,
        "response": response,
    }

    resource = "trust_accounting_service %s" % accounting_service.uid()
    args = {
        "service_url":
        accounting_service.canonical_url(),
        "authorisation":
        Authorisation(user=access_user, resource=resource).to_data(),
    }
    access_service.call_function(function="admin/trust_accounting_service",
                                 args=args)

    responses["_services"] = _services

    return responses
Esempio n. 18
0
    def validate_password(user_uid, username, device_uid, secrets, password,
                          otpcode, remember_device):
        """Validate that the passed password and one-time-code are valid.
           If they are, then return a tuple of the UserAccount of the unlocked
           user, the OTP that is used to generate secrets, and the
           device_uid of the login device

           If 'remember_device' is True and 'device_uid' is None, then
           this creates a new OTP for the login device, which is returned,
           and a new device_uid for that device. The password needed to
           match this device is a MD5 of the normal user password.
        """
        from Acquire.Crypto import PrivateKey as _PrivateKey
        from Acquire.Crypto import OTP as _OTP
        from Acquire.ObjectStore import string_to_bytes as _string_to_bytes

        privkey = _PrivateKey.from_data(data=secrets["private_key"],
                                        passphrase=password)

        # decrypt and validate the OTP code
        data = _string_to_bytes(secrets["otpsecret"])

        otpsecret = privkey.decrypt(data)
        otp = _OTP(secret=otpsecret)
        otp.verify(code=otpcode, once_only=True)

        # everything is ok - we can load the user account via the
        # decrypted primary password
        primary_password = _string_to_bytes(secrets["primary_password"])
        primary_password = privkey.decrypt(primary_password)

        from Acquire.ObjectStore import ObjectStore as _ObjectStore
        from Acquire.Service import get_service_account_bucket \
            as _get_service_account_bucket

        data = None
        secrets = None
        key = "%s/uids/%s" % (_user_root, user_uid)

        bucket = _get_service_account_bucket()

        try:
            data = _ObjectStore.get_object_from_json(bucket=bucket, key=key)
        except:
            pass

        if data is None:
            from Acquire.Identity import UserValidationError
            raise UserValidationError(
                "Unable to validate user as no account data is present!")

        from Acquire.Identity import UserAccount as _UserAccount
        user = _UserAccount.from_data(data=data, passphrase=primary_password)

        if user.uid() != user_uid:
            from Acquire.Identity import UserValidationError
            raise UserValidationError(
                "Unable to validate user as mismatch in user_uids!")

        if device_uid is None and remember_device:
            # create a new OTP that is unique for this device
            from Acquire.ObjectStore import create_uuid as _create_uuid
            from Acquire.Client import Credentials as _Credentials
            device_uid = _create_uuid()
            device_password = _Credentials.encode_device_uid(
                                                encoded_password=password,
                                                device_uid=device_uid)

            otp = UserCredentials.create(user_uid=user_uid,
                                         password=device_password,
                                         primary_password=primary_password,
                                         device_uid=device_uid)

            # now save a lookup so that we can find the user_uid from
            # the username and device-specific password
            encoded_password = UserCredentials.hash(
                                        username=username,
                                        password=device_password)

            key = "%s/passwords/%s/%s" % (_user_root, encoded_password,
                                          user_uid)

            from Acquire.ObjectStore import get_datetime_now_to_string \
                as _get_datetime_now_to_string

            _ObjectStore.set_string_object(
                                bucket=bucket, key=key,
                                string_data=_get_datetime_now_to_string())

        return {"user": user, "otp": otp, "device_uid": device_uid}
Esempio n. 19
0
service_file = "service.json"

if os.path.exists(service_file):
    with open(service_file, "r") as FILE:
        service_info = json.load(FILE)
        service_salt = service_info["salt"]

    while True:
        password = getpass.getpass(
            prompt="Please enter the service primary password: "******"key"],
                                               passphrase=password)
            break
        except:
            print("Password incorrect. Try again.")

    old_config = service_key.decrypt(string_to_bytes(service_info["config"]))
    old_config = json.loads(old_config)
    keep = True
else:
    while True:
        password = getpass.getpass(
            prompt="Please enter the service primary password: "******"Please enter the password again: ")

        if password == password2:
            break
Esempio n. 20
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)
Esempio n. 21
0
def run(args):
    """This function will allow a user to register an account with a
       username and password"""

    status = 0
    message = None
    provisioning_uri = None

    username = args["username"]
    password = args["password"]

    # generate a sanitised version of the username
    user_account = UserAccount(username)

    # generate the encryption keys and otp secret
    privkey = PrivateKey()
    pubkey = privkey.public_key()
    otp = OTP()

    provisioning_uri = otp.provisioning_uri(username)

    # save the encrypted private key (encrypted using the user's password)
    # and encrypted OTP secret (encrypted using the public key)
    user_account.set_keys(privkey.bytes(password), pubkey.bytes(),
                          otp.encrypt(pubkey))

    # remove the key and password from memory
    privkey = None
    password = None

    # now log into the central identity account to either register
    # the user, or to update to a new password
    bucket = login_to_service_account()
    account_key = "accounts/%s" % user_account.sanitised_name()

    try:
        existing_data = ObjectStore.get_object_from_json(bucket,
                                                         account_key)
    except:
        existing_data = None

    message = "Created a new account for '%s'" % username
    status = 0

    if existing_data is None:
        # save the new account details
        ObjectStore.set_object_from_json(bucket, account_key,
                                         user_account.to_data())

        # need to update the "whois" database with the uuid of this user
        ObjectStore.set_string_object(bucket,
                                      "whois/%s" % user_account.uuid(),
                                      user_account.username())
    else:
        # The account already exists. See if this is a password change
        # request
        old_password = None

        try:
            old_password = args["old_password"]
        except:
            raise ExistingAccountError(
                "An account by this name already exists!")

        if old_password != password:
            # this is a change of password request - validate that
            # the existing password unlocks the existing key
            user_account = UserAccount.from_data(existing_data)

            testkey = PrivateKey.read_bytes(user_account.private_key(),
                                            old_password)

            # decrypt the old secret
            old_secret = testkey.decrypt(user_account.otp_secret())

            # now encrypt the secret with the new key
            new_key = PublicKey.read_bytes(pubkey)
            new_secret = new_key.encrypt(old_secret)

            user_account.set_keys(privkey, pubkey, new_secret)

            # save the new account details
            ObjectStore.set_object_from_json(bucket, account_key,
                                             user_account.to_data())

            message = "Updated the password for '%s'" % username
        else:
            message = "No need to change account '%s'" % username

    return_value = create_return_value(status, message)

    if provisioning_uri:
        return_value["provisioning_uri"] = provisioning_uri

    return return_value
Esempio n. 22
0
    def __init__(self,
                 location=None,
                 user=None,
                 aclrule=None,
                 expires_datetime=None):
        """Construct a PAR for the specified location,
           authorised by the passed user, giving permissions
           according to the passed 'aclrule' (default is
           ACLRule.reader()).

           The passed 'expires_datetime' is the time at which
           this PAR will expire (by default within 24 hours)
        """
        self._location = None
        self._uid = None
        self._expires_datetime = None

        if location is None:
            return

        from Acquire.Client import Location as _Location
        if not isinstance(location, _Location):
            raise TypeError("The location must be type Location")

        if location.is_null():
            return

        from Acquire.Client import User as _User
        if not isinstance(user, _User):
            raise TypeError("The user must be type User")

        if not user.is_logged_in():
            raise PermissionError("The passed User must be logged in!")

        from Acquire.Client import ACLRule as _ACLRule

        if aclrule is None:
            aclrule = _ACLRule.reader()
        elif not isinstance(aclrule, _ACLRule):
            raise TypeError("The aclrule must be type ACLRule")

        if expires_datetime is None:
            from Acquire.ObjectStore import get_datetime_future \
                as _get_datetime_future
            expires_datetime = _get_datetime_future(days=1)
        else:
            from Acquire.ObjectStore import datetime_to_datetime \
                as _datetime_to_datetime
            expires_datetime = _datetime_to_datetime(expires_datetime)

        self._location = location
        self._expires_datetime = expires_datetime
        self._aclrule = aclrule

        from Acquire.Client import Authorisation as _Authorisation
        auth = _Authorisation(user=user,
                              resource="create_par %s" % self.fingerprint())

        from Acquire.Crypto import PrivateKey as _PrivateKey
        self._secret = _PrivateKey.random_passphrase()

        args = {
            "authorisation": auth.to_data(),
            "par": self.to_data(),
            "secret": self._secret
        }

        service = location.service()

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

        self._set_uid(result["par_uid"])
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
Esempio n. 24
0
def get_service_account_bucket(testing_dir=None):
    """This function logs into the object store account of the service account.
       Accessing the object store means being able to access
       all resources and which can authorise the creation
       of access all resources on the object store. Obviously this is
       a powerful account, so only log into it if you need it!!!

       The login information should not be put into a public
       repository or stored in plain text. In this case,
       the login information is held in an environment variable
       (which should be encrypted or hidden in some way...)
    """
    from Acquire.Service import assert_running_service as \
        _assert_running_service

    _assert_running_service()

    # read the password for the secret key from the filesystem
    try:
        with open("secret_key", "r") as FILE:
            password = FILE.readline()[0:-1]
    except:
        password = None

        # we must be in testing mode...
        from Acquire.ObjectStore import use_testing_object_store_backend as \
            _use_testing_object_store_backend

        # see if this is running in testing mode...
        global _current_testing_objstore
        if testing_dir:
            _current_testing_objstore = testing_dir
            return _use_testing_object_store_backend(testing_dir)
        elif _current_testing_objstore:
            return _use_testing_object_store_backend(_current_testing_objstore)

    if password is None:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "You need to supply login credentials via the 'secret_key' "
            "file, and 'SECRET_KEY' and 'SECRET_CONFIG' environment "
            "variables! %s" % testing_dir)

    secret_key = _os.getenv("SECRET_KEY")

    if secret_key is None:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "You must supply the password used to unlock the configuration "
            "key in the 'SECRET_KEY' environment variable")

    try:
        secret_key = _json.loads(secret_key)
    except Exception as e:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "Unable to decode valid JSON from the secret key: %s" % str(e))

    # use the password to decrypt the SECRET_KEY in the config
    try:
        from Acquire.Crypto import PrivateKey as _PrivateKey
        secret_key = _PrivateKey.from_data(secret_key, password)
    except Exception as e:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "Unable to open the private SECRET_KEY using the password "
            "supplied in the 'secret_key' file: %s" % str(e))

    config = _os.getenv("SECRET_CONFIG")

    if config is None:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "You must supply the encrypted config in teh 'SECRET_CONFIG' "
            "environment variable!")

    try:
        from Acquire.ObjectStore import string_to_bytes as _string_to_bytes
        config = secret_key.decrypt(_string_to_bytes(config))
    except Exception as e:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "Cannot decrypt the 'SECRET_CONFIG' with the 'SECRET_KEY'. Are "
            "you sure that the configuration has been set up correctly? %s "
            % str(e))

    # use the secret_key to decrypt the config in SECRET_CONFIG
    try:
        config = _json.loads(config)
    except Exception as e:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
            "Unable to decode valid JSON from the config: %s" % str(e))

    # get info from this config
    access_data = config["LOGIN"]
    bucket_data = config["BUCKET"]

    # save the service password to the environment
    _os.environ["SERVICE_PASSWORD"] = config["PASSWORD"]

    # save any other decrypted config data to environment variables
    for key in config.keys():
        if key not in ["LOGIN", "BUCKET", "PASSWORD"]:
            _os.environ[key] = config[key]

    # we have OCI login details, so make sure that we are using
    # the OCI object store backend
    from Acquire.ObjectStore import use_oci_object_store_backend as \
        _use_oci_object_store_backend

    _use_oci_object_store_backend()

    # now login and create/load the bucket for this account
    try:
        from ._oci_account import OCIAccount as _OCIAccount

        account_bucket = _OCIAccount.create_and_connect_to_bucket(
                                    access_data,
                                    bucket_data["compartment"],
                                    bucket_data["bucket"])
    except Exception as e:
        from Acquire.Service import ServiceAccountError
        raise ServiceAccountError(
             "Error connecting to the service account: %s" % str(e))

    return account_bucket
Esempio n. 25
0
def test_keys():
    privkey = PrivateKey()
    pubkey = privkey.public_key()

    message = "Hello World"

    sig = privkey.sign(message.encode("utf-8"))
    pubkey.verify(sig, message.encode("utf-8"))

    c = pubkey.encrypt(message.encode("utf-8"))

    m = privkey.decrypt(c).decode("utf-8")
    assert (m == message)

    privkey2 = PrivateKey()
    sig2 = privkey2.sign(message.encode("utf-8"))

    with pytest.raises(SignatureVerificationError):
        pubkey.verify(sig2, message.encode("utf-8"))

    bytes = privkey.bytes("testPass32")

    PrivateKey.read_bytes(bytes, "testPass32")

    privkey.write("test.pem", "testPass32")

    PrivateKey.read("test.pem", "testPass32")

    bytes = pubkey.bytes()
    pubkey2 = PublicKey.read_bytes(bytes)

    assert (bytes == pubkey2.bytes())

    long_message = str([random.getrandbits(8)
                        for _ in range(4096)]).encode("utf-8")

    c = pubkey.encrypt(long_message)

    m = privkey.decrypt(c)

    assert (m == long_message)

    os.unlink("test.pem")

    data = pubkey.to_data()

    pubkey2 = PublicKey.from_data(data)

    assert (pubkey.bytes() == pubkey2.bytes())

    data = privkey.to_data("testPass33")

    privkey2 = PrivateKey.from_data(data, "testPass33")

    assert (privkey == privkey2)
Esempio n. 26
0
"""
This script writes the login information (pem key etc.) that is needed
by the identity service to log onto the object store as the
identity admin user account
"""

import json
import sys
import os

from Acquire.Crypto import PrivateKey
from Acquire.ObjectStore import bytes_to_string

## Create a key to encrypt the config
config_key = PrivateKey()
secret_config = {}

## First create the login info to connect to the account
"""
[DEFAULT]
user=ocid1.user.oc1..aaaaaaaasuhkztlrvedgnkqnywkuj7giu7o4nyqohtwyk7zeldpkiktrhosq
fingerprint=5d:ac:65:4c:11:69:5b:e7:e8:5c:04:39:93:f0:cd:c8
key_file=~/.oci/oci_api_key.pem
pass_phrase=XXXXXX
tenancy=ocid1.tenancy.oc1..aaaaaaaa3eiex6fbfj626uwhs3dg24oygknrhhgfj4khqearluf4i74zdt2a
region=eu-frankfurt-1
"""

data = {}

# OCID for the user "bss-auth-service"
Esempio n. 27
0
import pytest

from Acquire.Service import call_function
from Acquire.Client import User, Wallet
from Acquire.Identity import Authorisation
from Acquire.Crypto import OTP, PrivateKey

_wallet_password = PrivateKey.random_passphrase()


@pytest.mark.parametrize("username, password",
                         [("testuser", "ABCdef12345"),
                          ("something", "!!DDerfld31"),
                          ("someone", "%$(F*Dj4jij43  kdfjdk")])
def test_login(username, password, aaai_services, tmpdir):
    # register the new user
    result = User.register(username=username,
                           password=password,
                           identity_url="identity")

    assert(type(result) is dict)

    otpsecret = result["otpsecret"]

    otp = OTP(otpsecret)

    user = User(username=username, identity_url="identity",
                auto_logout=False)

    result = user.request_login()
def login_to_service_account(testing_dir=None):
    """This function logs into the object store account of the service account.
       Accessing the object store means being able to access
       all resources and which can authorise the creation
       of access all resources on the object store. Obviously this is
       a powerful account, so only log into it if you need it!!!

       The login information should not be put into a public
       repository or stored in plain text. In this case,
       the login information is held in an environment variable
       (which should be encrypted or hidden in some way...)
    """

    # read the password for the secret key from the filesystem
    try:
        with open("secret_key", "r") as FILE:
            password = FILE.readline()[0:-1]
    except:
        password = None

        # we must be in testing mode...
        from Acquire.ObjectStore import use_testing_object_store_backend as \
            _use_testing_object_store_backend

        # see if this is running in testing mode...
        global _current_testing_objstore
        if testing_dir:
            _current_testing_objstore = testing_dir
            return _use_testing_object_store_backend(testing_dir)
        elif _current_testing_objstore:
            return _use_testing_object_store_backend(_current_testing_objstore)

    if password is None:
        raise ServiceAccountError(
            "You need to supply login credentials via the 'secret_key' "
            "file, and 'SECRET_KEY' and 'SECRET_CONFIG' environment "
            "variables! %s" % testing_dir)

    # use the password to decrypt the SECRET_KEY in the config
    secret_key = _PrivateKey.from_data(_json.loads(_os.getenv("SECRET_KEY")),
                                       password)

    # use the secret_key to decrypt the config in SECRET_CONFIG
    config = _json.loads(
        secret_key.decrypt(_string_to_bytes(
            _os.getenv("SECRET_CONFIG"))).decode("utf-8"))

    # get info from this config
    access_data = config["LOGIN"]
    bucket_data = config["BUCKET"]

    # save the service password to the environment
    _os.environ["SERVICE_PASSWORD"] = config["PASSWORD"]

    # we have OCI login details, so make sure that we are using
    # the OCI object store backend
    from Acquire.ObjectStore import use_oci_object_store_backend as \
        _use_oci_object_store_backend

    _use_oci_object_store_backend()

    # now login and create/load the bucket for this account
    try:
        from ._oci_account import OCIAccount as _OCIAccount

        account_bucket = _OCIAccount.create_and_connect_to_bucket(
            access_data, bucket_data["compartment"], bucket_data["bucket"])
    except Exception as e:
        raise ServiceAccountError(
            "Error connecting to the service account: %s" % str(e))

    return account_bucket