cloud_storage_rs/resources/bucket_access_control.rs
1use crate::error::GoogleResponse;
2use crate::resources::common::ListResponse;
3pub use crate::resources::common::{Entity, ProjectTeam, Role};
4
5/// The BucketAccessControl resource represents the Access Control Lists (ACLs) for buckets within
6/// Google Cloud Storage. ACLs let you specify who has access to your data and to what extent.
7///
8/// ```text,ignore
9/// Important: This method fails with a 400 Bad Request response for buckets with uniform
10/// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
11/// control access instead.
12/// ```
13///
14/// There are three roles that can be assigned to an entity:
15///
16/// * READERs can get the bucket, though no acl property will be returned, and list the bucket's
17/// objects.
18/// * WRITERs are READERs, and they can insert objects into the bucket and delete the bucket's
19/// objects.
20/// * OWNERs are WRITERs, and they can get the acl property of a bucket, update a bucket, and call
21/// all BucketAccessControl methods on the bucket.
22#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct BucketAccessControl {
25 /// The kind of item this is. For bucket access control entries, this is always storage#bucketAccessControl.
26 pub kind: String,
27 /// The ID of the access-control entry.
28 pub id: String,
29 /// The link to this access-control entry.
30 pub self_link: String,
31 /// The name of the bucket.
32 pub bucket: String,
33 /// The entity holding the permission, in one of the following forms:
34 ///
35 /// * `user-userId`
36 /// * `user-email`
37 /// * `group-groupId`
38 /// * `group-email`
39 /// * `domain-domain`
40 /// * `project-team-projectId`
41 /// * `allUsers`
42 /// * `allAuthenticatedUsers`
43 ///
44 /// Examples:
45 ///
46 /// * The user liz@example.com would be user-liz@example.com.
47 /// * The group example@googlegroups.com would be group-example@googlegroups.com.
48 /// * To refer to all members of the G Suite for Business domain example.com, the entity would
49 /// be domain-example.com.
50 pub entity: Entity,
51 /// The access permission for the entity.
52 pub role: Role,
53 /// The email address associated with the entity, if any.
54 pub email: Option<String>,
55 /// The ID for the entity, if any.
56 pub entity_id: Option<String>,
57 /// The domain associated with the entity, if any.
58 pub domain: Option<String>,
59 /// The project team associated with the entity, if any.
60 pub project_team: Option<ProjectTeam>,
61 /// HTTP 1.1 Entity tag for the access-control entry.
62 pub etag: String,
63}
64
65/// Model that can be used to create a new BucketAccessControl object.
66#[derive(Debug, PartialEq, serde::Serialize)]
67#[serde(rename_all = "camelCase")]
68pub struct NewBucketAccessControl {
69 /// The entity holding the permission, in one of the following forms:
70 ///
71 /// * `user-userId`
72 /// * `user-email`
73 /// * `group-groupId`
74 /// * `group-email`
75 /// * `domain-domain`
76 /// * `project-team-projectId`
77 /// * `allUsers`
78 /// * `allAuthenticatedUsers`
79 ///
80 /// Examples:
81 ///
82 /// * The user liz@example.com would be user-liz@example.com.
83 /// * The group example@googlegroups.com would be group-example@googlegroups.com.
84 /// * To refer to all members of the G Suite for Business domain example.com, the entity would
85 /// be domain-example.com.
86 pub entity: Entity,
87 /// The access permission for the entity.
88 pub role: Role,
89}
90
91impl BucketAccessControl {
92 /// Create a new `BucketAccessControl` using the provided `NewBucketAccessControl`, related to
93 /// the `Bucket` provided by the `bucket_name` argument.
94 ///
95 /// ### Important
96 /// Important: This method fails with a 400 Bad Request response for buckets with uniform
97 /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
98 /// control access instead.
99 /// ### Example
100 /// ```rust,no_run
101 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
102 /// use cloud_storage::bucket_access_control::{BucketAccessControl, NewBucketAccessControl};
103 /// use cloud_storage::bucket_access_control::{Role, Entity};
104 ///
105 /// let new_bucket_access_control = NewBucketAccessControl {
106 /// entity: Entity::AllUsers,
107 /// role: Role::Reader,
108 /// };
109 /// BucketAccessControl::create("mybucket", &new_bucket_access_control)?;
110 /// # Ok(())
111 /// # }
112 /// ```
113 pub fn create(
114 bucket: &str,
115 new_bucket_access_control: &NewBucketAccessControl,
116 ) -> Result<Self, crate::Error> {
117 let url = format!("{}/b/{}/acl", crate::BASE_URL, bucket);
118 let client = reqwest::blocking::Client::new();
119 let result: GoogleResponse<Self> = client
120 .post(&url)
121 .headers(crate::get_headers()?)
122 .json(new_bucket_access_control)
123 .send()?
124 .json()?;
125 match result {
126 GoogleResponse::Success(s) => Ok(s),
127 GoogleResponse::Error(e) => Err(e.into()),
128 }
129 }
130
131 /// Returns all `BucketAccessControl`s related to this bucket.
132 ///
133 /// ### Important
134 /// Important: This method fails with a 400 Bad Request response for buckets with uniform
135 /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
136 /// control access instead.
137 /// ### Example
138 /// ```rust,no_run
139 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
140 /// use cloud_storage::bucket_access_control::BucketAccessControl;
141 ///
142 /// let acls = BucketAccessControl::list("mybucket")?;
143 /// # Ok(())
144 /// # }
145 /// ```
146 pub fn list(bucket: &str) -> Result<Vec<Self>, crate::Error> {
147 let url = format!("{}/b/{}/acl", crate::BASE_URL, bucket);
148 let client = reqwest::blocking::Client::new();
149 let result: GoogleResponse<ListResponse<Self>> = client
150 .get(&url)
151 .headers(crate::get_headers()?)
152 .send()?
153 .json()?;
154 match result {
155 GoogleResponse::Success(s) => Ok(s.items),
156 GoogleResponse::Error(e) => Err(e.into()),
157 }
158 }
159
160 /// Returns the ACL entry for the specified entity on the specified bucket.
161 ///
162 /// ### Important
163 /// Important: This method fails with a 400 Bad Request response for buckets with uniform
164 /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
165 /// control access instead.
166 /// ### Example
167 /// ```rust,no_run
168 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
169 /// use cloud_storage::bucket_access_control::{BucketAccessControl, Entity};
170 ///
171 /// let controls = BucketAccessControl::read("mybucket", &Entity::AllUsers)?;
172 /// # Ok(())
173 /// # }
174 /// ```
175 pub fn read(bucket: &str, entity: &Entity) -> Result<Self, crate::Error> {
176 let url = format!("{}/b/{}/acl/{}", crate::BASE_URL, bucket, entity);
177 let client = reqwest::blocking::Client::new();
178 let result: GoogleResponse<Self> = client
179 .get(&url)
180 .headers(crate::get_headers()?)
181 .send()?
182 .json()?;
183 match result {
184 GoogleResponse::Success(s) => Ok(s),
185 GoogleResponse::Error(e) => Err(e.into()),
186 }
187 }
188
189 /// Update this `BucketAccessControl`.
190 ///
191 /// ### Important
192 /// Important: This method fails with a 400 Bad Request response for buckets with uniform
193 /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
194 /// control access instead.
195 /// ### Example
196 /// ```rust,no_run
197 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
198 /// use cloud_storage::bucket_access_control::{BucketAccessControl, Entity};
199 ///
200 /// let mut acl = BucketAccessControl::read("mybucket", &Entity::AllUsers)?;
201 /// acl.entity = Entity::AllAuthenticatedUsers;
202 /// # Ok(())
203 /// # }
204 /// ```
205 pub fn update(&self) -> Result<Self, crate::Error> {
206 let url = format!("{}/b/{}/acl/{}", crate::BASE_URL, self.bucket, self.entity);
207 let client = reqwest::blocking::Client::new();
208 let result: GoogleResponse<Self> = client
209 .put(&url)
210 .headers(crate::get_headers()?)
211 .json(self)
212 .send()?
213 .json()?;
214 match result {
215 GoogleResponse::Success(s) => Ok(s),
216 GoogleResponse::Error(e) => Err(e.into()),
217 }
218 }
219
220 /// Permanently deletes the ACL entry for the specified entity on the specified bucket.
221 ///
222 /// ### Important
223 /// Important: This method fails with a 400 Bad Request response for buckets with uniform
224 /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
225 /// control access instead.
226 /// ### Example
227 /// ```rust,no_run
228 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
229 /// use cloud_storage::bucket_access_control::{BucketAccessControl, Entity};
230 ///
231 /// let controls = BucketAccessControl::read("mybucket", &Entity::AllUsers)?;
232 /// controls.delete()?;
233 /// # Ok(())
234 /// # }
235 /// ```
236 pub fn delete(self) -> Result<(), crate::Error> {
237 let url = format!("{}/b/{}/acl/{}", crate::BASE_URL, self.bucket, self.entity);
238 let client = reqwest::blocking::Client::new();
239 let response = client.delete(&url).headers(crate::get_headers()?).send()?;
240 if response.status().is_success() {
241 Ok(())
242 } else {
243 Err(crate::Error::Google(response.json()?))
244 }
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn create() -> Result<(), Box<dyn std::error::Error>> {
254 let bucket = crate::read_test_bucket();
255 let new_bucket_access_control = NewBucketAccessControl {
256 entity: Entity::AllUsers,
257 role: Role::Reader,
258 };
259 BucketAccessControl::create(&bucket.name, &new_bucket_access_control)?;
260 Ok(())
261 }
262
263 #[test]
264 fn list() -> Result<(), Box<dyn std::error::Error>> {
265 let bucket = crate::read_test_bucket();
266 BucketAccessControl::list(&bucket.name)?;
267 Ok(())
268 }
269
270 #[test]
271 fn read() -> Result<(), Box<dyn std::error::Error>> {
272 let bucket = crate::read_test_bucket();
273 BucketAccessControl::read(&bucket.name, &Entity::AllUsers)?;
274 Ok(())
275 }
276
277 #[test]
278 fn update() -> Result<(), Box<dyn std::error::Error>> {
279 // use a seperate bucket to prevent synchronization issues
280 let bucket = crate::create_test_bucket("test-update-bucket-access-controls");
281 let new_bucket_access_control = NewBucketAccessControl {
282 entity: Entity::AllUsers,
283 role: Role::Reader,
284 };
285 BucketAccessControl::create(&bucket.name, &new_bucket_access_control)?;
286 let mut acl = BucketAccessControl::read(&bucket.name, &Entity::AllUsers)?;
287 acl.entity = Entity::AllAuthenticatedUsers;
288 acl.update()?;
289 bucket.delete()?;
290 Ok(())
291 }
292
293 #[test]
294 fn delete() -> Result<(), Box<dyn std::error::Error>> {
295 // use a seperate bucket to prevent synchronization issues
296 let bucket = crate::create_test_bucket("test-delete-bucket-access-controls");
297 let new_bucket_access_control = NewBucketAccessControl {
298 entity: Entity::AllUsers,
299 role: Role::Reader,
300 };
301 BucketAccessControl::create(&bucket.name, &new_bucket_access_control)?;
302 let acl = BucketAccessControl::read(&bucket.name, &Entity::AllUsers)?;
303 acl.delete()?;
304 bucket.delete()?;
305 Ok(())
306 }
307}