I'm using .NET Core, so I can't use the Azure DocumentDb SDK. That is why I want to create a document via the REST interface. I've managed to query the database, but when I POST a JSON document, I get an Unauthorized response. This is my code:
const string DatabaseId = "DB-id";
const string CollectionId = "UserSettings";
var documentDbUrl = "Injected via DI";
var authorizationKey = "Also injected;
using (var httpClient = new HttpClient())
{
var utcNow = DateTime.UtcNow;
httpClient.DefaultRequestHeaders.Add("x-ms-date", utcNow.ToString("r"));
httpClient.DefaultRequestHeaders.Add("x-ms-version", "2015-08-06");
httpClient.DefaultRequestHeaders.Add("x-ms-documentdb-is-upsert", "true");
var resourceLink = string.Format("dbs/{0}/colls/{1}/docs", DatabaseId, CollectionId);
var baseUrl = new Uri(documentDbUrl);
var masterKeyAuthorizationSignatureGenerator = new MasterKeyAuthorizationSignatureGenerator();
var authHeader = masterKeyAuthorizationSignatureGenerator.Generate("POST", resourceLink, "docs", authorizationKey, "master", "1.0", utcNow);
httpClient.DefaultRequestHeaders.Add("authorization", authHeader);
var response = await httpClient.PostAsJsonAsync(new Uri(baseUrl, resourceLink), userSettings);
// at this point, response.StatusCode is Unauthorized
}
The MasterKeyAuthorizationSignatureGenerator you see there contains the logic to create the hash, which works when querying the database:
public string Generate(string verb, string resourceId, string resourceType, string key, string keyType, string tokenVersion, DateTime requestDateTime)
{
var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };
var payLoad = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}\n{1}\n{2}\n{3}\n{4}\n",
verb.ToLowerInvariant(),
resourceType.ToLowerInvariant(),
resourceId,
requestDateTime.ToString("r").ToLowerInvariant(),
""
);
var hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad));
var signature = Convert.ToBase64String(hashPayLoad);
return WebUtility.UrlEncode(string.Format(System.Globalization.CultureInfo.InvariantCulture, "type={0}&ver={1}&sig={2}",
keyType,
tokenVersion,
signature));
}
I'm sure the databaseid, collectionid, url and key are correct. The key and id's are the same I use to query, which works. And when I change the url, for example by adding the documentid (which I then generate myself), I get another message (MethodNotAllowed).
Update:
Using Postman, I can see this is the response I get:
{
"code": "Unauthorized",
"message": "The input authorization token can't serve the request.
Please check that the expected payload is built as per the
protocol, and check the key being used. Server used the
following payload to sign:
'post\ndocs\ndbs/MyDb/colls/MyColl\nsat, 23 apr 2016 09:44:39 gmt\n\n'\r\nActivityId: 1be76530-ad32-4b54-b96b-6e0d4ebbc851"
}
Any hints on what I'm doing wrong or how I can analyse this?