Skip to main content

cloud_storage_rs/resources/
object_access_control.rs

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