mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-08-31 17:28:13 +00:00
Merge pull request 'api: s3: implement get bucket acl' (#1045) from ragazenta/garage:feat/dummy-acl into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1045
This commit is contained in:
@@ -226,6 +226,7 @@ impl ApiHandler for S3ApiServer {
|
|||||||
Endpoint::DeleteBucket {} => handle_delete_bucket(ctx).await,
|
Endpoint::DeleteBucket {} => handle_delete_bucket(ctx).await,
|
||||||
Endpoint::GetBucketLocation {} => handle_get_bucket_location(ctx),
|
Endpoint::GetBucketLocation {} => handle_get_bucket_location(ctx),
|
||||||
Endpoint::GetBucketVersioning {} => handle_get_bucket_versioning(),
|
Endpoint::GetBucketVersioning {} => handle_get_bucket_versioning(),
|
||||||
|
Endpoint::GetBucketAcl {} => handle_get_bucket_acl(ctx),
|
||||||
Endpoint::ListObjects {
|
Endpoint::ListObjects {
|
||||||
delimiter,
|
delimiter,
|
||||||
encoding_type,
|
encoding_type,
|
||||||
|
|||||||
+59
-1
@@ -5,7 +5,7 @@ use hyper::{Request, Response, StatusCode};
|
|||||||
use garage_model::bucket_alias_table::*;
|
use garage_model::bucket_alias_table::*;
|
||||||
use garage_model::bucket_table::Bucket;
|
use garage_model::bucket_table::Bucket;
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
use garage_model::key_table::Key;
|
use garage_model::key_table::{Key, KeyParams};
|
||||||
use garage_model::permission::BucketKeyPerm;
|
use garage_model::permission::BucketKeyPerm;
|
||||||
use garage_table::util::*;
|
use garage_table::util::*;
|
||||||
use garage_util::crdt::*;
|
use garage_util::crdt::*;
|
||||||
@@ -44,6 +44,55 @@ pub fn handle_get_bucket_versioning() -> Result<Response<ResBody>, Error> {
|
|||||||
.body(string_body(xml))?)
|
.body(string_body(xml))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_get_bucket_acl(ctx: ReqCtx) -> Result<Response<ResBody>, Error> {
|
||||||
|
let ReqCtx {
|
||||||
|
bucket_id, api_key, ..
|
||||||
|
} = ctx;
|
||||||
|
let key_p = api_key.params().ok_or_internal_error(
|
||||||
|
"Key should not be in deleted state at this point (in handle_get_bucket_acl)",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut grants: Vec<s3_xml::Grant> = vec![];
|
||||||
|
let kp = api_key.bucket_permissions(&bucket_id);
|
||||||
|
|
||||||
|
if kp.allow_owner {
|
||||||
|
grants.push(s3_xml::Grant {
|
||||||
|
grantee: create_grantee(&key_p, &api_key),
|
||||||
|
permission: s3_xml::Value("FULL_CONTROL".to_string()),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if kp.allow_read {
|
||||||
|
grants.push(s3_xml::Grant {
|
||||||
|
grantee: create_grantee(&key_p, &api_key),
|
||||||
|
permission: s3_xml::Value("READ".to_string()),
|
||||||
|
});
|
||||||
|
grants.push(s3_xml::Grant {
|
||||||
|
grantee: create_grantee(&key_p, &api_key),
|
||||||
|
permission: s3_xml::Value("READ_ACP".to_string()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if kp.allow_write {
|
||||||
|
grants.push(s3_xml::Grant {
|
||||||
|
grantee: create_grantee(&key_p, &api_key),
|
||||||
|
permission: s3_xml::Value("WRITE".to_string()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let access_control_policy = s3_xml::AccessControlPolicy {
|
||||||
|
xmlns: (),
|
||||||
|
owner: None,
|
||||||
|
acl: s3_xml::AccessControlList { entries: grants },
|
||||||
|
};
|
||||||
|
|
||||||
|
let xml = s3_xml::to_xml_with_header(&access_control_policy)?;
|
||||||
|
trace!("xml: {}", xml);
|
||||||
|
|
||||||
|
Ok(Response::builder()
|
||||||
|
.header("Content-Type", "application/xml")
|
||||||
|
.body(string_body(xml))?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_list_buckets(
|
pub async fn handle_list_buckets(
|
||||||
garage: &Garage,
|
garage: &Garage,
|
||||||
api_key: &Key,
|
api_key: &Key,
|
||||||
@@ -311,6 +360,15 @@ fn parse_create_bucket_xml(xml_bytes: &[u8]) -> Option<Option<String>> {
|
|||||||
Some(ret)
|
Some(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_grantee(key_params: &KeyParams, api_key: &Key) -> s3_xml::Grantee {
|
||||||
|
s3_xml::Grantee {
|
||||||
|
xmlns_xsi: (),
|
||||||
|
typ: "CanonicalUser".to_string(),
|
||||||
|
display_name: Some(s3_xml::Value(key_params.name.get().to_string())),
|
||||||
|
id: Some(s3_xml::Value(api_key.key_id.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ pub fn xmlns_tag<S: Serializer>(_v: &(), s: S) -> Result<S::Ok, S::Error> {
|
|||||||
s.serialize_str("http://s3.amazonaws.com/doc/2006-03-01/")
|
s.serialize_str("http://s3.amazonaws.com/doc/2006-03-01/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn xmlns_xsi_tag<S: Serializer>(_v: &(), s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
s.serialize_str("http://www.w3.org/2001/XMLSchema-instance")
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Value(#[serde(rename = "$value")] pub String);
|
pub struct Value(#[serde(rename = "$value")] pub String);
|
||||||
|
|
||||||
@@ -319,6 +323,42 @@ pub struct PostObject {
|
|||||||
pub etag: Value,
|
pub etag: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct Grantee {
|
||||||
|
#[serde(rename = "xmlns:xsi", serialize_with = "xmlns_xsi_tag")]
|
||||||
|
pub xmlns_xsi: (),
|
||||||
|
#[serde(rename = "xsi:type")]
|
||||||
|
pub typ: String,
|
||||||
|
#[serde(rename = "DisplayName")]
|
||||||
|
pub display_name: Option<Value>,
|
||||||
|
#[serde(rename = "ID")]
|
||||||
|
pub id: Option<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct Grant {
|
||||||
|
#[serde(rename = "Grantee")]
|
||||||
|
pub grantee: Grantee,
|
||||||
|
#[serde(rename = "Permission")]
|
||||||
|
pub permission: Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct AccessControlList {
|
||||||
|
#[serde(rename = "Grant")]
|
||||||
|
pub entries: Vec<Grant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct AccessControlPolicy {
|
||||||
|
#[serde(serialize_with = "xmlns_tag")]
|
||||||
|
pub xmlns: (),
|
||||||
|
#[serde(rename = "Owner")]
|
||||||
|
pub owner: Option<Owner>,
|
||||||
|
#[serde(rename = "AccessControlList")]
|
||||||
|
pub acl: AccessControlList,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -427,6 +467,43 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_bucket_acl_result() -> Result<(), ApiError> {
|
||||||
|
let grant = Grant {
|
||||||
|
grantee: Grantee {
|
||||||
|
xmlns_xsi: (),
|
||||||
|
typ: "CanonicalUser".to_string(),
|
||||||
|
display_name: Some(Value("owner_name".to_string())),
|
||||||
|
id: Some(Value("qsdfjklm".to_string())),
|
||||||
|
},
|
||||||
|
permission: Value("FULL_CONTROL".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let get_bucket_acl = AccessControlPolicy {
|
||||||
|
xmlns: (),
|
||||||
|
owner: None,
|
||||||
|
acl: AccessControlList {
|
||||||
|
entries: vec![grant],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
to_xml_with_header(&get_bucket_acl)?,
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
|
||||||
|
<AccessControlPolicy xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\
|
||||||
|
<AccessControlList>\
|
||||||
|
<Grant>\
|
||||||
|
<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\">\
|
||||||
|
<DisplayName>owner_name</DisplayName>\
|
||||||
|
<ID>qsdfjklm</ID>\
|
||||||
|
</Grantee>\
|
||||||
|
<Permission>FULL_CONTROL</Permission>\
|
||||||
|
</Grant>\
|
||||||
|
</AccessControlList>\
|
||||||
|
</AccessControlPolicy>"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delete_result() -> Result<(), ApiError> {
|
fn delete_result() -> Result<(), ApiError> {
|
||||||
let delete_result = DeleteResult {
|
let delete_result = DeleteResult {
|
||||||
|
|||||||
Reference in New Issue
Block a user