571 lines
18 KiB
C
571 lines
18 KiB
C
#include "oss_auth.h"
|
|
#include "aos_log.h"
|
|
#include "oss_util.h"
|
|
|
|
static const char *g_s_oss_sub_resource_list[] = {
|
|
"acl",
|
|
"uploadId",
|
|
"uploads",
|
|
"partNumber",
|
|
"response-content-type",
|
|
"response-content-language",
|
|
"response-expires",
|
|
"response-cache-control",
|
|
"response-content-disposition",
|
|
"response-content-encoding",
|
|
"append",
|
|
"position",
|
|
"lifecycle",
|
|
"delete",
|
|
"live",
|
|
"status",
|
|
"comp",
|
|
"vod",
|
|
"startTime",
|
|
"endTime",
|
|
"x-oss-process",
|
|
"security-token",
|
|
NULL,
|
|
};
|
|
|
|
static int is_oss_sub_resource(const char *str);
|
|
static int is_oss_canonicalized_header(const char *str);
|
|
static int oss_get_canonicalized_headers(aos_pool_t *p,
|
|
const aos_table_t *headers, aos_buf_t *signbuf);
|
|
static int oss_get_canonicalized_resource(aos_pool_t *p,
|
|
const aos_table_t *params, aos_buf_t *signbuf);
|
|
static int oss_get_canonicalized_params(aos_pool_t *p,
|
|
const aos_table_t *params, aos_buf_t *signbuf);
|
|
|
|
static int is_oss_sub_resource(const char *str)
|
|
{
|
|
int i = 0;
|
|
for ( ; g_s_oss_sub_resource_list[i]; i++) {
|
|
if (apr_strnatcmp(g_s_oss_sub_resource_list[i], str) == 0) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int is_oss_canonicalized_header(const char *str)
|
|
{
|
|
size_t len = strlen(OSS_CANNONICALIZED_HEADER_PREFIX);
|
|
return strncasecmp(str, OSS_CANNONICALIZED_HEADER_PREFIX, len) == 0;
|
|
}
|
|
|
|
static int oss_get_canonicalized_headers(aos_pool_t *p,
|
|
const aos_table_t *headers,
|
|
aos_buf_t *signbuf)
|
|
{
|
|
int pos;
|
|
int meta_count = 0;
|
|
int i;
|
|
int len;
|
|
const aos_array_header_t *tarr;
|
|
const aos_table_entry_t *telts;
|
|
char **meta_headers;
|
|
const char *value;
|
|
aos_string_t tmp_str;
|
|
char *tmpbuf = (char*)malloc(AOS_MAX_HEADER_LEN + 1);
|
|
if (NULL == tmpbuf) {
|
|
aos_error_log("malloc %d memory failed.", AOS_MAX_HEADER_LEN + 1);
|
|
return AOSE_OVER_MEMORY;
|
|
}
|
|
|
|
if (apr_is_empty_table(headers)) {
|
|
free(tmpbuf);
|
|
return AOSE_OK;
|
|
}
|
|
|
|
// sort user meta header
|
|
tarr = aos_table_elts(headers);
|
|
telts = (aos_table_entry_t*)tarr->elts;
|
|
meta_headers = aos_pcalloc(p, tarr->nelts * sizeof(char*));
|
|
for (pos = 0; pos < tarr->nelts; ++pos) {
|
|
if (is_oss_canonicalized_header(telts[pos].key)) {
|
|
aos_string_t key = aos_string(telts[pos].key);
|
|
aos_string_tolower(&key);
|
|
meta_headers[meta_count++] = key.data;
|
|
}
|
|
}
|
|
if (meta_count == 0) {
|
|
free(tmpbuf);
|
|
return AOSE_OK;
|
|
}
|
|
aos_gnome_sort((const char **)meta_headers, meta_count);
|
|
|
|
// sign string
|
|
for (i = 0; i < meta_count; ++i) {
|
|
value = apr_table_get(headers, meta_headers[i]);
|
|
aos_str_set(&tmp_str, value);
|
|
aos_strip_space(&tmp_str);
|
|
len = apr_snprintf(tmpbuf, AOS_MAX_HEADER_LEN + 1, "%s:%.*s",
|
|
meta_headers[i], tmp_str.len, tmp_str.data);
|
|
if (len > AOS_MAX_HEADER_LEN) {
|
|
free(tmpbuf);
|
|
aos_error_log("user meta header too many, %d > %d.",
|
|
len, AOS_MAX_HEADER_LEN);
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
tmp_str.data = tmpbuf;
|
|
tmp_str.len = len;
|
|
aos_buf_append_string(p, signbuf, tmpbuf, len);
|
|
aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1);
|
|
}
|
|
|
|
free(tmpbuf);
|
|
return AOSE_OK;
|
|
}
|
|
|
|
static int oss_get_canonicalized_resource(aos_pool_t *p,
|
|
const aos_table_t *params,
|
|
aos_buf_t *signbuf)
|
|
{
|
|
int pos;
|
|
int subres_count = 0;
|
|
int i;
|
|
int len;
|
|
char sep;
|
|
const char *value;
|
|
char tmpbuf[AOS_MAX_QUERY_ARG_LEN+1];
|
|
char **subres_headers;
|
|
const aos_array_header_t *tarr;
|
|
const aos_table_entry_t *telts;
|
|
|
|
if (apr_is_empty_table(params)) {
|
|
return AOSE_OK;
|
|
}
|
|
|
|
// sort sub resource param
|
|
tarr = aos_table_elts(params);
|
|
telts = (aos_table_entry_t*)tarr->elts;
|
|
subres_headers = aos_pcalloc(p, tarr->nelts * sizeof(char*));
|
|
for (pos = 0; pos < tarr->nelts; ++pos) {
|
|
if (is_oss_sub_resource(telts[pos].key)) {
|
|
subres_headers[subres_count++] = telts[pos].key;
|
|
}
|
|
}
|
|
if (subres_count == 0) {
|
|
return AOSE_OK;
|
|
}
|
|
aos_gnome_sort((const char **)subres_headers, subres_count);
|
|
|
|
// sign string
|
|
sep = '?';
|
|
for (i = 0; i < subres_count; ++i) {
|
|
value = apr_table_get(params, subres_headers[i]);
|
|
if (value != NULL && *value != '\0') {
|
|
len = apr_snprintf(tmpbuf, sizeof(tmpbuf), "%c%s=%s",
|
|
sep, subres_headers[i], value);
|
|
} else {
|
|
len = apr_snprintf(tmpbuf, sizeof(tmpbuf), "%c%s",
|
|
sep, subres_headers[i]);
|
|
}
|
|
if (len >= AOS_MAX_QUERY_ARG_LEN) {
|
|
aos_error_log("http query params too long, %s.", tmpbuf);
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
aos_buf_append_string(p, signbuf, tmpbuf, len);
|
|
sep = '&';
|
|
}
|
|
|
|
return AOSE_OK;
|
|
}
|
|
|
|
int oss_get_string_to_sign(aos_pool_t *p,
|
|
http_method_e method,
|
|
const aos_string_t *canon_res,
|
|
const aos_table_t *headers,
|
|
const aos_table_t *params,
|
|
aos_string_t *signstr)
|
|
{
|
|
int res;
|
|
aos_buf_t *signbuf;
|
|
const char *value;
|
|
aos_str_null(signstr);
|
|
|
|
signbuf = aos_create_buf(p, 1024);
|
|
|
|
#define signbuf_append_from_headers(KEY) do { \
|
|
if ((value = apr_table_get(headers, KEY)) != NULL) { \
|
|
aos_buf_append_string(p, signbuf, value, strlen(value)); \
|
|
} \
|
|
aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1); \
|
|
} while (0)
|
|
|
|
#define signbuf_append(VALUE, LEN) do { \
|
|
aos_buf_append_string(p, signbuf, VALUE, LEN); \
|
|
aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1); \
|
|
} while (0)
|
|
|
|
value = aos_http_method_to_string(method);
|
|
signbuf_append(value, strlen(value));
|
|
|
|
signbuf_append_from_headers(OSS_CONTENT_MD5);
|
|
signbuf_append_from_headers(OSS_CONTENT_TYPE);
|
|
|
|
// date
|
|
if ((value = apr_table_get(headers, OSS_CANNONICALIZED_HEADER_DATE)) == NULL) {
|
|
value = apr_table_get(headers, OSS_DATE);
|
|
}
|
|
if (NULL == value || *value == '\0') {
|
|
aos_error_log("http header date is empty.");
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
signbuf_append(value, strlen(value));
|
|
|
|
// user meta headers
|
|
if ((res = oss_get_canonicalized_headers(p, headers, signbuf)) != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
// canonicalized resource
|
|
aos_buf_append_string(p, signbuf, canon_res->data, canon_res->len);
|
|
|
|
if (params != NULL && (res = oss_get_canonicalized_resource(p, params, signbuf)) != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
// result
|
|
signstr->data = (char *)signbuf->pos;
|
|
signstr->len = aos_buf_size(signbuf);
|
|
|
|
return AOSE_OK;
|
|
}
|
|
|
|
void oss_sign_headers(aos_pool_t *p,
|
|
const aos_string_t *signstr,
|
|
const aos_string_t *access_key_id,
|
|
const aos_string_t *access_key_secret,
|
|
aos_table_t *headers)
|
|
{
|
|
int b64Len;
|
|
char *value;
|
|
unsigned char hmac[20];
|
|
char b64[((20 + 1) * 4) / 3];
|
|
|
|
HMAC_SHA1(hmac, (unsigned char *)access_key_secret->data, access_key_secret->len,
|
|
(unsigned char *)signstr->data, signstr->len);
|
|
|
|
// Now base-64 encode the results
|
|
b64Len = aos_base64_encode(hmac, 20, b64);
|
|
value = apr_psprintf(p, "OSS %.*s:%.*s", access_key_id->len, access_key_id->data, b64Len, b64);
|
|
apr_table_addn(headers, OSS_AUTHORIZATION, value);
|
|
|
|
return;
|
|
}
|
|
|
|
int oss_get_signed_headers(aos_pool_t *p,
|
|
const aos_string_t *access_key_id,
|
|
const aos_string_t *access_key_secret,
|
|
const aos_string_t* canon_res,
|
|
aos_http_request_t *req)
|
|
{
|
|
int res;
|
|
aos_string_t signstr;
|
|
|
|
res = oss_get_string_to_sign(p, req->method, canon_res,
|
|
req->headers, req->query_params, &signstr);
|
|
|
|
if (res != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
aos_debug_log("signstr:%.*s.", signstr.len, signstr.data);
|
|
|
|
oss_sign_headers(p, &signstr, access_key_id, access_key_secret, req->headers);
|
|
|
|
return AOSE_OK;
|
|
}
|
|
|
|
int oss_sign_request(aos_http_request_t *req,
|
|
const oss_config_t *config)
|
|
{
|
|
aos_string_t canon_res;
|
|
char canon_buf[AOS_MAX_URI_LEN];
|
|
char datestr[AOS_MAX_GMT_TIME_LEN];
|
|
const char *value;
|
|
int res = AOSE_OK;
|
|
int len = 0;
|
|
|
|
len = strlen(req->resource);
|
|
if (len >= AOS_MAX_URI_LEN - 1) {
|
|
aos_error_log("http resource too long, %s.", req->resource);
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
|
|
canon_res.data = canon_buf;
|
|
canon_res.len = apr_snprintf(canon_buf, sizeof(canon_buf), "/%s", req->resource);
|
|
|
|
if ((value = apr_table_get(req->headers, OSS_CANNONICALIZED_HEADER_DATE)) == NULL) {
|
|
aos_get_gmt_str_time(datestr);
|
|
apr_table_set(req->headers, OSS_DATE, datestr);
|
|
}
|
|
|
|
res = oss_get_signed_headers(req->pool, &config->access_key_id,
|
|
&config->access_key_secret, &canon_res, req);
|
|
return res;
|
|
}
|
|
|
|
int get_oss_request_signature(const oss_request_options_t *options,
|
|
aos_http_request_t *req,
|
|
const aos_string_t *expires,
|
|
aos_string_t *signature)
|
|
{
|
|
aos_string_t canon_res;
|
|
char canon_buf[AOS_MAX_URI_LEN];
|
|
const char *value;
|
|
aos_string_t signstr;
|
|
int res = AOSE_OK;
|
|
int b64Len;
|
|
unsigned char hmac[20];
|
|
char b64[((20 + 1) * 4) / 3];
|
|
|
|
canon_res.data = canon_buf;
|
|
canon_res.len = apr_snprintf(canon_buf, sizeof(canon_buf), "/%s", req->resource);
|
|
|
|
apr_table_set(req->headers, OSS_DATE, expires->data);
|
|
|
|
if ((res = oss_get_string_to_sign(options->pool, req->method, &canon_res,
|
|
req->headers, req->query_params, &signstr))!= AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
HMAC_SHA1(hmac, (unsigned char *)options->config->access_key_secret.data,
|
|
options->config->access_key_secret.len,
|
|
(unsigned char *)signstr.data, signstr.len);
|
|
|
|
b64Len = aos_base64_encode(hmac, 20, b64);
|
|
value = apr_psprintf(options->pool, "%.*s", b64Len, b64);
|
|
aos_str_set(signature, value);
|
|
|
|
return res;
|
|
}
|
|
|
|
int oss_get_signed_url(const oss_request_options_t *options,
|
|
aos_http_request_t *req,
|
|
const aos_string_t *expires,
|
|
aos_string_t *signed_url)
|
|
{
|
|
char *signed_url_str;
|
|
aos_string_t querystr;
|
|
char uristr[3*AOS_MAX_URI_LEN+1];
|
|
int res = AOSE_OK;
|
|
aos_string_t signature;
|
|
const char *proto;
|
|
|
|
if (options->config->sts_token.data != NULL) {
|
|
apr_table_set(req->query_params, OSS_SECURITY_TOKEN, options->config->sts_token.data);
|
|
}
|
|
|
|
res = get_oss_request_signature(options, req, expires, &signature);
|
|
if (res != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
apr_table_set(req->query_params, OSS_ACCESSKEYID, options->config->access_key_id.data);
|
|
apr_table_set(req->query_params, OSS_EXPIRES, expires->data);
|
|
apr_table_set(req->query_params, OSS_SIGNATURE, signature.data);
|
|
|
|
uristr[0] = '\0';
|
|
aos_str_null(&querystr);
|
|
res = aos_url_encode(uristr, req->uri, AOS_MAX_URI_LEN);
|
|
if (res != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
res = aos_query_params_to_string(options->pool, req->query_params, &querystr);
|
|
if (res != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
proto = strlen(req->proto) != 0 ? req->proto : AOS_HTTP_PREFIX;
|
|
signed_url_str = apr_psprintf(options->pool, "%s%s/%s%.*s",
|
|
proto, req->host, uristr,
|
|
querystr.len, querystr.data);
|
|
aos_str_set(signed_url, signed_url_str);
|
|
|
|
return res;
|
|
}
|
|
|
|
int oss_get_rtmp_signed_url(const oss_request_options_t *options,
|
|
aos_http_request_t *req,
|
|
const aos_string_t *expires,
|
|
const aos_string_t *play_list_name,
|
|
aos_table_t *params,
|
|
aos_string_t *signed_url)
|
|
{
|
|
char *signed_url_str;
|
|
aos_string_t querystr;
|
|
char uristr[3*AOS_MAX_URI_LEN+1];
|
|
int res = AOSE_OK;
|
|
aos_string_t signature;
|
|
int pos = 0;
|
|
const aos_array_header_t *tarr;
|
|
const aos_table_entry_t *telts;
|
|
|
|
if (NULL != params) {
|
|
tarr = aos_table_elts(params);
|
|
telts = (aos_table_entry_t*)tarr->elts;
|
|
for (pos = 0; pos < tarr->nelts; ++pos) {
|
|
apr_table_set(req->query_params, telts[pos].key, telts[pos].val);
|
|
}
|
|
}
|
|
apr_table_set(req->query_params, OSS_PLAY_LIST_NAME, play_list_name->data);
|
|
|
|
res = get_oss_rtmp_request_signature(options, req, expires,&signature);
|
|
if (res != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
apr_table_set(req->query_params, OSS_ACCESSKEYID,
|
|
options->config->access_key_id.data);
|
|
apr_table_set(req->query_params, OSS_EXPIRES, expires->data);
|
|
apr_table_set(req->query_params, OSS_SIGNATURE, signature.data);
|
|
|
|
uristr[0] = '\0';
|
|
aos_str_null(&querystr);
|
|
res = aos_url_encode(uristr, req->uri, AOS_MAX_URI_LEN);
|
|
if (res != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
res = aos_query_params_to_string(options->pool, req->query_params, &querystr);
|
|
if (res != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
signed_url_str = apr_psprintf(options->pool, "%s%s/%s%.*s",
|
|
req->proto, req->host, uristr,
|
|
querystr.len, querystr.data);
|
|
aos_str_set(signed_url, signed_url_str);
|
|
|
|
return res;
|
|
}
|
|
|
|
int get_oss_rtmp_request_signature(const oss_request_options_t *options,
|
|
aos_http_request_t *req,
|
|
const aos_string_t *expires,
|
|
aos_string_t *signature)
|
|
{
|
|
aos_string_t canon_res;
|
|
char canon_buf[AOS_MAX_URI_LEN];
|
|
const char *value;
|
|
aos_string_t signstr;
|
|
int res = AOSE_OK;
|
|
int b64Len;
|
|
unsigned char hmac[20];
|
|
char b64[((20 + 1) * 4) / 3];
|
|
|
|
canon_res.data = canon_buf;
|
|
canon_res.len = apr_snprintf(canon_buf, sizeof(canon_buf), "/%s", req->resource);
|
|
|
|
if ((res = oss_get_rtmp_string_to_sign(options->pool, expires, &canon_res,
|
|
req->query_params, &signstr))!= AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
HMAC_SHA1(hmac, (unsigned char *)options->config->access_key_secret.data,
|
|
options->config->access_key_secret.len,
|
|
(unsigned char *)signstr.data, signstr.len);
|
|
|
|
b64Len = aos_base64_encode(hmac, 20, b64);
|
|
value = apr_psprintf(options->pool, "%.*s", b64Len, b64);
|
|
aos_str_set(signature, value);
|
|
|
|
return res;
|
|
}
|
|
|
|
int oss_get_rtmp_string_to_sign(aos_pool_t *p,
|
|
const aos_string_t *expires,
|
|
const aos_string_t *canon_res,
|
|
const aos_table_t *params,
|
|
aos_string_t *signstr)
|
|
{
|
|
int res;
|
|
aos_buf_t *signbuf;
|
|
aos_str_null(signstr);
|
|
|
|
signbuf = aos_create_buf(p, 1024);
|
|
|
|
// expires
|
|
aos_buf_append_string(p, signbuf, expires->data, expires->len);
|
|
aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1);
|
|
|
|
// canonicalized params
|
|
if ((res = oss_get_canonicalized_params(p, params, signbuf)) != AOSE_OK) {
|
|
return res;
|
|
}
|
|
|
|
// canonicalized resource
|
|
aos_buf_append_string(p, signbuf, canon_res->data, canon_res->len);
|
|
|
|
// result
|
|
signstr->data = (char *)signbuf->pos;
|
|
signstr->len = aos_buf_size(signbuf);
|
|
|
|
return AOSE_OK;
|
|
}
|
|
|
|
static int oss_get_canonicalized_params(aos_pool_t *p,
|
|
const aos_table_t *params,
|
|
aos_buf_t *signbuf)
|
|
{
|
|
int pos;
|
|
int meta_count = 0;
|
|
int i;
|
|
int len;
|
|
const aos_array_header_t *tarr;
|
|
const aos_table_entry_t *telts;
|
|
char **meta_headers;
|
|
const char *value;
|
|
aos_string_t tmp_str;
|
|
char *tmpbuf = (char*)malloc(AOS_MAX_HEADER_LEN + 1);
|
|
if (NULL == tmpbuf) {
|
|
aos_error_log("malloc %d memory failed.", AOS_MAX_HEADER_LEN + 1);
|
|
return AOSE_OVER_MEMORY;
|
|
}
|
|
|
|
if (apr_is_empty_table(params)) {
|
|
free(tmpbuf);
|
|
return AOSE_OK;
|
|
}
|
|
|
|
// sort user meta header
|
|
tarr = aos_table_elts(params);
|
|
telts = (aos_table_entry_t*)tarr->elts;
|
|
meta_headers = aos_pcalloc(p, tarr->nelts * sizeof(char*));
|
|
for (pos = 0; pos < tarr->nelts; ++pos) {
|
|
aos_string_t key = aos_string(telts[pos].key);
|
|
meta_headers[meta_count++] = key.data;
|
|
}
|
|
if (meta_count == 0) {
|
|
free(tmpbuf);
|
|
return AOSE_OK;
|
|
}
|
|
aos_gnome_sort((const char **)meta_headers, meta_count);
|
|
|
|
// sign string
|
|
for (i = 0; i < meta_count; ++i) {
|
|
value = apr_table_get(params, meta_headers[i]);
|
|
aos_str_set(&tmp_str, value);
|
|
aos_strip_space(&tmp_str);
|
|
len = apr_snprintf(tmpbuf, AOS_MAX_HEADER_LEN + 1, "%s:%.*s",
|
|
meta_headers[i], tmp_str.len, tmp_str.data);
|
|
if (len > AOS_MAX_HEADER_LEN) {
|
|
free(tmpbuf);
|
|
aos_error_log("rtmp parameters too many, %d > %d.",
|
|
len, AOS_MAX_HEADER_LEN);
|
|
return AOSE_INVALID_ARGUMENT;
|
|
}
|
|
tmp_str.data = tmpbuf;
|
|
tmp_str.len = len;
|
|
aos_buf_append_string(p, signbuf, tmpbuf, len);
|
|
aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1);
|
|
}
|
|
|
|
free(tmpbuf);
|
|
return AOSE_OK;
|
|
}
|