This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new d9eba0ad feat(services/oss): Add server side encryption support for 
oss (#2092)
d9eba0ad is described below

commit d9eba0ad866cdaa945fb16b43682b787836b4b12
Author: leenstx <[email protected]>
AuthorDate: Mon Apr 24 21:55:38 2023 +0800

    feat(services/oss): Add server side encryption support for oss (#2092)
    
    * Add server side encryption support for oss #1981
    
    * Add server side encryption support for oss #1981
    
    add doc
---
 core/src/services/oss/backend.rs | 62 +++++++++++++++++++++++++++++++++++++++-
 core/src/services/oss/core.rs    | 48 +++++++++++++++++++++++++++++--
 2 files changed, 106 insertions(+), 4 deletions(-)

diff --git a/core/src/services/oss/backend.rs b/core/src/services/oss/backend.rs
index 8748c7dd..f6e21394 100644
--- a/core/src/services/oss/backend.rs
+++ b/core/src/services/oss/backend.rs
@@ -114,6 +114,10 @@ pub struct OssBuilder {
     presign_endpoint: Option<String>,
     bucket: String,
 
+    // sse options
+    server_side_encryption: Option<String>,
+    server_side_encryption_key_id: Option<String>,
+
     // authenticate options
     access_key_id: Option<String>,
     access_key_secret: Option<String>,
@@ -253,6 +257,41 @@ impl OssBuilder {
         };
         Ok((endpoint, host))
     }
+
+    /// Set server_side_encryption for this backend.
+    ///
+    /// Available values: `AES256`, `KMS`.
+    ///
+    /// Reference: 
<https://www.alibabacloud.com/help/en/object-storage-service/latest/server-side-encryption-5>
+    /// Brief explanation:
+    /// There are two server-side encryption methods available:
+    /// SSE-AES256:
+    ///     1. Configure the bucket encryption mode as OSS-managed and specify 
the encryption algorithm as AES256.
+    ///     2. Include the `x-oss-server-side-encryption` parameter in the 
request and set its value to AES256.
+    /// SSE-KMS:
+    ///     1. To use this service, you need to first enable KMS.
+    ///     2. Configure the bucket encryption mode as KMS, and specify the 
specific CMK ID for BYOK (Bring Your Own Key)
+    ///        or not specify the specific CMK ID for OSS-managed KMS key.
+    ///     3. Include the `x-oss-server-side-encryption` parameter in the 
request and set its value to KMS.
+    ///     4. If a specific CMK ID is specified, include the 
`x-oss-server-side-encryption-key-id` parameter in the request, and set its 
value to the specified CMK ID.
+    pub fn server_side_encryption(&mut self, v: &str) -> &mut Self {
+        if !v.is_empty() {
+            self.server_side_encryption = Some(v.to_string())
+        }
+        self
+    }
+
+    /// Set server_side_encryption_key_id for this backend.
+    ///
+    /// # Notes
+    ///
+    /// This option only takes effect when server_side_encryption equals to 
KMS.
+    pub fn server_side_encryption_key_id(&mut self, v: &str) -> &mut Self {
+        if !v.is_empty() {
+            self.server_side_encryption_key_id = Some(v.to_string())
+        }
+        self
+    }
 }
 
 impl Builder for OssBuilder {
@@ -270,7 +309,10 @@ impl Builder for OssBuilder {
         map.get("access_key_id").map(|v| builder.access_key_id(v));
         map.get("access_key_secret")
             .map(|v| builder.access_key_secret(v));
-
+        map.get("server_side_encryption")
+            .map(|v| builder.server_side_encryption(v));
+        map.get("server_side_encryption_key_id")
+            .map(|v| builder.server_side_encryption_key_id(v));
         builder
     }
 
@@ -310,6 +352,22 @@ impl Builder for OssBuilder {
         };
         debug!("backend use presign_endpoint: {}", &presign_endpoint);
 
+        let server_side_encryption = match &self.server_side_encryption {
+            None => None,
+            Some(v) => Some(
+                build_header_value(v)
+                    .map_err(|err| err.with_context("key", 
"server_side_encryption"))?,
+            ),
+        };
+
+        let server_side_encryption_key_id = match 
&self.server_side_encryption_key_id {
+            None => None,
+            Some(v) => Some(
+                build_header_value(v)
+                    .map_err(|err| err.with_context("key", 
"server_side_encryption_key_id"))?,
+            ),
+        };
+
         let mut cfg = AliyunConfig::default();
         // Load cfg from env first.
         cfg = cfg.from_env();
@@ -338,6 +396,8 @@ impl Builder for OssBuilder {
                 signer,
                 loader,
                 client,
+                server_side_encryption,
+                server_side_encryption_key_id,
             }),
         })
     }
diff --git a/core/src/services/oss/core.rs b/core/src/services/oss/core.rs
index 1129f72e..8a4670e7 100644
--- a/core/src/services/oss/core.rs
+++ b/core/src/services/oss/core.rs
@@ -27,6 +27,8 @@ use http::header::CONTENT_TYPE;
 use http::header::IF_MATCH;
 use http::header::IF_NONE_MATCH;
 use http::header::RANGE;
+use http::HeaderName;
+use http::HeaderValue;
 use http::Request;
 use http::Response;
 use reqsign::AliyunCredential;
@@ -40,6 +42,10 @@ use crate::raw::*;
 use crate::*;
 
 mod constants {
+    pub const X_OSS_SERVER_SIDE_ENCRYPTION: &str = 
"x-oss-server-side-encryption";
+
+    pub const X_OSS_SERVER_SIDE_ENCRYPTION_KEY_ID: &str = 
"x-oss-server-side-encryption-key-id";
+
     pub const RESPONSE_CONTENT_DISPOSITION: &str = 
"response-content-disposition";
 }
 
@@ -53,6 +59,9 @@ pub struct OssCore {
     pub endpoint: String,
     pub presign_endpoint: String,
 
+    pub server_side_encryption: Option<HeaderValue>,
+    pub server_side_encryption_key_id: Option<HeaderValue>,
+
     pub client: HttpClient,
     pub loader: AliyunLoader,
     pub signer: AliyunOssSigner,
@@ -110,6 +119,31 @@ impl OssCore {
     pub async fn send(&self, req: Request<AsyncBody>) -> 
Result<Response<IncomingAsyncBody>> {
         self.client.send(req).await
     }
+
+    /// Set sse headers
+    /// # Note
+    /// According to the OSS documentation, only PutObject, CopyObject, and 
InitiateMultipartUpload may require to be set.
+    pub fn insert_sse_headers(&self, mut req: http::request::Builder) -> 
http::request::Builder {
+        if let Some(v) = &self.server_side_encryption {
+            let mut v = v.clone();
+            v.set_sensitive(true);
+
+            req = req.header(
+                
HeaderName::from_static(constants::X_OSS_SERVER_SIDE_ENCRYPTION),
+                v,
+            )
+        }
+        if let Some(v) = &self.server_side_encryption_key_id {
+            let mut v = v.clone();
+            v.set_sensitive(true);
+
+            req = req.header(
+                
HeaderName::from_static(constants::X_OSS_SERVER_SIDE_ENCRYPTION_KEY_ID),
+                v,
+            )
+        }
+        req
+    }
 }
 
 impl OssCore {
@@ -144,6 +178,9 @@ impl OssCore {
             req = req.header(CACHE_CONTROL, cache_control)
         }
 
+        // set sse headers
+        req = self.insert_sse_headers(req);
+
         let req = req.body(body).map_err(new_request_build_error)?;
         Ok(req)
     }
@@ -333,8 +370,13 @@ impl OssCore {
         );
         let source = format!("/{}/{}", self.bucket, 
percent_encode_path(&source));
 
-        let mut req = Request::put(&url)
-            .header("x-oss-copy-source", source)
+        let mut req = Request::put(&url);
+
+        req = self.insert_sse_headers(req);
+
+        req = req.header("x-oss-copy-source", source);
+
+        let mut req = req
             .body(AsyncBody::Empty)
             .map_err(new_request_build_error)?;
 
@@ -438,7 +480,7 @@ impl OssCore {
         if let Some(cache_control) = cache_control {
             req = req.header(CACHE_CONTROL, cache_control);
         }
-
+        req = self.insert_sse_headers(req);
         let mut req = req.body(body).map_err(new_request_build_error)?;
         self.sign(&mut req).await?;
         Ok(req)

Reply via email to