minio-rs/src/s3/signer.rs
Bala FA 0fb80e1456
Refactor S3 client implementation (#13)
Added below S3 APIs

* abort_multipart_upload()
* bucket_exists()
* complete_multipart_upload()
* create_multipart_upload()
* get_object()
* list_buckets()
* list_objects_v1()
* list_objects_v2()
* list_object_versions()
* list_objects()
* make_bucket()
* put_object()
* put_object_api()
* remove_bucket()
* remove_object()
* remove_objects_api()
* remove_objects()
* select_object_content()
* stat_object()
* upload_part()

Signed-off-by: Bala.FA <bala@minio.io>
2022-08-20 15:10:11 -07:00

242 lines
6.7 KiB
Rust

// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
// Copyright 2022 MinIO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::s3::utils::{
get_canonical_headers, get_canonical_query_string, sha256_hash, to_amz_date, to_signer_date,
Multimap, UtcTime,
};
use hex::encode as hexencode;
use hmac::{Hmac, Mac};
use hyper::http::Method;
use sha2::Sha256;
pub fn hmac_hash(key: &[u8], data: &[u8]) -> Vec<u8> {
let mut hasher = Hmac::<Sha256>::new_from_slice(key).expect("HMAC can take key of any size");
hasher.update(data);
return hasher.finalize().into_bytes().to_vec();
}
pub fn hmac_hash_hex(key: &[u8], data: &[u8]) -> String {
return hexencode(hmac_hash(key, data));
}
pub fn get_scope(date: UtcTime, region: &str, service_name: &str) -> String {
return format!(
"{}/{}/{}/aws4_request",
to_signer_date(date),
region,
service_name
);
}
pub fn get_canonical_request_hash(
method: &Method,
uri: &str,
query_string: &str,
headers: &str,
signed_headers: &str,
content_sha256: &str,
) -> String {
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
let canonical_request = format!(
"{}\n{}\n{}\n{}\n\n{}\n{}",
method, uri, query_string, headers, signed_headers, content_sha256
);
return sha256_hash(canonical_request.as_bytes());
}
pub fn get_string_to_sign(date: UtcTime, scope: &str, canonical_request_hash: &str) -> String {
return format!(
"AWS4-HMAC-SHA256\n{}\n{}\n{}",
to_amz_date(date),
scope,
canonical_request_hash
);
}
pub fn get_signing_key(
secret_key: &str,
date: UtcTime,
region: &str,
service_name: &str,
) -> Vec<u8> {
let mut key: Vec<u8> = b"AWS4".to_vec();
key.extend(secret_key.as_bytes());
let date_key = hmac_hash(key.as_slice(), to_signer_date(date).as_bytes());
let date_region_key = hmac_hash(date_key.as_slice(), region.as_bytes());
let date_region_service_key = hmac_hash(date_region_key.as_slice(), service_name.as_bytes());
return hmac_hash(date_region_service_key.as_slice(), b"aws4_request");
}
pub fn get_signature(signing_key: &[u8], string_to_sign: &[u8]) -> String {
hmac_hash_hex(signing_key, string_to_sign)
}
pub fn get_authorization(
access_key: &str,
scope: &str,
signed_headers: &str,
signature: &str,
) -> String {
return format!(
"AWS4-HMAC-SHA256 Credential={}/{}, SignedHeaders={}, Signature={}",
access_key, scope, signed_headers, signature
);
}
pub fn sign_v4(
service_name: &str,
method: &Method,
uri: &str,
region: &str,
headers: &mut Multimap,
query_params: &Multimap,
access_key: &str,
secret_key: &str,
content_sha256: &str,
date: UtcTime,
) {
let scope = get_scope(date, region, service_name);
let (signed_headers, canonical_headers) = get_canonical_headers(headers);
let canonical_query_string = get_canonical_query_string(query_params);
let canonical_request_hash = get_canonical_request_hash(
method,
uri,
&canonical_query_string,
&canonical_headers,
&signed_headers,
content_sha256,
);
let string_to_sign = get_string_to_sign(date, &scope, &canonical_request_hash);
let signing_key = get_signing_key(secret_key, date, region, service_name);
let signature = get_signature(signing_key.as_slice(), string_to_sign.as_bytes());
let authorization = get_authorization(access_key, &scope, &signed_headers, &signature);
headers.insert("Authorization".to_string(), authorization);
}
pub fn sign_v4_s3(
method: &Method,
uri: &str,
region: &str,
headers: &mut Multimap,
query_params: &Multimap,
access_key: &str,
secret_key: &str,
content_sha256: &str,
date: UtcTime,
) {
sign_v4(
"s3",
method,
uri,
region,
headers,
query_params,
access_key,
secret_key,
content_sha256,
date,
)
}
pub fn sign_v4_sts(
method: &Method,
uri: &str,
region: &str,
headers: &mut Multimap,
query_params: &Multimap,
access_key: &str,
secret_key: &str,
content_sha256: &str,
date: UtcTime,
) {
sign_v4(
"sts",
method,
uri,
region,
headers,
query_params,
access_key,
secret_key,
content_sha256,
date,
)
}
pub fn presign_v4(
method: &Method,
host: &str,
uri: &str,
region: &str,
query_params: &mut Multimap,
access_key: &str,
secret_key: &str,
date: UtcTime,
expires: u32,
) {
let scope = get_scope(date, region, "s3");
let canonical_headers = "host:".to_string() + host;
let signed_headers = "host";
query_params.insert(
"X-Amz-Algorithm".to_string(),
"AWS4-HMAC-SHA256".to_string(),
);
query_params.insert(
"X-Amz-Credential".to_string(),
access_key.to_string() + "/" + &scope,
);
query_params.insert("X-Amz-Date".to_string(), to_amz_date(date));
query_params.insert("X-Amz-Expires".to_string(), expires.to_string());
query_params.insert(
"X-Amz-SignedHeaders".to_string(),
signed_headers.to_string(),
);
let canonical_query_string = get_canonical_query_string(query_params);
let canonical_request_hash = get_canonical_request_hash(
method,
uri,
&canonical_query_string,
&canonical_headers,
&signed_headers,
"UNSIGNED-PAYLOAD",
);
let string_to_sign = get_string_to_sign(date, &scope, &canonical_request_hash);
let signing_key = get_signing_key(secret_key, date, region, "s3");
let signature = get_signature(signing_key.as_slice(), string_to_sign.as_bytes());
query_params.insert("X-Amz-Signature".to_string(), signature);
}
pub fn post_presign_v4(
string_to_sign: &str,
secret_key: &str,
date: UtcTime,
region: &str,
) -> String {
let signing_key = get_signing_key(secret_key, date, region, "s3");
return get_signature(signing_key.as_slice(), string_to_sign.as_bytes());
}