So we want to use a webapi that is build in ASP.net and uses OData as protocol. I did some homework and saw that Microsoft has a very good documenten OData Connected Service
. The only thing I can't find is that the webapi we want to use has a HMAC for security. I cannot find an example where the OData Connected Service
is used with HMAC. Could someone explain if and how HMAC is possible with the OData Connected Service
?

- 323
- 3
- 20
1 Answers
Probably the answer depends on the specific implementation of the HMAC on the server side.
If server receives all the data included in the request along with the Authorization header and extracts the values (APP Id, Signature, Nonce and Request Time stamp) from the Authorization header, then client should:
Build a string by combining all the data that will be sent, this string contains the following parameters (APP Id, HTTP method, request URI, request time stamp, nonce, and Base 64 string representation of the request pay load).
The signature will be sent in the Authorization header using a custom scheme such as ”amx”. The data in the Authorization header will contain the APP Id, request time stamp, and nonce separated by colon ‘:’. The format for the Authorization header will be like: [Authorization: amx APPId:Signature:Nonce:Timestamp].
Client send the request as usual along with the generated data in the Authorization header (just use client hooks or httpclient).
Example (after generating client code):
private string APPId = "65d3a4f0-0239-404c-8394-21b94ff50604";
private string APIKey = "WLUEWeL3so2hdHhHM5ZYnvzsOUBzSGH4+T3EgrQ91KI=";
public async Task<IEnumerable<string>> TestODataHMAC()
{
// add there your OData Uri
var container = new DefaultContainer(new Uri("https://services.odata.org/V4/(S(qc322lduoxrqt13nhydbdcvx))/TripPinServiceRW/"));
container.Configurations.RequestPipeline.OnMessageCreating = (args) =>
{
var request = new HttpWebRequestMessage(args);
// Get the Request URI
string requestUri = HttpUtility.UrlEncode(request.Url.AbsoluteUri.ToLower());
// Calculate UNIX time
var epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
var timeSpan = DateTime.UtcNow - epochStart;
var requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString();
// Create the random nonce for each request
var nonce = Guid.NewGuid().ToString();
// Creating the raw signature string by combinging
// APPId, request Http Method, request Uri, request TimeStamp, nonce
var signatureRawData = string.Format("{0}{1}{2}{3}{4}", APPId, request.Method, requestUri, requestTimeStamp, nonce);
// Converting the APIKey into byte array
var secretKeyByteArray = Convert.FromBase64String(APIKey);
// Converting the signatureRawData into byte array
var signature = Encoding.UTF8.GetBytes(signatureRawData);
// Generate the hmac signature and set it in the Authorization header
using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray))
{
var signatureBytes = hmac.ComputeHash(signature);
var requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
//Setting the values in the Authorization header using custom scheme (hmacauth)
request.SetHeader("Authorization", string.Format("hmacauth {0}:{1}:{2}:{3}", APPId, requestSignatureBase64String, nonce, requestTimeStamp));
}
return request;
};
// add there your OData method call
var nquery = container.People.Where(p => p.Gender == PersonGender.Female).Take(10) as DataServiceQuery<Person>;
var response = await nquery?.ExecuteAsync();
return (response as QueryOperationResponse<Person>).Select(p => p.FirstName).ToArray();
}

- 11
- 2
-
Thanks for your reply! In this case a MD5 HASH of the content is also requested so how would one HASH the content/body in the `OnMessageCreating` ? – Gforse Oct 14 '19 at 10:40
-
At the moment, I do not know the right way to do this. Unless to somehow receive the body of the request before the call, and put it into `container.Configurations.RequestPipeline.OnMessageCreating`. Can you change server logic to avoid request body in the HMAC authorization header? Then you can use the HMAC without the request body in the client side. – unchase Nov 14 '19 at 11:19