use super::*;
mod object_list;
impl BucketWarden {
pub fn get_object(
&mut self,
principal: &str,
bucket: &str,
key: &str,
) -> Result<GetObjectResult, RuntimeError> {
self.read_current_object(principal, bucket, key, S3Action::GetObject)
}
pub fn get_object_version(
&mut self,
principal: &str,
bucket: &str,
key: &str,
version_id: &str,
) -> Result<GetObjectResult, RuntimeError> {
self.read_object_version(principal, bucket, key, version_id, S3Action::GetObject)
}
pub fn get_object_torrent(
&mut self,
principal: &str,
bucket: &str,
key: &str,
) -> Result<GetObjectResult, RuntimeError> {
self.read_current_object(principal, bucket, key, S3Action::GetObjectTorrent)
}
pub fn get_object_version_torrent(
&mut self,
principal: &str,
bucket: &str,
key: &str,
version_id: &str,
) -> Result<GetObjectResult, RuntimeError> {
self.read_object_version(
principal,
bucket,
key,
version_id,
S3Action::GetObjectTorrent,
)
}
fn read_current_object(
&mut self,
principal: &str,
bucket: &str,
key: &str,
action: S3Action,
) -> Result<GetObjectResult, RuntimeError> {
let resource = object_resource(bucket, key);
let (
context,
result_version_id,
etag,
last_modified_epoch_seconds,
ciphertext,
metadata,
envelope,
integrity,
replication_status,
) = {
let version = match self.current_version(bucket, key) {
Ok(version) => version,
Err(error @ RuntimeError::NoSuchKey(_)) => {
self.authorize(principal, action, &resource)?;
return Err(error);
}
Err(error) => return Err(error),
};
(
object_tag_context(version),
version.version_id.clone(),
version.etag.clone(),
version.last_modified_epoch_seconds,
version.ciphertext.clone(),
version.metadata.clone(),
version.envelope.clone(),
version.integrity.clone(),
version.replication_status.clone(),
)
};
self.authorize_with_context(principal, action, &resource, &context)?;
let body = match self.kms.decrypt(&ciphertext) {
Ok(body) => body,
Err(error) => {
self.audit_kms_failure(
principal,
"kms:Decrypt",
&resource,
&ciphertext.key_id,
&error.to_string(),
);
return Err(RuntimeError::Kms(error));
}
};
self.verify_integrity_record(&integrity, &body)?;
let result = GetObjectResult {
bucket: bucket.to_string(),
key: key.to_string(),
version_id: result_version_id,
etag,
last_modified_epoch_seconds,
body,
metadata,
replication_status,
};
self.audit_allowed(
principal,
action,
&resource,
Some(result.version_id.clone()),
);
self.audit_kms_decrypt(principal, &resource, &result.version_id, &ciphertext.key_id);
if let Some(envelope) = envelope {
self.audit_kms_unwrap(principal, &resource, &result.version_id, &envelope.key_id);
}
Ok(result)
}
fn read_object_version(
&mut self,
principal: &str,
bucket: &str,
key: &str,
version_id: &str,
action: S3Action,
) -> Result<GetObjectResult, RuntimeError> {
let resource = object_resource(bucket, key);
let (
context,
result_version_id,
etag,
last_modified_epoch_seconds,
ciphertext,
metadata,
envelope,
integrity,
replication_status,
) = {
let version = self.version_by_id(bucket, key, version_id)?;
if version.delete_marker {
return Err(RuntimeError::NoSuchKey(object_resource(bucket, key)));
}
(
object_tag_context(version),
version.version_id.clone(),
version.etag.clone(),
version.last_modified_epoch_seconds,
version.ciphertext.clone(),
version.metadata.clone(),
version.envelope.clone(),
version.integrity.clone(),
version.replication_status.clone(),
)
};
self.authorize_with_context(principal, action, &resource, &context)?;
let body = match self.kms.decrypt(&ciphertext) {
Ok(body) => body,
Err(error) => {
self.audit_kms_failure(
principal,
"kms:Decrypt",
&resource,
&ciphertext.key_id,
&error.to_string(),
);
return Err(RuntimeError::Kms(error));
}
};
self.verify_integrity_record(&integrity, &body)?;
let result = GetObjectResult {
bucket: bucket.to_string(),
key: key.to_string(),
version_id: result_version_id,
etag,
last_modified_epoch_seconds,
body,
metadata,
replication_status,
};
self.audit_allowed(
principal,
action,
&resource,
Some(result.version_id.clone()),
);
self.audit_kms_decrypt(principal, &resource, &result.version_id, &ciphertext.key_id);
if let Some(envelope) = envelope {
self.audit_kms_unwrap(principal, &resource, &result.version_id, &envelope.key_id);
}
Ok(result)
}
pub fn head_object(
&mut self,
principal: &str,
bucket: &str,
key: &str,
) -> Result<HeadObjectResult, RuntimeError> {
let resource = object_resource(bucket, key);
self.authorize(principal, S3Action::HeadObject, &resource)?;
let version = self.current_version(bucket, key)?;
let result = HeadObjectResult {
bucket: bucket.to_string(),
key: key.to_string(),
version_id: version.version_id.clone(),
etag: version.etag.clone(),
last_modified_epoch_seconds: version.last_modified_epoch_seconds,
content_length: version.content_length(),
metadata: version.metadata.clone(),
replication_status: version.replication_status.clone(),
};
self.audit_allowed(
principal,
S3Action::HeadObject,
&resource,
Some(result.version_id.clone()),
);
Ok(result)
}
pub fn head_object_version(
&mut self,
principal: &str,
bucket: &str,
key: &str,
version_id: &str,
) -> Result<HeadObjectResult, RuntimeError> {
let resource = object_resource(bucket, key);
self.authorize(principal, S3Action::HeadObject, &resource)?;
let version = self.version_by_id(bucket, key, version_id)?;
if version.delete_marker {
return Err(RuntimeError::NoSuchKey(object_resource(bucket, key)));
}
let result = HeadObjectResult {
bucket: bucket.to_string(),
key: key.to_string(),
version_id: version.version_id.clone(),
etag: version.etag.clone(),
last_modified_epoch_seconds: version.last_modified_epoch_seconds,
content_length: version.content_length(),
metadata: version.metadata.clone(),
replication_status: version.replication_status.clone(),
};
self.audit_allowed(
principal,
S3Action::HeadObject,
&resource,
Some(result.version_id.clone()),
);
Ok(result)
}
pub fn get_object_attributes(
&mut self,
principal: &str,
bucket: &str,
key: &str,
) -> Result<GetObjectAttributesResult, RuntimeError> {
let resource = object_resource(bucket, key);
self.authorize(principal, S3Action::GetObjectAttributes, &resource)?;
let version = self.current_version(bucket, key)?;
let result = GetObjectAttributesResult {
bucket: bucket.to_string(),
key: key.to_string(),
version_id: version.version_id.clone(),
etag: version.etag.clone(),
last_modified_epoch_seconds: version.last_modified_epoch_seconds,
object_size: version.integrity.content_length,
checksum: Checksum {
checksum_sha256: base64_encode(version.integrity.checksum_sha256.as_bytes()),
},
storage_class: "STANDARD".to_string(),
object_parts: GetObjectAttributesParts {
total_parts_count: version.integrity.part_checksums.len(),
part_number_marker: 0,
max_parts: version.integrity.part_checksums.len(),
is_truncated: false,
},
};
self.audit_allowed(
principal,
S3Action::GetObjectAttributes,
&resource,
Some(result.version_id.clone()),
);
Ok(result)
}
pub fn get_object_version_attributes(
&mut self,
principal: &str,
bucket: &str,
key: &str,
version_id: &str,
) -> Result<GetObjectAttributesResult, RuntimeError> {
let resource = object_resource(bucket, key);
self.authorize(principal, S3Action::GetObjectAttributes, &resource)?;
let version = self.version_by_id(bucket, key, version_id)?;
if version.delete_marker {
return Err(RuntimeError::NoSuchKey(object_resource(bucket, key)));
}
let result = GetObjectAttributesResult {
bucket: bucket.to_string(),
key: key.to_string(),
version_id: version.version_id.clone(),
etag: version.etag.clone(),
last_modified_epoch_seconds: version.last_modified_epoch_seconds,
object_size: version.integrity.content_length,
checksum: Checksum {
checksum_sha256: base64_encode(version.integrity.checksum_sha256.as_bytes()),
},
storage_class: "STANDARD".to_string(),
object_parts: GetObjectAttributesParts {
total_parts_count: version.integrity.part_checksums.len(),
part_number_marker: 0,
max_parts: version.integrity.part_checksums.len(),
is_truncated: false,
},
};
self.audit_allowed(
principal,
S3Action::GetObjectAttributes,
&resource,
Some(result.version_id.clone()),
);
Ok(result)
}
}