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}