1use objectstore_service::id::{ObjectContext, ObjectId};
2use objectstore_service::multipart::{
3 AbortMultipartResponse, CompleteMultipartResponse, CompletedPart, InitiateMultipartResponse,
4 ListPartsResponse, PartNumber, UploadId, UploadPartResponse,
5};
6use objectstore_service::service::{DeleteResponse, GetResponse, InsertResponse, MetadataResponse};
7use objectstore_service::{ClientStream, StorageService};
8use objectstore_types::auth::Permission;
9use objectstore_types::metadata::Metadata;
10use objectstore_types::range::ByteRange;
11
12use crate::auth::{AuthContext, AuthError};
13use crate::endpoints::common::ApiResult;
14
15#[derive(Debug)]
37pub struct AuthAwareService {
38 service: StorageService,
39 context: Option<AuthContext>,
40 enforce: bool,
41}
42
43impl AuthAwareService {
44 pub fn new(
53 service: StorageService,
54 context: Option<AuthContext>,
55 enforce: bool,
56 ) -> ApiResult<Self> {
57 if enforce && context.is_none() {
58 let err = AuthError::InternalError("Missing auth context".into());
59 err.log(None, None, enforce);
60 Err(err.into())
61 } else {
62 Ok(Self {
63 service,
64 context,
65 enforce,
66 })
67 }
68 }
69
70 fn assert_authorized(&self, perm: Permission, context: &ObjectContext) -> ApiResult<()> {
71 let auth_result = match &self.context {
72 Some(auth) => auth.assert_authorized(perm, context),
73 None => Ok(()),
74 }
75 .inspect_err(|err| err.log(Some(perm), Some(context.usecase.as_str()), self.enforce));
76
77 match self.enforce {
78 true => Ok(auth_result?),
79 false => Ok(()),
80 }
81 }
82
83 pub fn check_permission(&self, perm: Permission, context: &ObjectContext) -> ApiResult<()> {
89 self.assert_authorized(perm, context)
90 }
91
92 pub async fn insert_object(
94 &self,
95 context: ObjectContext,
96 key: Option<String>,
97 metadata: Metadata,
98 stream: ClientStream,
99 ) -> ApiResult<InsertResponse> {
100 self.assert_authorized(Permission::ObjectWrite, &context)?;
101 Ok(self
102 .service
103 .insert_object(context, key, metadata, stream)
104 .await?)
105 }
106
107 pub async fn get_metadata(&self, id: ObjectId) -> ApiResult<MetadataResponse> {
109 self.assert_authorized(Permission::ObjectRead, id.context())?;
110 Ok(self.service.get_metadata(id).await?)
111 }
112
113 pub async fn get_object(
115 &self,
116 id: ObjectId,
117 range: Option<ByteRange>,
118 ) -> ApiResult<GetResponse> {
119 self.assert_authorized(Permission::ObjectRead, id.context())?;
120 Ok(self.service.get_object(id, range).await?)
121 }
122
123 pub async fn delete_object(&self, id: ObjectId) -> ApiResult<DeleteResponse> {
125 self.assert_authorized(Permission::ObjectDelete, id.context())?;
126 Ok(self.service.delete_object(id).await?)
127 }
128
129 pub async fn initiate_multipart(
133 &self,
134 id: ObjectId,
135 metadata: Metadata,
136 ) -> ApiResult<InitiateMultipartResponse> {
137 self.assert_authorized(Permission::ObjectWrite, id.context())?;
138 Ok(self.service.initiate_multipart(id, metadata).await?)
139 }
140
141 pub async fn upload_part(
143 &self,
144 id: ObjectId,
145 upload_id: UploadId,
146 part_number: PartNumber,
147 content_length: u64,
148 content_md5: Option<String>,
149 body: ClientStream,
150 ) -> ApiResult<UploadPartResponse> {
151 self.assert_authorized(Permission::ObjectWrite, id.context())?;
152 Ok(self
153 .service
154 .upload_part(
155 id,
156 upload_id,
157 part_number,
158 content_length,
159 content_md5,
160 body,
161 )
162 .await?)
163 }
164
165 pub async fn list_parts(
167 &self,
168 id: ObjectId,
169 upload_id: UploadId,
170 max_parts: Option<u32>,
171 part_number_marker: Option<PartNumber>,
172 ) -> ApiResult<ListPartsResponse> {
173 self.assert_authorized(Permission::ObjectWrite, id.context())?;
174 Ok(self
175 .service
176 .list_parts(id, upload_id, max_parts, part_number_marker)
177 .await?)
178 }
179
180 pub async fn abort_multipart(
182 &self,
183 id: ObjectId,
184 upload_id: UploadId,
185 ) -> ApiResult<AbortMultipartResponse> {
186 self.assert_authorized(Permission::ObjectWrite, id.context())?;
187 Ok(self.service.abort_multipart(id, upload_id).await?)
188 }
189
190 pub async fn complete_multipart(
192 &self,
193 id: ObjectId,
194 upload_id: UploadId,
195 parts: Vec<CompletedPart>,
196 ) -> ApiResult<CompleteMultipartResponse> {
197 self.assert_authorized(Permission::ObjectWrite, id.context())?;
198 Ok(self
199 .service
200 .complete_multipart(id, upload_id, parts)
201 .await?)
202 }
203}