tustvold commented on code in PR #5259:
URL: https://github.com/apache/arrow-rs/pull/5259#discussion_r1441830118
##########
object_store/src/azure/credential.rs:
##########
@@ -205,6 +286,156 @@ fn add_if_exists<'a>(h: &'a HeaderMap, key: &HeaderName)
-> &'a str {
.unwrap_or_default()
}
+fn string_to_sign_sas(
+ u: &Url,
+ method: &Method,
+ account: &str,
+ start: &DateTime<Utc>,
+ end: &DateTime<Utc>,
+) -> (String, String, String, String, String) {
+ let signed_resource = if u
+ .query()
+ .map(|q| q.contains("comp=list"))
Review Comment:
I think lets not support lists for now, we can always add it back later. I'm
just thinking about some silliness where a query parameter happens to match
this and we do something unintentional
##########
object_store/src/azure/client.rs:
##########
@@ -324,6 +337,74 @@ impl AzureClient {
Ok(())
}
+ /// Make a Get User Delegation Key request
+ ///
<https://docs.microsoft.com/en-us/rest/api/storageservices/get-user-delegation-key>
+ async fn get_user_delegation_key(
+ &self,
+ start: &DateTime<Utc>,
+ end: &DateTime<Utc>,
+ ) -> Result<UserDelegationKey> {
+ let credential = self.get_credential().await?;
+ let url = self.config.service.clone();
+
+ let start = start.to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
+ let expiry = end.to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
+
+ let mut body = String::new();
+ body.push_str("<?xml version=\"1.0\"
encoding=\"utf-8\"?>\n<KeyInfo>\n");
+ body.push_str(&format!(
+ "\t<Start>{start}</Start>\n\t<Expiry>{expiry}</Expiry>\n"
+ ));
+ body.push_str("</KeyInfo>");
+
+ let response = self
+ .client
+ .request(Method::POST, url)
+ .body(body)
+ .query(&[("restype", "service"), ("comp", "userdelegationkey")])
+ .with_azure_authorization(&credential, &self.config.account)
+ .send_retry(&self.config.retry_config)
+ .await
+ .context(DelegationKeyRequestSnafu)?
+ .bytes()
+ .await
+ .context(DelegationKeyResponseBodySnafu)?;
+
+ let response: UserDelegationKey =
+
quick_xml::de::from_reader(response.reader()).context(DelegationKeyResponseSnafu)?;
+
+ Ok(response)
+ }
+
+ pub async fn signer(&self, expires_in: Duration) -> Result<AzureSigner> {
Review Comment:
This could do with a doc comment explaining what it is/does
##########
object_store/src/signer.rs:
##########
@@ -30,5 +30,21 @@ pub trait Signer: Send + Sync + fmt::Debug + 'static {
/// the URL should be valid, return a signed [`Url`] created with the
object store
/// implementation's credentials such that the URL can be handed to
something that doesn't have
/// access to the object store's credentials, to allow limited access to
the object store.
- async fn signed_url(&self, method: Method, path: &Path, expires_in:
Duration) -> Result<Url>;
+ async fn signed_url(&self, method: &Method, path: &Path, expires_in:
Duration) -> Result<Url>;
+
+ /// Generate signed urls for multiple paths.
+ ///
+ /// See [`Signer::signed_url`] for more details.
+ async fn signed_urls(
+ &self,
+ method: &Method,
+ paths: &[Path],
+ expires_in: Duration,
+ ) -> Result<Vec<Url>> {
+ let mut urls = Vec::with_capacity(paths.len());
+ for path in paths {
+ urls.push(self.signed_url(method, path, expires_in).await?);
+ }
+ Ok(urls)
+ }
Review Comment:
I think providing a type-erased way to sign multiple URLs makes sense to me
:+1:
--
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]