Each HTTP request of a Log Service API operation must pass security verification to ensure log data security. Log Service uses the asymmetric encryption algorithm to verify API requests based on Alibaba Cloud AccessKey pairs.
Usage notes
Log Service SDKs encapsulate all API operations of Log Service. You can use a Log Service SDK to call all API operations of Log Service in an efficient manner. Log Service provides SDKs for multiple programming languages. The SDKs automatically sign requests. We recommend that you use a Log Service SDK to access Log Service. For more information, see Overview of Log Service SDKs.
- Identify who sends the API request.
A user must specify an AccessKey pair to generate the digital signature for an API request. When an AccessKey pair is specified, Log Service uses the AccessKey pair to identify the user and implement access control.
- Check whether a request header is tampered during transmission.
The server calculates the digital signature of an API request and compares the digital signature with the signature calculated by the client. If the request header is tampered during transmission, the two signatures are different and the verification fails.
For more information, see AccessKey pair. You can use an existing AccessKey pair or create an AccessKey pair. The AccessKey pair must be in the Active state.
The following sections describe the signature structure and the process of calculating a signature, and provide sample code in different programming languages. The sample code shows how signature algorithms are used to calculate signatures.
Signature structure
Field | Description | Example |
---|---|---|
x-log-signaturemethod | The encryption method of the request. | hmac-sha1 |
x-log-apiversion | The version of the API. | 0.6.0 |
Date | The standard timestamp header of the HTTP request. The timestamp header follows the time format that is defined in RFC 822 or RFC 1123 and uses the UTC standard time. Format: %a, %d %b %Y %H:%M:%S GMT . | Mon, 3 Jan 2010 08:33:47 GMT |
Content-MD5 | The MD5 hash value of the HTTP request body. The value must be converted to a hexadecimal string that contains only uppercase letters. | 72A15D7DE7EE9E7BB86461FFEA9499 |
Authorization | The signature. Format: LOG accessKeyId:Signature . accessKeyId specifies the AccessKey ID. Signature specifies the signature string. For information about the signature string, see Signature structure string. | LOG testAccessKeyId:RLETq4u7sWb3cssZIhsun**** |
Content-Type | The type of the HTTP request body. If no HTTP request body exists, you do not need to add this field. | application/json |
POST /logstores/test-logstore/shards/0?action=split HTTP/1.1
Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
Date: Tue, 23 Aug 2022 12:12:03 GMT
x-log-apiversion: 0.6.0
x-log-signaturemethod: hmac-sha1
Content-Length: 18
Content-Type: application/json
Content-MD5: 1572A15D7DE7EE9E7BB86461FFEA9499
Authorization: LOG testAccessKeyId:RLETq4u7sWb3cssZIhsun****
{"hello": "world"}
Calculate a signature
The Authorization
field is an important component of the signature structure. The Authorization field is in the LOG accessKeyId:Signature
format that concatenates the AccessKeyId
and Signature
fields. accessKeyId specifies an AccessKey ID and Signature specifies a signature string. This section describes how to construct a signature string for the Signature
field.
Signature message

Parameter | Description | Example |
---|---|---|
method | The HTTP request method. The value contains only uppercase letters. Valid values: GET, POST, PUT, and DELETE. | GET |
Content-MD5 | The MD5 hash value of the HTTP request body. The value must be converted to a hexadecimal string that contains only uppercase letters. If the HTTP request body is left empty, the value is an empty string. | 1572A15D7DE7EE9E7BB86461FFEA9499 |
Content-Type | The type of the HTTP request body. If the HTTP request body is left empty, the value can be an empty string. | application/json |
Date | The formatted string of the current time. The string follows the time format that is defined in RFC 822 or RFC 1123 and represents a UTC standard time. Format: %a, %d %b %Y %H:%M:%S GMT . | Mon, 3 Jan 2010 08:33:47 GMT |
header | The request header that contains key-value pairs prefixed by x-log- or x-acs- . The key-value pairs are sorted in ascending order by key. The key and value in a key-value pair are connected by a colon (: ). Key-value pairs are separated by line feeds. |
|
uri | The path of the request. The domain name and the query parameters are excluded. | /logstores/test-logstore |
query parameters | The query parameters of the request. The query parameters are in the key-value pair format and are sorted in ascending order by key. The key and value in a key-value pair are connected by an equal sign (= ). Key-value pairs are separated by ampersands (& ). | offset=1&size=10 |
POST
1572A15D7DE7EE9E7BB86461FFEA9499
application/json
Tue, 23 Aug 2022 12:12:03 GMT
x-log-apiversion:0.6.0
x-log-bodyrawsize:0
x-log-signaturemethod:hmac-sha1
/logstores?offset=1&size=10
Signature string

- Obtain a signature message.
- Use the HMAC-SHA1 algorithm and an AccessKey secret to encrypt the message and obtain an encrypted hash value.
- Encode the hash value in Base64 to generate a signature string.
Examples
AccessKeyId = "bq2sjzesjmo86kq****"
AccessKeySecret = "4fdO2fTDDnZPU/L7CHNd****"
- Example 1 You want to list all Logstores of a project named ali-test-project. In this case, you can send the following GET request:
GET /logstores?logstoreName=&offset=0&size=1000 HTTP/1.1 Date: Mon, 09 Nov 2015 06:11:16 GMT Host: ali-test-project.cn-hangzhou.log.aliyuncs.com x-log-apiversion: 0.6.0 x-log-bodyrawsize:0 x-log-signaturemethod: hmac-sha1
The following signature string is generated for the preceding API request:GET\n\n\nMon, 09 Nov 2015 06:11:16 GMT\nx-log-apiversion:0.6.0\x-log-bodyrawsize:0\nx-log-signaturemethod:hmac-sha1\n/logstores?logstoreName=&offset=0&size=1000
The GET request does not contain an HTTP request body. The values of the Content-MD5 and Content-Type fields are empty strings. The following string is the digital signature that is calculated by using the specified AccessKey secret:jEYOTCJs2e88o+y5F4/S5I****
The following request is a signed API request:GET /logstores?logstoreName=&offset=0&size=1000 HTTP/1.1 Date: Mon, 09 Nov 2015 06:11:16 GMT Host: ali-test-project.cn-hangzhou.log.aliyuncs.com x-log-apiversion: 0.6.0 x-log-bodyrawsize:0 x-log-signaturemethod: hmac-sha1 Authorization: LOG bq2sjzesjmo86kq35behupbq:jEYOTCJs2e88o+y5F4/S5I****
- Example 2 You want to write the following log to a Logstore named test-logstore, which belongs to the ali-test-project project:
topic="" time=1447048976 source="10.10.10.1" "TestKey": "TestContent"
In this case, you can send the following HTTP request:POST /logstores/test-logstore HTTP/1.1 Date: Mon, 09 Nov 2015 06:03:03 GMT Host: ali-test-project.cn-hangzhou.log.aliyuncs.com x-log-apiversion:0.6.0 x-log-bodyrawsize:50 x-log-signaturemethod:hmac-sha1 Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494 Content-Length: 52 <The log is serialized to byte streams in the ProtoBuffer format.>
The log that you want to write to Log Service is serialized into byte streams in the ProtoBuffer format, and then used as the HTTP request body. For more information about the ProtoBuffer format, see Data encoding. In this case, the value of the Content-Type header field is application/x-protobuf. The value of the Content-MD5 header field is the MD5 hash of the HTTP request body. The following string is the string to be signed that is generated for the API request:POST\n1DD45FA4A70A9300CC9FE7305AF2C494\napplication/x-protobuf\nMon, 09 Nov 2015 06:03:03 GMT\nx-log-apiversion:0.6.0\nx-log-bodyrawsize:50\nx-log-compresstype:lz4\nx-log-signaturemethod:hmac-sha1\n/logstores/ali-test-logstore
The following string is the digital signature that is calculated by using the specified AccessKey secret:XWLGYHGg2F2hcfxWxMLiNk****
The following request is a signed API request:POST /logstores/ali-test-logstore HTTP/1.1 Date: Mon, 09 Nov 2015 06:03:03 GMT Host: ali-test-project.cn-hangzhou.log.aliyuncs.com x-log-apiversion:0.6.0 x-log-bodyrawsize:50 x-log-compresstype:lz4 x-log-signaturemethod:hmac-sha1 Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494 Content-Length: 52 Authorization: LOG bq2sjzesjmo86kq35behupbq:XWLGYHGg2F2hcfxWxMLiNk**** <The log is serialized into byte streams in the ProtoBuffer format.>
Sample code
- Sample code of a Java signatureThe following sample code uses the
commons-codec
third-party library. Add the following Maven dependency topom.xml
:
The following sample code is used to sign an API request and is for reference only:<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.15</version> </dependency>
package com.aliyun.openservices.log.http.signer; import org.apache.commons.codec.binary.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; public class v1 { public static String md5(byte[] bs) throws Exception { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(bs); String hex = new BigInteger(1, digest.digest()).toString(16).toUpperCase(); return new String(new char[32 - hex.length()]).replace("\0", "0") + hex; } public static String getDateString() { DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); df.setTimeZone(new SimpleTimeZone(0, "GMT")); return df.format(new Date()); } public static void sign(String method, String uri, String accessKeyId, String accessKeySecret, Map<String, String> params, Map<String, String> headers, byte[] body) throws Exception { int contentLength = 0; String contentMD5 = "", message = ""; headers.put("x-log-apiversion", "0.6.0"); headers.put("x-log-signaturemethod", "hmac-sha1"); if (body != null && body.length > 0) { contentLength = body.length; contentMD5 = md5(body); headers.put("Content-MD5", contentMD5); } String date = getDateString(); headers.put("Date", date); headers.put("Content-Length", String.valueOf(contentLength)); message += method + "\n" + contentMD5 + "\n" + headers.getOrDefault("Content-Type", "") + "\n" + date + "\n"; // header String headerStr = headers.entrySet().stream() .filter(e -> e.getKey().startsWith("x-log-") || e.getKey().startsWith("x-acs-")) .sorted(Map.Entry.comparingByKey()) .map(e -> String.format("%s:%s\n", e.getKey(), e.getValue())) .collect(Collectors.joining("")); message += headerStr; // uri & params message += uri; if (params.size() > 0) { message += "?"; } message += params.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .map(e -> String.format("%s=%s", e.getKey(), e.getValue())) .collect(Collectors.joining("&")); // signature & authorization Mac mac = Mac.getInstance("HmacSHA1"); mac.init(new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1")); String signature = new String(Base64.encodeBase64(mac.doFinal(message.getBytes(StandardCharsets.UTF_8)))); String auth = "LOG " + accessKeyId + ":" + signature; headers.put("Authorization", auth); } }
- Sample code of a Python signatureThe following sample code is used to sign an API request and is for reference only:
import base64 import hashlib import hmac import locale from datetime import datetime from typing import Dict, Tuple def get_date(): try: locale.setlocale(locale.LC_TIME, "C") except Exception as ex: pass return datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') def sign(method: str, uri: str, access_key_id: str, access_key_secret: str, params: Dict[str, str], headers: Dict[str, str], body: bytes): content_length = 0 content_md5, message = '', '' headers["x-log-apiversion"] = "0.6.0" headers["x-log-signaturemethod"] = "hmac-sha1" if body is not None and len(body) > 0: content_length = len(body) content_md5 = hashlib.md5(body).hexdigest().upper() headers['Content-MD5'] = content_md5 date = get_date() headers['Date'] = date headers['Content-Length'] = content_length content_type = headers.get('Content-Type', '') message += method + "\n" + content_md5 + \ "\n" + content_type + "\n" + date + "\n" # header filter_by_prefix = lambda t: t[0].startswith('x-log-') or t[0].startswith('x-acs-') slsHeaders = list(filter(filter_by_prefix, headers.items())) sort_by_key = lambda k: k[0] for [k, v] in sorted(slsHeaders, key=sort_by_key): message += k + ':' + v + "\n" # uri and params message += uri message += '?' if len(params) > 0 else '' sep = '' for [k, v] in sorted(params.items(), key=sort_by_key): message += sep + k + '=' + v sep = '&' # signature and authorization hashed = hmac.new(access_key_secret.encode('utf8'), message.encode('utf8'), hashlib.sha1).digest() signature = base64.encodebytes(hashed).decode('utf8').rstrip() auth = f'LOG {access_key_id}:{signature}' headers['Authorization'] = auth
- Sample code of a PHP signatureThe following sample code is used to sign an API request and is for reference only:
<?php // returns new headers array function sign($method, $uri, $accessKeyId, $accessKeySecret, $params, $headers, $body) { $contentLength = 0; $headers["x-log-apiversion"] = "0.6.0"; $headers["x-log-signaturemethod"] = "hmac-sha1"; if (!is_null($body) && strlen($body) > 0) { $contentLength = strlen($body); $contentMd5 = strtoupper(md5($body)); $headers["Content-MD5"] = $contentMd5; } // date setLocale(LC_TIME, 'en_US'); $date = gmdate('D, d M Y H:i:s \G\M\T', time()); $headers["Date"] = $date; $headers["Content-Length"] = (string)$contentLength; $contentType = isset($headers['Content-Type']) ? $headers['Content-Type'] : ''; $message = $method . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n"; // header $filterHeaders = []; foreach ($headers as $key => $val) { if (str_starts_with($key, 'x-log-') || str_starts_with($key, 'x-acs-')) { $filterHeaders[$key] = $val; } } ksort($filterHeaders); foreach ($filterHeaders as $key => $val) { $message .= $key . ':' . $val . "\n"; } // uri and params $message .= $uri; if (sizeof($params) > 0) { $message .= '?'; } ksort($params); $sep = ''; foreach ($params as $key => $val) { $message .= $sep . $key . '=' . $val; $sep = '&'; } // signature & authorization $signature = base64_encode(hash_hmac('sha1', $message, $accessKeySecret, TRUE)); $auth = 'LOG ' . $accessKeyId . ':' . $signature; $headers['Authorization'] = $auth; return $headers; }; // example call $headers = sign( 'POST', '/logstores/test-logstore', 'testAccessId', 'testAccessKey', array( "test" => "test", "hello" => "world" ), array( "x-log-signaturemethod" => "hmac-sha1", "x-log-bodyrawsize" => "0", "x-log-apiversion" => "0.6.0" ), 'hello, world' ); echo ($headers['Authorization']); foreach ($headers as $key => $val) { echo ($key . '=' . $val . "\n"); } ?>
- Sample code of a Go signatureThe following sample code is used to sign an API request and is for reference only:
package sls import ( "crypto/hmac" "crypto/md5" "crypto/sha1" "encoding/base64" "fmt" "sort" "strconv" "strings" "time" ) /* * @param uri The uri of http request, exclude host and query param, eg: /logstores/test-logstore * @param headers This function modifies headers, headers must not be a nil map * @param method Http method in uppercase , eg: GET, POST, PUT, DELETE */ func Sign(method, uri, accessKeyID, accessKeySecret string, headers, queryParams map[string]string, body []byte) error { var message, signature string var contentMD5, contentType, date string headers["x-log-apiversion"] = "0.6.0"; headers["x-log-signaturemethod"] = "hmac-sha1"; if len(body) > 0 { contentMD5 = fmt.Sprintf("%X", md5.Sum(body)) headers["Content-MD5"] = contentMD5 } date = time.Now().In(time.FixedZone("GMT", 0)).Format(time.RFC1123) headers["Date"] = date headers["Content-Length"] = strconv.Itoa(len(body)) if val, ok := headers["Content-Type"]; ok { contentType = val } message += method + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n" // header slsHeaders := make(map[string]string) for k, v := range headers { if strings.HasPrefix(k, "x-log-") || strings.HasPrefix(k, "x-acs-") { slsHeaders[k] = v } } forEachInOrder(slsHeaders, func(k, v string) { message += k + ":" + v + "\n" }) message += uri if len(queryParams) > 0 { message += "?" } sep := "" forEachInOrder(queryParams, func(k, v string) { message += sep + k + "=" + v sep = "&" }) // Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret)) mac := hmac.New(sha1.New, []byte(accessKeySecret)) _, err := mac.Write([]byte(message)) if err != nil { return err } signature = base64.StdEncoding.EncodeToString(mac.Sum(nil)) auth := fmt.Sprintf("LOG %v:%v", accessKeyID, signature) headers["Authorization"] = auth return nil } func forEachInOrder(m map[string]string, f func(k, v string)) { var ss sort.StringSlice for k := range m { ss = append(ss, k) } ss.Sort() for _, k := range ss { f(k, m[k]) } }
- Sample code of a C# signatureThe following sample code is used to sign an API request and is for reference only:
using System.Security.Cryptography; using System.Text; using StringMap = System.Collections.Generic.Dictionary<string, string>; void sign(string method, string uri, string accessKeyId, string accessKeySecret, StringMap queryParams, StringMap headers, byte[] body ) { int contentLength = 0; string contentMd5 = "", message = ""; headers["x-log-apiversion"] = "0.6.0"; headers["x-log-signaturemethod"] = "hmac-sha1"; if (body != null && body.Length > 0) { contentLength = body.Length; contentMd5 = BitConverter.ToString(MD5.Create().ComputeHash(body)).Replace("-", ""); Console.WriteLine(contentMd5); headers["Content-MD5"] = contentMd5; } string date = DateTime.Now.ToUniversalTime().ToString("R"); headers["Date"] = date; headers["Content-Length"] = contentLength.ToString(); message += method + "\n" + contentMd5 + "\n" + headers.GetValueOrDefault("Content-Type", "") + "\n" + date + "\n"; var sortedHeader = from entry in headers orderby entry. Key ascending select entry; // header foreach (var entry in sortedHeader) { if (entry.Key.StartsWith("x-log-") || entry.Key.StartsWith("x-acs-")) { message += entry.Key + ":" + entry.Value + "\n"; } } // url & params message += uri; if (queryParams.Count() > 0) { message += "?"; } var sortedParam = from entry in queryParams orderby entry. Key ascending select entry; string sep = ""; foreach (var entry in sortedParam) { message += sep + entry.Key + "=" + entry.Value; sep = "&"; } var hmac = new HMACSHA1(Encoding.ASCII.GetBytes(accessKeySecret)); var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(message))); var auth = "LOG " + accessKeyId + ":" + signature; headers["Authorization"] = auth; }
- Sample code of a C++ signatureThe following sample code is used to sign an API request. You must implement the helper functions in the code based on your business requirements. The adapter.h header file in the sample code belongs to Log Service SDK for C++. We recommend that you sign the request based on Log Service SDK for C++. For more information, see Get started with Log Service SDK for C++.
- CodecTool::CalcMD5(string): calculates the MD5 hash value and converts the value to a hexadecimal string that contains only uppercase letters.
- CodecTool::StartWith(string, string): checks whether the string starts with another string.
- CodecTool::Base64Enconde(string): encodes the string in Base64.
- CodecTool::CalcHMACSHA1(string, string): uses the HMAC-SHA1 algorithm to calculate a hash value.
- CodecTool::GetDateString(): obtains the formatted string of the current time. Format:
%a, %d %b %Y %H:%M:%S GMT
. Example: Mon,3 Jan 2010 08:33:47 GMT.
#include <map> #include <string> #include <unordered_map> #include <unordered_set> #include <vector> #include "adapter.h" using namespace std; using aliyun_log_sdk_v6::CodecTool; void Sign(const string& httpMethod, const string& uri, map<string, string>& httpHeaders, const map<string, string>& urlParams, const string& body, const string& accessKeyId, const string& accessKeySecret) { string message; string contentMd5, signature, contentType; httpHeaders["x-log-apiversion"] = "0.6.0"; httpHeaders["x-log-signaturemethod"] = "hmac-sha1"; // 1. Content-Md5 if (!body.empty()) { contentMd5 = CodecTool::CalcMD5(body); httpHeaders["Content-Md5"] = contentMd5; } // 2. Date string dateTime = CodecTool::GetDateString(); httpHeaders["Date"] = dateTime; // 3. Content-Length string contentLength = std::to_string(body.size()); httpHeaders["Content-Length"] = contentLength; // 4. Content-Type if (httpHeaders.find("Content-Type") != httpHeaders.end()) { contentType = httpHeaders["Content-Type"]; } message.append(httpMethod).append("\n"); message.append(contentMd5).append("\n"); message.append(contentType).append("\n"); message.append(dateTime).append("\n"); // 5. header map<string, string> filteredHeaders; for (auto it : httpHeaders) { string key = it.first, value = it.second; if (CodecTool::StartWith(key, "x-log-") || CodecTool::StartWith(key, "x-acs-")) { filteredHeaders[key] = value; } } for (auto it : filteredHeaders) { message.append(it.first).append(":").append(it.second); message.append("\n"); } // 6. uri and url params message.append(uri); if (urlParams.size() > 0) message.append("?"); for (auto it = urlParams.begin(); it != urlParams.end(); ++it) { if (it != urlParams.begin()) { message.append("&"); } message.append(it->first).append("=").append(it->second); } // 7.Signature signature = CodecTool::Base64Enconde( CodecTool::CalcHMACSHA1(message, accessKeySecret)); // 8. authorization httpHeaders["authorization"] = "LOG " + accessKeyId + ':' + signature; }
- Sample code of a TypeScript signatureThe following sample code uses the
crypto-js
third-party library. Run the following command to install the dependency:
The following sample code is used to sign an API request and is for reference only:npm install crypto-js --save
import CryptoJS from 'crypto-js' export function sign( method: string, uri: string, access_key_id: string, access_key_secret: string, params: Map<string, string>, headers: Map<string, string>, body: string | undefined ) { let content_length = 0 let content_md5 = '', message = '' headers.set("x-log-apiversion", "0.6.0") headers.set("x-log-signaturemethod", "hmac-sha1") if (body !== undefined && body.length > 0) { content_length = body.length content_md5 = CryptoJS.MD5(body).toString(CryptoJS.enc.Hex).toUpperCase() headers.set('Content-MD5', content_md5) } const date = new Date().toUTCString() headers.set('Date', date) headers.set('Content-Length', content_length.toString()) message += method + '\n' + content_md5 + '\n' + (headers.get('Content-Type') ?? '') + '\n' + date + '\n' // headers const sort_by_key = (a: [string, string], b: [string, string]) => a[0].localeCompare(b[0]) const filter_by_prefix = (e: [string, string]) => e[0].startsWith('x-log-') || e[0].startsWith('x-acs-') const header_str = [...headers.entries()] .filter(filter_by_prefix) .sort(sort_by_key) .map((e) => e[0] + ':' + e[1] + '\n') .join('') message += header_str // uri & query params message += uri if (params.size > 0) { message += '?' } message += [...params.entries()] .sort(sort_by_key) .map((e) => e[0] + '=' + e[1]) .join('&') // signature & authorization const signature = CryptoJS.HmacSHA1(message, access_key_secret).toString( CryptoJS.enc.Base64 ) const auth = 'LOG ' + access_key_id + ':' + signature headers.set('Authorization', auth) } // example call sign( 'POST', '/logstores/test-logstore', 'testAccessId', 'testAccessKey', new Map<string, string>([ ['test', 'test'], ['hello', 'world'], ]), new Map<string, string>([ ['x-log-signaturemethod', 'hmac-sha1'], ['x-log-bodyrawsize', '0'], ['x-log-apiversion', '0.6.0'], ['Content-Type', 'application/json'], ]), 'hello, world' )
- Sample code of a Rust signatureThe following section shows the names and versions of the dependency libraries:
The following sample code is used to sign an API request and is for reference only:[dependencies] chrono = "0.4.19" md5 = "0.7.0" base64 = "0.13.0" hmac-sha1 = "0.1.3"
extern crate base64; extern crate hmacsha1; extern crate md5; use chrono::Utc; use std::collections::*; pub fn sign( method: &str, uri: &str, access_key_id: &str, access_key_secret: &str, params: &HashMap<String, String>, headers: &mut HashMap<String, String>, body: Option<Vec<u8>>, ) -> String { let mut content_length = 0; let mut content_md5 = String::from(""); headers.insert("x-log-apiversion".to_owned(), "0.6.0".to_owned()); headers.insert("x-log-signaturemethod".to_owned(), "hmac-sha1".to_owned()); if let Some(content) = body { if content.len() > 0 { content_length = content.len(); content_md5 = format!("{:X}", md5::compute(content)); headers.insert("Content-MD5".to_owned(), content_md5.clone()); } } headers.insert("Content-Length".to_owned(), content_length.to_string()); // date let date = Utc::now().format("%a, %d %b %Y %H:%M:%S GMT").to_string(); headers.insert("Date".to_owned(), date.clone()); let mut message = "".to_owned(); let content_type = headers .get(&"Content-Type".to_owned()) .cloned() .unwrap_or(String::from("")); message += format!("{}\n{}\n{}\n{}\n", method, content_md5, content_type, date).as_str(); // header let mut sorted_header: Vec<_> = headers.iter().collect(); sorted_header.sort_by_key(|x| x.0); for (k, v) in sorted_header { if k.starts_with("x-log-") || k.starts_with("x-acs-") { message += format!("{}:{}\n", k, v).as_str(); } } // url & params message += uri; if params.len() > 0 { message += "?"; } let mut sorted_params: Vec<_> = params.iter().collect(); sorted_params.sort_by_key(|x| x.0); let mut sep = ""; for (k, v) in sorted_params { message += format!("{}{}={}", sep, k, v).as_str(); sep = "&"; } let signature = base64::encode(hmacsha1::hmac_sha1( access_key_secret.as_bytes(), message.as_bytes(), )); let auth = format!("LOG {}:{}", access_key_id, signature); headers.insert("Authorization".to_owned(), auth.to_owned()); auth }