Skip to content
Permalink
Browse files

S3Document: If you get a 403, try recomputing the signing key.

  • Loading branch information...
kohler committed Nov 6, 2019
1 parent c42c7f8 commit a2d68d20a023ed7acf085ee11e7f4cd8ab91d539
Showing with 47 additions and 27 deletions.
  1. +4 −1 lib/curls3document.php
  2. +33 −14 lib/s3document.php
  3. +10 −12 src/conference.php
@@ -63,8 +63,11 @@ function parse_result() {
$hstr = preg_replace('/(?:\r\n?|\n)[ \t]+/s', " ", $hstr);
$this->parse_response_lines(preg_split('/\r\n?|\n/', $hstr));
$this->status = curl_getinfo($this->curlh, CURLINFO_RESPONSE_CODE);
if ($this->status === 0)
if ($this->status === 0) {
$this->status = null;
} else if ($this->status === 403) {
$this->status = $this->s3->check_403();
}
if ($this->status === null || $this->status === 500) {
$now = microtime(true);
$this->tries[] = [$this->runindex, round(($now - $this->start) * 1000) / 1000, round(($now - $this->first_start) * 1000) / 1000, $this->status, curl_errno($this->curlh)];
@@ -46,9 +46,12 @@ class S3Document extends S3Result {
private $s3_key;
private $s3_secret;
private $s3_region;
private $setting_cache;
private $setting_cache_prefix;
private $s3_scope;
private $s3_signing_key;
private $fixed_time;
private $reset_key = false;
static public $retry_timeout_allowance = 10; // in seconds
static private $instances = [];
@@ -59,9 +62,9 @@ function __construct($opt = []) {
$this->s3_secret = $opt["secret"];
$this->s3_bucket = $opt["bucket"];
$this->s3_region = get($opt, "region", "us-east-1");
$this->s3_scope = get($opt, "scope");
$this->s3_signing_key = get($opt, "signing_key");
$this->fixed_time = get($opt, "fixed_time");
$this->setting_cache = get($opt, "setting_cache");
$this->setting_cache_prefix = get($opt, "setting_cache_prefix", "__s3");
}
static function make($opt) {
@@ -81,25 +84,38 @@ function check_key_secret_bucket($key, $secret, $bucket) {
&& $this->s3_bucket === $bucket;
}
private function check_scope($s3_scope_date) {
return $this->s3_scope
&& substr($this->s3_scope, 0, 8) === $s3_scope_date
&& preg_match('{\G/([^/]*)/s3/aws4_request\z}',
$this->s3_scope, $m, 0, 8)
&& $m[1] === $this->s3_region;
}
function scope_and_signing_key($time) {
global $Now;
if ($this->s3_scope === null
&& $this->setting_cache) {
$this->s3_scope = $this->setting_cache->setting_data($this->setting_cache_prefix . "_scope");
$this->s3_signing_key = $this->setting_cache->setting_data($this->setting_cache_prefix . "_signing_key");
}
$s3_scope_date = gmdate("Ymd", $time);
if (!$this->check_scope($s3_scope_date)) {
$this->s3_scope = $s3_scope_date . "/" . $this->s3_region
. "/s3/aws4_request";
$expected_s3_scope = $s3_scope_date . "/" . $this->s3_region
. "/s3/aws4_request";
if ($this->s3_scope !== $expected_s3_scope) {
$this->reset_key = true;
$this->s3_scope = $expected_s3_scope;
$date_key = hash_hmac("sha256", $s3_scope_date, "AWS4" . $this->s3_secret, true);
$region_key = hash_hmac("sha256", $this->s3_region, $date_key, true);
$service_key = hash_hmac("sha256", "s3", $region_key, true);
$this->s3_signing_key = hash_hmac("sha256", "aws4_request", $service_key, true);
if ($this->setting_cache) {
$this->setting_cache->__save_setting($this->setting_cache_prefix . "_scope", $Now, $this->s3_scope);
$this->setting_cache->__save_setting($this->setting_cache_prefix . "_signing_key", $Now, $this->s3_signing_key);
}
}
return [$this->s3_scope, $this->s3_signing_key];
}
function check_403() {
if (!$this->reset_key) {
$this->s3_scope = $this->s3_signing_key = "";
return null;
} else {
return 403;
}
return array($this->s3_scope, $this->s3_signing_key);
}
function signature($method, $url, $hdr, $content = null) {
@@ -247,6 +263,9 @@ private function run($skey, $method, $args) {
for ($i = 1; true; ++$i) {
$this->clear_result();
$this->run_stream_once($skey, $method, $args);
if ($this->status === 403) {
$this->status = $this->check_403();
}
if ($this->status !== null && $this->status !== 500) {
return;
}
@@ -584,7 +584,7 @@ function setting_json($name, $defval = null) {
return is_string($x) ? json_decode($x) : $x;
}
private function __save_setting($name, $value, $data = null) {
function __save_setting($name, $value, $data = null) {
$change = false;
if ($value === null && $data === null) {
if ($this->qe("delete from Settings where name=?", $name)) {
@@ -767,19 +767,17 @@ function s3_docstore() {
global $Now;
if ($this->_s3_document === false) {
if ($this->setting_data("s3_bucket")) {
$opts = ["key" => $this->setting_data("s3_key"),
"secret" => $this->setting_data("s3_secret"),
"bucket" => $this->setting_data("s3_bucket"),
"scope" => $this->setting_data("__s3_scope"),
"signing_key" => $this->setting_data("__s3_signing_key")];
$opts = [
"key" => $this->setting_data("s3_key"),
"secret" => $this->setting_data("s3_secret"),
"bucket" => $this->setting_data("s3_bucket"),
"setting_cache" => $this,
"setting_cache_prefix" => "__s3"
];
$this->_s3_document = S3Document::make($opts);
list($scope, $signing_key) = $this->_s3_document->scope_and_signing_key($Now);
if ($opts["scope"] !== $scope || $opts["signing_key"] !== $signing_key) {
$this->__save_setting("__s3_scope", 1, $scope);
$this->__save_setting("__s3_signing_key", 1, $signing_key);
}
} else
} else {
$this->_s3_document = null;
}
}
return $this->_s3_document;
}

0 comments on commit a2d68d2

Please sign in to comment.
You can’t perform that action at this time.