carols10cents commented on code in PR #4876:
URL: https://github.com/apache/arrow-rs/pull/4876#discussion_r1342780895


##########
object_store/src/aws/credential.rs:
##########
@@ -154,21 +155,140 @@ impl<'a> AwsAuthorizer<'a> {
         let header_digest = HeaderValue::from_str(&digest).unwrap();
         request.headers_mut().insert(HASH_HEADER, header_digest);
 
-        // Each path segment must be URI-encoded twice (except for Amazon S3 
which only gets URI-encoded once).
+        let (signed_headers, canonical_headers) = 
canonicalize_headers(request.headers());
+
+        let scope = self.scope(date);
+
+        let string_to_sign = self.string_to_sign(
+            date,
+            &scope,
+            request.method(),
+            request.url(),
+            &canonical_headers,
+            &signed_headers,
+            &digest,
+        );
+
+        // sign the string
+        let signature =
+            self.credential
+                .sign(&string_to_sign, date, self.region, self.service);
+
+        // build the actual auth header
+        let authorisation = format!(
+            "{} Credential={}/{}, SignedHeaders={}, Signature={}",
+            ALGORITHM, self.credential.key_id, scope, signed_headers, signature
+        );
+
+        let authorization_val = HeaderValue::from_str(&authorisation).unwrap();
+        request.headers_mut().insert(AUTH_HEADER, authorization_val);
+    }
+
+    /// Authorize a request via `method` to `url` valid for the duration 
specified in `expires_in`
+    /// by attaching the relevant [AWS SigV4] query parameters.
+    ///
+    /// [AWS SigV4]: 
https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html
+    ///
+    /// # Example
+    ///
+    /// This example modifies `url` to add the signing parameters needed to 
enable a user to upload
+    /// a file to "some-folder/some-file.txt" in the next hour.
+    ///
+    /// ```
+    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
+    /// use object_store::{aws::{AmazonS3Builder, AwsAuthorizer}, path::Path};
+    /// use reqwest::Method;
+    /// use std::time::Duration;
+    /// use url::Url;
+    ///
+    /// let region = "us-east-1";
+    /// let s3 = AmazonS3Builder::new()
+    ///     .with_region(region)
+    ///     .with_bucket_name("my-bucket")
+    ///     .with_access_key_id("my-access-key-id")
+    ///     .with_secret_access_key("my-secret-access-key")
+    ///     .build()?;
+    /// let credential = s3
+    ///     .credentials()
+    ///     .get_credential()
+    ///     .await?;
+    /// let authorizer = AwsAuthorizer::new(&credential, "s3", region);
+    /// let mut url = 
Url::parse(&s3.path_url(&Path::from("some-folder/some-file.txt")))?;
+    /// authorizer.sign(Method::PUT, &mut url, Duration::from_secs(60 * 60));
+    /// #     Ok(())
+    /// # }
+    /// ```
+    pub fn sign(&self, method: Method, url: &mut Url, expires_in: Duration) {
+        let date = self.date.unwrap_or_else(Utc::now);
+        let scope = self.scope(date);
+
+        // 
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
+        url.query_pairs_mut()
+            .append_pair("X-Amz-Algorithm", ALGORITHM)
+            .append_pair(
+                "X-Amz-Credential",
+                &format!("{}/{}", self.credential.key_id, scope),
+            )
+            .append_pair("X-Amz-Date", 
&date.format("%Y%m%dT%H%M%SZ").to_string())
+            .append_pair("X-Amz-Expires", &expires_in.as_secs().to_string())
+            .append_pair("X-Amz-SignedHeaders", "host");
+
+        // TODO: For S3, you must include the X-Amz-Security-Token query 
parameter in the URL if

Review Comment:
   and done ✅ 



##########
object_store/src/aws/credential.rs:
##########
@@ -154,21 +155,140 @@ impl<'a> AwsAuthorizer<'a> {
         let header_digest = HeaderValue::from_str(&digest).unwrap();
         request.headers_mut().insert(HASH_HEADER, header_digest);
 
-        // Each path segment must be URI-encoded twice (except for Amazon S3 
which only gets URI-encoded once).
+        let (signed_headers, canonical_headers) = 
canonicalize_headers(request.headers());
+
+        let scope = self.scope(date);
+
+        let string_to_sign = self.string_to_sign(
+            date,
+            &scope,
+            request.method(),
+            request.url(),
+            &canonical_headers,
+            &signed_headers,
+            &digest,
+        );
+
+        // sign the string
+        let signature =
+            self.credential
+                .sign(&string_to_sign, date, self.region, self.service);
+
+        // build the actual auth header
+        let authorisation = format!(
+            "{} Credential={}/{}, SignedHeaders={}, Signature={}",
+            ALGORITHM, self.credential.key_id, scope, signed_headers, signature
+        );
+
+        let authorization_val = HeaderValue::from_str(&authorisation).unwrap();
+        request.headers_mut().insert(AUTH_HEADER, authorization_val);
+    }
+
+    /// Authorize a request via `method` to `url` valid for the duration 
specified in `expires_in`
+    /// by attaching the relevant [AWS SigV4] query parameters.
+    ///
+    /// [AWS SigV4]: 
https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html
+    ///
+    /// # Example
+    ///
+    /// This example modifies `url` to add the signing parameters needed to 
enable a user to upload
+    /// a file to "some-folder/some-file.txt" in the next hour.
+    ///
+    /// ```
+    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
+    /// use object_store::{aws::{AmazonS3Builder, AwsAuthorizer}, path::Path};
+    /// use reqwest::Method;
+    /// use std::time::Duration;
+    /// use url::Url;
+    ///
+    /// let region = "us-east-1";
+    /// let s3 = AmazonS3Builder::new()
+    ///     .with_region(region)
+    ///     .with_bucket_name("my-bucket")
+    ///     .with_access_key_id("my-access-key-id")
+    ///     .with_secret_access_key("my-secret-access-key")
+    ///     .build()?;
+    /// let credential = s3
+    ///     .credentials()
+    ///     .get_credential()
+    ///     .await?;
+    /// let authorizer = AwsAuthorizer::new(&credential, "s3", region);
+    /// let mut url = 
Url::parse(&s3.path_url(&Path::from("some-folder/some-file.txt")))?;
+    /// authorizer.sign(Method::PUT, &mut url, Duration::from_secs(60 * 60));
+    /// #     Ok(())
+    /// # }
+    /// ```
+    pub fn sign(&self, method: Method, url: &mut Url, expires_in: Duration) {
+        let date = self.date.unwrap_or_else(Utc::now);
+        let scope = self.scope(date);
+
+        // 
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
+        url.query_pairs_mut()
+            .append_pair("X-Amz-Algorithm", ALGORITHM)
+            .append_pair(
+                "X-Amz-Credential",
+                &format!("{}/{}", self.credential.key_id, scope),
+            )
+            .append_pair("X-Amz-Date", 
&date.format("%Y%m%dT%H%M%SZ").to_string())
+            .append_pair("X-Amz-Expires", &expires_in.as_secs().to_string())
+            .append_pair("X-Amz-SignedHeaders", "host");
+
+        // TODO: For S3, you must include the X-Amz-Security-Token query 
parameter in the URL if

Review Comment:
   and done ✅ 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to