Beispiel #1
0
 def test_mongocrypt_aws_session_token(self):
     kms_providers = {
         'aws': {
             'accessKeyId': 'foo',
             'secretAccessKey': 'foo',
             'sessionToken': 'token'
         }
     }
     opts = MongoCryptOptions(kms_providers)
     mc = MongoCrypt(opts, MockCallback())
     mc.close()
Beispiel #2
0
 def test_mongocrypt(self):
     kms_providers = {
         'aws': {
             'accessKeyId': 'foo',
             'secretAccessKey': 'foo'
         }
     }
     opts = MongoCryptOptions(kms_providers)
     mc = MongoCrypt(opts)
     mc.close()
     mc.close()
Beispiel #3
0
    def __init__(self, callback, mongo_crypt_opts):
        """Encrypts and decrypts MongoDB commands.

        This class is used by a driver to support automatic encryption and
        decryption of MongoDB commands.

        :Parameters:
          - `callback`: A :class:`MongoCryptCallback`.
          - `mongo_crypt_opts`: A :class:`MongoCryptOptions`.
        """
        self.callback = callback
        self.mongocrypt = MongoCrypt(mongo_crypt_opts)
Beispiel #4
0
    def test_mongocrypt_validation(self):
        with self.assertRaisesRegex(TypeError,
                                    'options must be a MongoCryptOptions'):
            MongoCrypt({})
        with self.assertRaisesRegex(TypeError,
                                    'options must be a MongoCryptOptions'):
            MongoCrypt(None)

        invalid_key_len_opts = MongoCryptOptions({'local': {'key': b'1'}})
        with self.assertRaisesRegex(MongoCryptError,
                                    "local key must be 96 bytes"):
            MongoCrypt(invalid_key_len_opts)
Beispiel #5
0
    def __init__(self, callback, mongo_crypt_opts):
        """Encrypts and decrypts BSON values.

        This class is used by a driver to support explicit encryption and
        decryption of individual fields in a BSON document.

        :Parameters:
          - `callback`: A :class:`MongoCryptCallback`.
          - `mongo_crypt_opts`: A :class:`MongoCryptOptions`.
        """
        self.callback = callback
        if mongo_crypt_opts.schema_map is not None:
            raise ValueError("mongo_crypt_opts.schema_map must be None")
        self.mongocrypt = MongoCrypt(mongo_crypt_opts, callback)
Beispiel #6
0
    def test_setopt_kms_provider_base64_or_bytes(self):
        test_fields = [("local", "key"), ("gcp", "privateKey")]
        callback = MockCallback()
        base_kms_dict = {
            'local': {
                'key': b'\x00' * 96
            },
            'gcp': {
                'email': '*****@*****.**',
                'privateKey': b'\x00'
            }
        }

        for f1, f2 in test_fields:
            kms_dict = copy.deepcopy(base_kms_dict)

            # Case 1: pass key as string containing bytes (valid)
            kms_dict[f1][f2] = b'\x00' * 96
            options = MongoCryptOptions(kms_dict)
            mc = MongoCrypt(options, callback)
            mc.close()

            # Case 2: pass key as base64-encoded unicode literal (valid)
            kms_dict[f1][f2] = to_base64(b'\x00' * 96)
            options = MongoCryptOptions(kms_dict)
            mc = MongoCrypt(options, callback)
            mc.close()

            # Case 3: pass key as unicode string containing bytes (invalid)
            kms_dict[f1][f2] = unicode_type(b'\x00' * 96)
            options = MongoCryptOptions(kms_dict)
            with self.assertRaisesRegex(
                    MongoCryptError,
                    "unable to parse base64 from UTF-8 field %s.%s" %
                (f1, f2)):
                MongoCrypt(options, callback)

        # Case 4: pass key as base64-encoded string (invalid)
        # Only applicable to "local" as key length is not validated for gcp.
        kms_dict = copy.deepcopy(base_kms_dict)
        kms_dict['local']['key'] = base64.b64encode(b'\x00' * 96)
        options = MongoCryptOptions(kms_dict)
        with self.assertRaisesRegex(MongoCryptError,
                                    "local key must be 96 bytes"):
            MongoCrypt(options, callback)
Beispiel #7
0
class AutoEncrypter(object):
    def __init__(self, callback, mongo_crypt_opts):
        """Encrypts and decrypts MongoDB commands.

        This class is used by a driver to support automatic encryption and
        decryption of MongoDB commands.

        :Parameters:
          - `callback`: A :class:`MongoCryptCallback`.
          - `mongo_crypt_opts`: A :class:`MongoCryptOptions`.
        """
        self.callback = callback
        self.mongocrypt = MongoCrypt(mongo_crypt_opts)

    def encrypt(self, database, cmd):
        """Encrypt a MongoDB command.

        :Parameters:
          - `database`: The database for this command.
          - `cmd`: A MongoDB command as BSON.

        :Returns:
          The encrypted command.
        """
        with self.mongocrypt.encryption_context(database, cmd) as ctx:
            return run_state_machine(ctx, self.callback)

    def decrypt(self, response):
        """Decrypt a MongoDB command response.

        :Parameters:
          - `response`: A MongoDB command response as BSON.

        :Returns:
          The decrypted command response.
        """
        with self.mongocrypt.decryption_context(response) as ctx:
            return run_state_machine(ctx, self.callback)

    def close(self):
        """Cleanup resources."""
        self.mongocrypt.close()
        self.callback.close()
Beispiel #8
0
 def create_mongocrypt():
     return MongoCrypt(
         MongoCryptOptions({
             'aws': {
                 'accessKeyId': 'example',
                 'secretAccessKey': 'example'
             },
             'local': {
                 'key': b'\x00' * 96
             }
         }), MockCallback())
Beispiel #9
0
    def test_mongocrypt_validation(self):
        callback = MockCallback()
        options = MongoCryptOptions({'local': {'key': b'\x00' * 96}})

        with self.assertRaisesRegex(TypeError,
                                    'options must be a MongoCryptOptions'):
            MongoCrypt({}, callback)
        with self.assertRaisesRegex(TypeError,
                                    'options must be a MongoCryptOptions'):
            MongoCrypt(None, callback)

        with self.assertRaisesRegex(TypeError,
                                    'callback must be a MongoCryptCallback'):
            MongoCrypt(options, {})
        with self.assertRaisesRegex(TypeError,
                                    'callback must be a MongoCryptCallback'):
            MongoCrypt(options, None)

        invalid_key_len_opts = MongoCryptOptions({'local': {'key': b'1'}})
        with self.assertRaisesRegex(MongoCryptError,
                                    "local key must be 96 bytes"):
            MongoCrypt(invalid_key_len_opts, callback)
Beispiel #10
0
class ExplicitEncrypter(object):
    def __init__(self, callback, mongo_crypt_opts):
        """Encrypts and decrypts BSON values.

        This class is used by a driver to support explicit encryption and
        decryption of individual fields in a BSON document.

        :Parameters:
          - `callback`: A :class:`MongoCryptCallback`.
          - `mongo_crypt_opts`: A :class:`MongoCryptOptions`.
        """
        self.callback = callback
        if mongo_crypt_opts.schema_map is not None:
            raise ValueError("mongo_crypt_opts.schema_map must be None")
        self.mongocrypt = MongoCrypt(mongo_crypt_opts, callback)

    def create_data_key(self,
                        kms_provider,
                        master_key=None,
                        key_alt_names=None):
        """Creates a data key used for explicit encryption.

        :Parameters:
          - `kms_provider`: The KMS provider to use. Supported values are
            "aws", "azure", "gcp", "kmip", and "local".
          - `master_key`: See DataKeyOpts.
          - `key_alt_names` (optional): An optional list of string alternate
            names used to reference a key. If a key is created with alternate
            names, then encryption may refer to the key by the unique
            alternate name instead of by ``_id``.

        :Returns:
          The _id of the created data key document.
        """
        # CDRIVER-3275 each key_alt_name needs to be wrapped in a bson
        # document.
        encoded_names = []
        if key_alt_names is not None:
            for name in key_alt_names:
                encoded_names.append(
                    self.callback.bson_encode({'keyAltName': name}))

        opts = DataKeyOpts(master_key, encoded_names)
        with self.mongocrypt.data_key_context(kms_provider, opts) as ctx:
            key = run_state_machine(ctx, self.callback)
        return self.callback.insert_data_key(key)

    def encrypt(self, value, algorithm, key_id=None, key_alt_name=None):
        """Encrypts a BSON value.

        Note that exactly one of ``key_id`` or  ``key_alt_name`` must be
        provided.

        :Parameters:
          - `value` (bytes): The BSON value to encrypt.
          - `algorithm` (string): The encryption algorithm to use. See
            :class:`Algorithm` for some valid options.
          - `key_id` (bytes): The bytes of the binary subtype 4 ``_id`` data
            key. For example, ``uuid.bytes`` or ``bytes(bson_binary)``.
          - `key_alt_name` (string): Identifies a key vault document by
            'keyAltName'.

        :Returns:
          The encrypted BSON value.
        """
        # CDRIVER-3275 key_alt_name needs to be wrapped in a bson document.
        if key_alt_name is not None:
            key_alt_name = self.callback.bson_encode(
                {'keyAltName': key_alt_name})
        opts = ExplicitEncryptOpts(algorithm, key_id, key_alt_name)
        with self.mongocrypt.explicit_encryption_context(value, opts) as ctx:
            return run_state_machine(ctx, self.callback)

    def decrypt(self, value):
        """Decrypts a BSON value.

        :Parameters:
          - `value`: The encoded document to decrypt, which must be in the
            form { "v" : encrypted BSON value }}.

        :Returns:
          The decrypted BSON value.
        """
        with self.mongocrypt.explicit_decryption_context(value) as ctx:
            return run_state_machine(ctx, self.callback)

    def close(self):
        """Cleanup resources."""
        self.mongocrypt.close()