Skip to content

Commit

Permalink
Add authentication to S3 GET requests
Browse files Browse the repository at this point in the history
This is configurable through the `SCCACHE_S3_GET_AUTH` environment
variable. When `"true"`, authentication will be performed in the same
manner as for PUT requests, allowing completely private buckets to be
used.
  • Loading branch information
jrobsonchase committed Oct 10, 2017
1 parent 646be05 commit aa5f93f
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 4 deletions.
26 changes: 24 additions & 2 deletions src/cache/s3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub struct S3Cache {
bucket: Rc<Bucket>,
/// Credentials provider.
provider: AutoRefreshingProvider<ChainProvider>,
/// Whether or not to authenticate S3 GET requests.
get_auth: bool,
}

impl S3Cache {
Expand All @@ -57,9 +59,11 @@ impl S3Cache {
let provider = AutoRefreshingProvider::new(ChainProvider::with_profile_providers(profile_providers, handle));
//TODO: configurable SSL
let bucket = Rc::new(Bucket::new(bucket, endpoint, Ssl::No, handle)?);
let get_auth = env::var("SCCACHE_S3_GET_AUTH").unwrap_or("false".to_string()).to_lowercase() == "true";
Ok(S3Cache {
bucket: bucket,
provider: provider,
get_auth: get_auth,
})
}
}
Expand All @@ -71,7 +75,8 @@ fn normalize_key(key: &str) -> String {
impl Storage for S3Cache {
fn get(&self, key: &str) -> SFuture<Cache> {
let key = normalize_key(key);
Box::new(self.bucket.get(&key).then(|result| {

let result_cb = |result| {
match result {
Ok(data) => {
let hit = CacheRead::from(io::Cursor::new(data))?;
Expand All @@ -82,7 +87,24 @@ impl Storage for S3Cache {
Ok(Cache::Miss)
}
}
}))
};

if self.get_auth {
let bucket = self.bucket.clone();
let authed = self.provider
.credentials()
.chain_err(|| {
"failed to get AWS credentials"
})
.and_then(move |credentials| bucket.get(&key, Some(&credentials)))
.then(result_cb);
Box::new(authed)
} else {
let open = self.bucket
.get(&key, None)
.then(result_cb);
Box::new(open)
}
}

fn put(&self, key: &str, entry: CacheWrite) -> SFuture<Duration> {
Expand Down
22 changes: 20 additions & 2 deletions src/simples3/s3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,29 @@ impl Bucket {
})
}

pub fn get(&self, key: &str) -> SFuture<Vec<u8>> {
pub fn get(&self, key: &str, creds: Option<&AwsCredentials>) -> SFuture<Vec<u8>> {
let url = format!("{}{}", self.base_url, key);
debug!("GET {}", url);
let url2 = url.clone();
Box::new(self.client.get(url.parse().unwrap()).chain_err(move || {
let mut request = Request::new(Method::Get, url.parse().unwrap());
match creds {
Some(creds) => {
let mut canonical_headers = String::new();

if let Some(token) = creds.token().as_ref().map(|s| s.as_str()) {
request.headers_mut()
.set_raw("x-amz-security-token", vec!(token.as_bytes().to_vec()));
canonical_headers.push_str(format!("{}:{}\n", "x-amz-security-token", token).as_ref());
}
let date = time::now_utc().rfc822().to_string();
let auth = self.auth("GET", &date, key, "", &canonical_headers, "", creds);
request.headers_mut().set_raw("Date", vec!(date.into_bytes()));
request.headers_mut().set_raw("Authorization", vec!(auth.into_bytes()));
}
// request is fine as-is
None => {},
}
Box::new(self.client.request(request).chain_err(move || {
format!("failed GET: {}", url)
}).and_then(|res| {
if res.status().is_success() {
Expand Down

0 comments on commit aa5f93f

Please sign in to comment.