Encoding/Encrypting node.js 中的 Azure Log Analytics 授权 Header

Encoding/Encrypting the Azure Log Analytics Authorization Header in node.js

我一直在尝试让日志收集器 API 在 node.js Azure 函数中工作,但卡在 403/Forbidden 错误上,这表明我没有形成授权 header 正确。完整代码位于此处的 github 存储库中:

https://github.com/sportsmgmt-labs/Azure-Log-Analytics-Node-Function

数据收集器 API 文档在此处:

https://docs.microsoft.com/en-us/azure/log-analytics/log-analytics-data-collector-api

授权header格式如下:

Authorization: SharedKey {WorkspaceID}:{Signature}

签名的地方encoded/encrypted是这样的:

Base64(HMAC-SHA256(UTF8(StringToSign)))

这是我创建授权的代码 header:

var contentLength = Buffer.byteLength(req.body['log-entry'], 'utf8');

var authorization = 'POST\n' + contentLength + '\napplication/json\nx-ms-date:' + processingDate + '\n/api/logs';

// encode string using Base64(HMAC-SHA256(UTF8(StringToSign)))
authorization = crypto.createHmac('sha256', sharedKey).update(authorization.toString('utf8')).digest('base64');

authorization = 'Authorization: SharedKey ' + workspaceId + ':' + authorization;

服务器的响应是:

{"Error":"InvalidAuthorization","Message":"An invalid scheme was specified in the Authorization header"}

有人可以帮我理解我做错了什么吗?谢谢!

编辑:这是执行此操作的 Python 代码:

def build_signature(customer_id, shared_key, date, content_length, method, content_type, resource):
    x_headers = 'x-ms-date:' + date
    string_to_hash = method + "\n" + str(content_length) + "\n" + content_type + "\n" + x_headers + "\n" + resource
    bytes_to_hash = bytes(string_to_hash).encode('utf-8')  
    decoded_key = base64.b64decode(shared_key)
    encoded_hash = base64.b64encode(hmac.new(decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest())
    authorization = "SharedKey {}:{}".format(customer_id,encoded_hash)
    return authorization

...和 ​​C# 代码:

    static void Main()
    {
        // Create a hash for the API signature
        var datestring = DateTime.UtcNow.ToString("r");
        string stringToHash = "POST\n" + json.Length + "\napplication/json\n" + "x-ms-date:" + datestring + "\n/api/logs";
        string hashedString = BuildSignature(stringToHash, sharedKey);
        string signature = "SharedKey " + customerId + ":" + hashedString;

        PostData(signature, datestring, json);
    }

    // Build the API signature
    public static string BuildSignature(string message, string secret)
    {
        var encoding = new System.Text.ASCIIEncoding();
        byte[] keyByte = Convert.FromBase64String(secret);
        byte[] messageBytes = encoding.GetBytes(message);
        using (var hmacsha256 = new HMACSHA256(keyByte))
        {
            byte[] hash = hmacsha256.ComputeHash(messageBytes);
            return Convert.ToBase64String(hash);
        }
    }

您需要先解码共享密钥。请尝试更改以下代码行:

authorization = crypto.createHmac('sha256', sharedKey).update(authorization.toString('utf8')).digest('base64');
authorization = 'Authorization: SharedKey ' + workspaceId + ':' + authorization;

至:

authorization = crypto.createHmac('sha256', new Buffer(sharedKey, 'base64')).update(authorization, 'utf-8').digest('base64');
var signature = 'SharedKey ' + workspaceId + ':' + authorization;

那么请求 header 将如下所示:

headers: {
    'content-type': 'application/json',
    'Authorization': signature,
    'Log-Type': <log_type>,
    'x-ms-date': processingDate
},

Node.js 代码示例

var request = require('request');
var crypto = require('crypto');

// Azure Log Analysis credentials
var workspaceId = 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
var sharedKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

var apiVersion = '2016-04-01';
var processingDate = new Date().toUTCString();

var jsonData = [{
   "slot_ID": 12345,
    "ID": "5cdad72f-c848-4df0-8aaa-ffe033e75d57",
    "availability_Value": 100,
    "performance_Value": 6.954,
    "measurement_Name": "last_one_hour",
    "duration": 3600,
    "warning_Threshold": 0,
    "critical_Threshold": 0,
    "IsActive": "true"
},
{   
    "slot_ID": 67890,
    "ID": "b6bee458-fb65-492e-996d-61c4d7fbb942",
    "availability_Value": 100,
    "performance_Value": 3.379,
    "measurement_Name": "last_one_hour",
    "duration": 3600,
    "warning_Threshold": 0,
    "critical_Threshold": 0,
    "IsActive": "false"
}]

var body = JSON.stringify(jsonData);    

var contentLength = Buffer.byteLength(body, 'utf8');

var stringToSign = 'POST\n' + contentLength + '\napplication/json\nx-ms-date:' + processingDate + '\n/api/logs';
var signature = crypto.createHmac('sha256', new Buffer(sharedKey, 'base64')).update(stringToSign, 'utf-8').digest('base64');
var authorization = 'SharedKey ' + workspaceId + ':' + signature;

var headers = {
    "content-type": "application/json", 
    "Authorization": authorization,
    "Log-Type": 'WebMonitorTest',
    "x-ms-date": processingDate
};

var url = 'https://' + workspaceId + '.ods.opinsights.azure.com/api/logs?api-version=' + apiVersion;

request.post({url: url, headers: headers, body: body}, function (error, response, body) {
  console.log('error:', error); 
  console.log('statusCode:', response && response.statusCode); 
  console.log('body:', body); 
});