diff --git a/docs/API.md b/docs/API.md
index a7e308e28..a2b180e1d 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -53,7 +53,7 @@ s3Client = Minio(
| [`set_bucket_policy`](#set_bucket_policy) | | |
| [`delete_bucket_policy`](#delete_bucket_policy) | | |
| [`get_bucket_encryption`](#get_bucket_encryption) | | |
-| [`put_bucket_encryption`](#put_bucket_encryption) | | |
+| [`set_bucket_encryption`](#set_bucket_encryption) | | |
| [`delete_bucket_encryption`](#delete_bucket_encryption) | | |
## 1. Constructor
@@ -447,9 +447,9 @@ __Parameters__
__Return Value__
-| Param |
-|:------------------------------------|
-| Encryption configuration as _dict_. |
+| Param |
+|:--------------------|
+| _SSEConfig_ object. |
__Example__
@@ -457,32 +457,25 @@ __Example__
config = minio.get_bucket_encryption("my-bucketname")
```
-
+
-### put_bucket_encryption(bucket_name, encryption_configuration)
+### set_bucket_encryption(bucket_name, config)
Set encryption configuration of a bucket.
__Parameters__
-| Param | Type | Description |
-|:----------------|:-------|:--------------------------------------------------|
-| ``bucket_name`` | _str_ | Name of the bucket. |
-| ``enc_config`` | _dict_ | Encryption configuration as dictionary to be set. |
+| Param | Type | Description |
+|:----------------|:------------|:--------------------------------------|
+| ``bucket_name`` | _str_ | Name of the bucket. |
+| ``config`` | _SSEConfig_ | Server-side encryption configuration. |
__Example__
```py
-# Sample default encryption configuration
-config = {
- 'ServerSideEncryptionConfiguration':{
- 'Rule': [
- {'ApplyServerSideEncryptionByDefault': {'SSEAlgorithm': 'AES256'}}
- ]
- }
-}
-
-minio.put_bucket_encryption("my-bucketname", config)
+minio.set_bucket_encryption(
+ "my-bucketname", SSEConfig(Rule.new_sse_s3_rule()),
+)
```
diff --git a/examples/remove_bucket_encryption.py b/examples/delete_bucket_encryption.py
similarity index 68%
rename from examples/remove_bucket_encryption.py
rename to examples/delete_bucket_encryption.py
index b61860229..97429b87a 100644
--- a/examples/remove_bucket_encryption.py
+++ b/examples/delete_bucket_encryption.py
@@ -18,15 +18,11 @@
# dummy values, please replace them with original values.
from minio import Minio
-from minio.error import ResponseError
-client = Minio('s3.amazonaws.com',
- access_key='YOUR-ACCESSKEYID',
- secret_key='YOUR-SECRETACCESSKEY',
- secure=True)
+client = Minio(
+ "play.min.io",
+ access_key="Q3AM3UQ867SPQQA43P2F",
+ secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
+)
-try:
- # Delete default encryption configuration on bucket 'my-bucketname'.
- client.delete_bucket_encryption('my-bucketname')
-except ResponseError as err:
- print(err)
+client.delete_bucket_encryption("my-bucketname")
diff --git a/examples/get_bucket_encryption.py b/examples/get_bucket_encryption.py
index 78377a5f4..ff502c354 100644
--- a/examples/get_bucket_encryption.py
+++ b/examples/get_bucket_encryption.py
@@ -18,15 +18,11 @@
# dummy values, please replace them with original values.
from minio import Minio
-from minio.error import ResponseError
-client = Minio('s3.amazonaws.com',
- access_key='YOUR-ACCESSKEYID',
- secret_key='YOUR-SECRETACCESSKEY',
- secure=True)
+client = Minio(
+ "play.min.io",
+ access_key="Q3AM3UQ867SPQQA43P2F",
+ secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
+)
-try:
- # Get current policy of bucket 'my-bucketname'.
- print(client.get_bucket_encryption('my-bucketname'))
-except ResponseError as err:
- print(err)
+config = client.get_bucket_encryption("my-bucketname")
diff --git a/examples/set_bucket_encryption.py b/examples/set_bucket_encryption.py
index daad2a9ab..58eb1bedf 100644
--- a/examples/set_bucket_encryption.py
+++ b/examples/set_bucket_encryption.py
@@ -18,27 +18,14 @@
# dummy values, please replace them with original values.
from minio import Minio
-from minio.error import ResponseError
+from minio.sseconfig import Rule, SSEConfig
-client = Minio('s3.amazonaws.com',
- access_key='YOUR-ACCESSKEYID',
- secret_key='YOUR-SECRETACCESSKEY',
- secure=True)
+client = Minio(
+ "play.min.io",
+ access_key="Q3AM3UQ867SPQQA43P2F",
+ secret_key="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG",
+)
-try:
- # Set default encryption configuration for bucket 'my-bucketname'
- ENC_CONFIG = {
- 'ServerSideEncryptionConfiguration': {
- 'Rule': [
- {
- 'ApplyServerSideEncryptionByDefault': {
- 'SSEAlgorithm': 'AES256'
- }
- }
- ]
- }
- }
-
- client.put_bucket_encryption('my-bucketname', ENC_CONFIG)
-except ResponseError as err:
- print(err)
+client.set_bucket_encryption(
+ "my-bucketname", SSEConfig(Rule.new_sse_s3_rule()),
+)
diff --git a/minio/api.py b/minio/api.py
index 13a39ce91..f95e9dd14 100644
--- a/minio/api.py
+++ b/minio/api.py
@@ -65,13 +65,12 @@
from .signer import (AMZ_DATE_FORMAT, SIGN_V4_ALGORITHM, get_credential_string,
post_presign_v4, presign_v4, sign_v4_s3)
from .sse import SseCustomerKey
+from .sseconfig import SSEConfig
from .thread_pool import ThreadPool
from .versioningconfig import VersioningConfig
from .xml import Element, SubElement, marshal, unmarshal
from .xml_marshal import (marshal_complete_multipart,
- xml_marshal_bucket_encryption,
- xml_marshal_delete_objects, xml_marshal_select,
- xml_to_dict)
+ xml_marshal_delete_objects, xml_marshal_select)
try:
from json.decoder import JSONDecodeError
@@ -760,22 +759,22 @@ def delete_bucket_notification(self, bucket_name):
"""
self.set_bucket_notification(bucket_name, NotificationConfig())
- def put_bucket_encryption(self, bucket_name, enc_config):
+ def set_bucket_encryption(self, bucket_name, config):
"""
Set encryption configuration of a bucket.
:param bucket_name: Name of the bucket.
- :param enc_config: Encryption configuration as dictionary to be set.
+ :param config: :class:`SSEConfig ` object.
Example::
- minio.put_bucket_encryption("my-bucketname", config)
+ minio.set_bucket_encryption(
+ "my-bucketname", SSEConfig(Rule.new_sse_s3_rule()),
+ )
"""
check_bucket_name(bucket_name)
-
- # 'Rule' is a list, so we need to go through each one of
- # its key/value pair and collect the encryption values.
- rules = enc_config['ServerSideEncryptionConfiguration']['Rule']
- body = xml_marshal_bucket_encryption(rules)
+ if not isinstance(config, SSEConfig):
+ raise ValueError("config must be SSEConfig type")
+ body = marshal(config)
self._execute(
"PUT",
bucket_name,
@@ -789,18 +788,23 @@ def get_bucket_encryption(self, bucket_name):
Get encryption configuration of a bucket.
:param bucket_name: Name of the bucket.
- :return: Encryption configuration.
+ :return: :class:`SSEConfig ` object.
Example::
config = minio.get_bucket_encryption("my-bucketname")
"""
check_bucket_name(bucket_name)
- response = self._execute(
- "GET",
- bucket_name,
- query_params={"encryption": ""},
- )
- return xml_to_dict(response.data.decode())
+ try:
+ response = self._execute(
+ "GET",
+ bucket_name,
+ query_params={"encryption": ""},
+ )
+ return unmarshal(SSEConfig, response.data.decode())
+ except S3Error as exc:
+ if exc.code != "ServerSideEncryptionConfigurationNotFoundError":
+ raise
+ return None
def delete_bucket_encryption(self, bucket_name):
"""
@@ -812,11 +816,15 @@ def delete_bucket_encryption(self, bucket_name):
minio.delete_bucket_encryption("my-bucketname")
"""
check_bucket_name(bucket_name)
- self._execute(
- "DELETE",
- bucket_name,
- query_params={"encryption": ""},
- )
+ try:
+ self._execute(
+ "DELETE",
+ bucket_name,
+ query_params={"encryption": ""},
+ )
+ except S3Error as exc:
+ if exc.code != "ServerSideEncryptionConfigurationNotFoundError":
+ raise
def listen_bucket_notification(self, bucket_name, prefix='', suffix='',
events=('s3:ObjectCreated:*',
diff --git a/minio/sseconfig.py b/minio/sseconfig.py
new file mode 100644
index 000000000..b06fffd59
--- /dev/null
+++ b/minio/sseconfig.py
@@ -0,0 +1,98 @@
+# -*- coding: utf-8 -*-
+# MinIO Python Library for Amazon S3 Compatible Cloud Storage, (C)
+# 2020 MinIO, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Request/response of PutBucketEncryption and GetBucketEncryption APIs."""
+
+from __future__ import absolute_import
+
+from abc import ABCMeta
+
+from .xml import Element, SubElement, find, findtext
+
+AES256 = "AES256"
+AWS_KMS = "aws:kms"
+
+
+class Rule:
+ """Server-side encryption rule. """
+ __metaclass__ = ABCMeta
+
+ def __init__(self, sse_algorithm, kms_master_key_id=None):
+ self._sse_algorithm = sse_algorithm
+ self._kms_master_key_id = kms_master_key_id
+
+ @property
+ def sse_algorithm(self):
+ """Get SSE algorithm."""
+ return self._sse_algorithm
+
+ @property
+ def kms_master_key_id(self):
+ """Get KMS master key ID."""
+ return self._kms_master_key_id
+
+ @classmethod
+ def new_sse_s3_rule(cls):
+ """Create SSE-S3 rule."""
+ return cls(AES256)
+
+ @classmethod
+ def new_sse_kms_rule(cls, kms_master_key_id=None):
+ """Create new SSE-KMS rule."""
+ return cls(AWS_KMS, kms_master_key_id)
+
+ @classmethod
+ def fromxml(cls, element):
+ """Create new object with values from XML element."""
+ element = find(element, "ApplyServerSideEncryptionByDefault")
+ sse_algorithm = findtext(element, "SSEAlgorithm", True)
+ kms_master_key_id = findtext(element, "KMSMasterKeyID")
+ return cls(sse_algorithm, kms_master_key_id)
+
+ def toxml(self, element):
+ """Convert to XML."""
+ element = SubElement(element, "Rule")
+ tag = SubElement(element, "ApplyServerSideEncryptionByDefault")
+ SubElement(tag, "SSEAlgorithm", self._sse_algorithm)
+ if self._kms_master_key_id is not None:
+ SubElement(tag, "KMSMasterKeyID", self._kms_master_key_id)
+ return element
+
+
+class SSEConfig:
+ """server-side encyption configuration."""
+
+ def __init__(self, rule):
+ if not rule:
+ raise ValueError("rule must be provided")
+ self._rule = rule
+
+ @property
+ def rule(self):
+ """Get rule."""
+ return self._rule
+
+ @classmethod
+ def fromxml(cls, element):
+ """Create new object with values from XML element."""
+ element = find(element, "Rule")
+ return cls(Rule.fromxml(element))
+
+ def toxml(self, element):
+ """Convert to XML."""
+ element = Element("ServerSideEncryptionConfiguration")
+ self._rule.toxml(element)
+ return element
diff --git a/minio/xml_marshal.py b/minio/xml_marshal.py
index 12ac893c3..a5e6075d0 100644
--- a/minio/xml_marshal.py
+++ b/minio/xml_marshal.py
@@ -90,27 +90,6 @@ def xml_to_dict(in_xml):
return _etree_to_dict(elem)
-def xml_marshal_bucket_encryption(rules):
- """Encode bucket encryption to XML."""
-
- root = Element('ServerSideEncryptionConfiguration')
-
- if rules:
- # As server supports only one rule, the first rule is taken due to
- # no validation is done at server side.
- apply_element = SubElement(SubElement(root, 'Rule'),
- 'ApplyServerSideEncryptionByDefault')
- SubElement(apply_element, 'SSEAlgorithm',
- rules[0]['ApplyServerSideEncryptionByDefault'].get(
- 'SSEAlgorithm', 'AES256'))
- kms_text = rules[0]['ApplyServerSideEncryptionByDefault'].get(
- 'KMSMasterKeyID')
- if kms_text:
- SubElement(apply_element, 'KMSMasterKeyID', kms_text)
-
- return _get_xml_data(root)
-
-
def xml_marshal_select(req):
"""Encode select request to XML."""
diff --git a/tests/unit/sseconfig.py b/tests/unit/sseconfig.py
new file mode 100644
index 000000000..eabcd4ab2
--- /dev/null
+++ b/tests/unit/sseconfig.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+# MinIO Python Library for Amazon S3 Compatible Cloud Storage,
+# (C) 2020 MinIO, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from unittest import TestCase
+
+from nose.tools import eq_
+
+from minio import xml
+from minio.sseconfig import AWS_KMS, Rule, SSEConfig
+
+
+class ReplicationConfigTest(TestCase):
+ def test_config(self):
+ config = SSEConfig(Rule.new_sse_s3_rule())
+ xml.marshal(config)
+
+ config = xml.unmarshal(
+ SSEConfig,
+ """
+
+
+ aws:kms
+ arn:aws:kms:us-east-1:1234/5678example
+
+
+
+ """,
+ )
+ xml.marshal(config)
+ eq_(config.rule().sse_algorithm(), AWS_KMS)
+ eq_(
+ config.rule().kms_master_key_id(),
+ "arn:aws:kms:us-east-1:1234/5678example",
+ )