I am trying to call Azure Storage queue using REST API, but I am getting an error
The MAC signature found in the HTTP request
'UCiypkoySXueF4scXt+EqQESf5VXmAVLJUA93+3W10M=' is not the same as any
computed signature. The server used following string to sign: 'POST
text/plain
My C# Code is
var Client = new HttpClient();
var RequestDateString = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
if (Client.DefaultRequestHeaders.Contains("x-ms-date"))
Client.DefaultRequestHeaders.Remove("x-ms-date");
Client.DefaultRequestHeaders.Add("x-ms-date", RequestDateString);
var StorageAccountName = "storaxxxxxxxsnd";
var StorageKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==";
String urlPath = String.Format("{0}/messages", "splitator");
Uri uri = new Uri(string.Format("https://{0}.queue.core.windows.net/", StorageAccountName) + urlPath);
if (Client.DefaultRequestHeaders.Contains("Authorization"))
Client.DefaultRequestHeaders.Remove("Authorization");
var canonicalizedStringToBuild = string.Format("{0}\n{1}", RequestDateString, $"/{StorageAccountName}/{uri.AbsolutePath.TrimStart('/')}");
string signature;
using (var hmac = new HMACSHA256(Convert.FromBase64String(StorageKey)))
{
byte[] dataToHmac = Encoding.UTF8.GetBytes(canonicalizedStringToBuild);
signature = Convert.ToBase64String(hmac.ComputeHash(dataToHmac));
}
string authorizationHeader = string.Format($"{StorageAccountName}:" + signature);
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey", authorizationHeader);
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
if (Client.DefaultRequestHeaders.Contains("x-ms-version"))
Client.DefaultRequestHeaders.Remove("x-ms-version");
Client.DefaultRequestHeaders.Add("x-ms-version", "2015-12-11");
// if (httpMethod == HttpMethod.Delete || httpMethod == HttpMethod.Put)
// {
// if (Client.DefaultRequestHeaders.Contains("If-Match"))
// Client.DefaultRequestHeaders.Remove("If-Match");
// Currently I'm not using optimistic concurrency :-(
try
{
//Client.DefaultRequestHeaders.Add("If-Match", "*");
var stringContent = new StringContent("TESTAUTH", Encoding.UTF8, "text/plain");
var response= Client.PostAsync(uri, stringContent);
var resu=response.Result;
}
catch(Exception ex)
{
}
I am not sure what I am missing. I tried various combination but its failing.
I tried Microsoft recommended stringToSign formula too
I tried using canonical headers too
string signature;
var stringTosign = "POST\n" + "\n" + "\n" + "1024" + "\n" + "\n" + "text/plain\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + dateInRfc1123Format + "/xxxxxx/splitator/messages";
var hmac = new HMACSHA256(Convert.FromBase64String(accountKey));
var headerval= accountName + ":" + Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringTosign)));
Client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey", headerval);
Client.DefaultRequestHeaders.Accept.Clear();
I fixed the issue in your code, and now it's working. Please give it a try:
namespace ConsoleApp25
{
class Program
{
static void Main(string[] args)
{
var Client = new HttpClient();
var StorageAccountName = "yy1";
var StorageKey = "xxxx";
var apiversion = "2020-02-10";
var queue_name = "myqueue2";
String urlPath = String.Format("{0}/messages", queue_name);
Uri uri = new Uri(string.Format("https://{0}.queue.core.windows.net/{1}", StorageAccountName, urlPath));
//define a message to send
string raw_message = "TESTAUTH is ok";
//to send the message to the queue storage, the raw message must be formatted as below
string queue_message = $"<QueueMessage><MessageText>{raw_message}</MessageText></QueueMessage>";
//define the content type
string content_type = "text/plain; charset=utf-8";
//define date
var RequestDateString = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
string StringToSign = String.Format("POST\n"
+ "\n" // content encoding
+ "\n" // content language
+ queue_message.Length + "\n" // content length
+ "\n" // content md5
+ content_type +"\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "x-ms-date:" + RequestDateString + "\nx-ms-version:" + apiversion + "\n" // headers
+ "/{0}/{1}/{2}", StorageAccountName, queue_name, "messages"); //url
string auth = SignThis(StringToSign, StorageKey, StorageAccountName);
//define authorization header
if (Client.DefaultRequestHeaders.Contains("Authorization"))
Client.DefaultRequestHeaders.Remove("Authorization");
Client.DefaultRequestHeaders.Add("Authorization", auth);
Client.DefaultRequestHeaders.Accept.Clear();
//define x-ms-version header
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
if (Client.DefaultRequestHeaders.Contains("x-ms-version"))
Client.DefaultRequestHeaders.Remove("x-ms-version");
Client.DefaultRequestHeaders.Add("x-ms-version", apiversion);
//define the x-ms-date header
if (Client.DefaultRequestHeaders.Contains("x-ms-date"))
Client.DefaultRequestHeaders.Remove("x-ms-date");
Client.DefaultRequestHeaders.Add("x-ms-date", RequestDateString);
try
{
var stringContent = new StringContent(queue_message, Encoding.UTF8, "text/plain");
var response = Client.PostAsync(uri, stringContent);
var resu = response.Result;
}
catch (Exception ex)
{
}
Console.WriteLine("**completed**");
Console.ReadLine();
}
private static String SignThis(String StringToSign, string Key, string Account)
{
String signature = string.Empty;
byte[] unicodeKey = Convert.FromBase64String(Key);
using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(
CultureInfo.InvariantCulture,
"{0} {1}:{2}",
"SharedKey",
Account,
signature);
return authorizationHeader;
}
}
}
And if you don't want to generate the shared key since it's not easy, you can use sas token for authentication in the rest api.
Related
I want to translate single document from one language to another please guide me how to do that i have done translating all the files in azure blob storage but not able to find to translate single file.
please find below code and let me know the changes.
string _FileName = Path.GetFileName(file.FileName);
fileName = _FileName;
string _path = Path.Combine(Server.MapPath("~/UploadedFiles"), _FileName);
file.SaveAs(_path);
string route = "/batches";
string endpoint = "https://translator.cognitiveservices.azure.com/translator/text/batch/v1.0";
string filePath = UploadToAzureStorageAccount.UploadDocument(_path, "uploadeddocs");
string subscriptionKey = "key";
string json = ("" +
"{\"inputs\": " +
"[{\"storageType\": \"File\","+"\"source\": " +
"{\"sourceUrl\": \"https://cdposticketsstorage.blob.core.windows.net/uploadeddocs/test.docx?sp=r&st=2022-03-08T08:13:18Z&se=2022-03-08T16:13:18Z&spr=https&sv=2020-08-04&sr=b&sig=Pt68ogFCj6WSgEBUWI95YJ4GudOcyhEW1cgVXmFCing%3D\"," +
"\"storageSource\": \"AzureBlob\"" +
"}," +
"\"targets\": " +
"[{\"targetUrl\": \"https://cdposticketsstorage.blob.core.windows.net/translateddocs/translate.docx?sp=rcw&st=2022-03-08T11:15:45Z&se=2022-03-08T19:15:45Z&spr=https&sv=2020-08-04&sr=b&sig=QM2FhLxOIE%2FLjeLLfYyR2PmfkNb3nm70wZdCveSJC0M%3D\"," +
"\"storageSource\": \"AzureBlob\"," +
"\"language\": \"fr\"}]}]}");
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(endpoint + route);
request.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
request.Content = content;
HttpResponseMessage response = await client.SendAsync(request);
string result = response.Content.ReadAsStringAsync().Result;
if (response.IsSuccessStatusCode)
{
Console.WriteLine($"Status code: {response.StatusCode}");
Console.WriteLine();
Console.WriteLine($"Response Headers:");
Console.WriteLine(response.Headers);
}
else
Console.Write("Error");
}
// TextTranslatorAPI client = new TextTranslatorAPI();
//string res = await client.DocumentTranslator(fileName);
//return res;
}
ViewBag.Message = "File Uploaded Successfully!!";
}
catch(Exception e)
{
ViewBag.Message = "File upload failed!!";
}
I am trying to make a put request to Azure storage file, where I want to add some simple contents. I change the URL and add ?comp=range at the end of the url but I get 403 error in response. I have created a basic console application in .net.
My Header is :
const string requestMethod = "PUT";
string urlPath = strShareName + "/" + "rahila.csv?comp=range";//+ "?comp=range HTTP/1.1";
String canonicalizedResource = String.Format("/{0}/{1}/{2}", StorageAccountName, strShareName, strFileName);
try
{
//GetWebRequest(requestMethod, urlPath, canonicalizedResource, "CreateFile");
HttpWebRequest request = null;
try
{
const string type = "file";
string MethodType = "CreateFile";
const string msVersion = "2015-04-05";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
String canonicalizedHeaders = "";
string data = "rahila sted";
canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}", dateInRfc1123Format, msVersion);
if (MethodType == "CreateFile")
{
canonicalizedHeaders = String.Format("x-ms-content-length:65536\nx-ms-date:{0}\nx-ms-type:file\nx-ms-version:{1}", dateInRfc1123Format, msVersion);
}
String stringToSign = "";
stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, canonicalizedResource);
if (String.IsNullOrEmpty(stringToSign))
{
throw new ArgumentNullException("canonicalizedString");
}
String signature;
if (String.IsNullOrEmpty(stringToSign))
{
throw new ArgumentNullException("unsignedString");
}
if (Convert.FromBase64String(StorageKey) == null)
{
throw new ArgumentNullException("key");
}
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(stringToSign);
using (HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String(StorageKey)))
{
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}",
StorageScheme,
StorageAccountName, signature);
Uri uri = new Uri(FileEndPoint + urlPath);
request = (HttpWebRequest)WebRequest.Create(uri);
if (requestMethod != "Get")
{
request.ContentLength = data.Length;
}
// string data = "Hello testing";
//int a= ((data.Length) + 1);
request.Method = "PUT";//requestMethod;
request.Headers.Add("x-ms-write", "update");
request.Headers.Add("x-ms-date", dateInRfc1123Format);
request.Headers.Add("x-ms-version", msVersion);
request.Headers.Add("x-ms-range", "bytes=0-65535"); // + ((data.Length) - 1));
request.Headers.Add("Authorization", authorizationHeader);
the line where i get the exception is in the bold format.
HttpWebResponse response = null;
response = (HttpWebResponse)request.GetResponse();
string returnString = response.StatusCode.ToString();
Can anyone help me to resolve this issue or just guide me how to write content to a simple file on azure storage without using the azure client API.
update 12/19:
When using Put Range to upload content to azure file, you can follow the following code(I assume you have already created a file on the azure file share, and it's content length is larger than the content being uploaded):
static void UploadText()
{
string Account = "xxxx";
string Key = "xxxx";
string FileShare = "test1";
string FileName = "11.txt";
string apiversion = "2019-02-02";
//the string to be uploaded to azure file, note that the length of the uploaded string should less than the azure file length
string upload_text = "bbbbbbbbbbbbbbbbbbbbbbbb.";
Console.WriteLine("the string length: " + upload_text.Length);
DateTime dt = DateTime.UtcNow;
string StringToSign = String.Format("PUT\n"
+ "\n" // content encoding
+ "\n" // content language
+ upload_text.Length + "\n" // content length
+ "\n" // content md5
+ "\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n"//+ "bytes=0-" + (upload_text.Length - 1) + "\n" // range
+"x-ms-date:" + dt.ToString("R") + "\nx-ms-range:bytes=0-"+(upload_text.Length-1) + "\nx-ms-version:" + apiversion + "\nx-ms-write:update\n" // headers
+ "/{0}/{1}/{2}\ncomp:range", Account, FileShare, FileName);
string auth = SignThis(StringToSign, Key, Account);
string method = "PUT";
string urlPath = string.Format("https://{0}.file.core.windows.net/{1}/{2}?comp=range", Account, FileShare,FileName);
Uri uri = new Uri(urlPath);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = method;
request.ContentLength = upload_text.Length;
request.Headers.Add("x-ms-range", "bytes=0-"+(upload_text.Length-1));
request.Headers.Add("x-ms-write", "update");
request.Headers.Add("x-ms-date", dt.ToString("R"));
request.Headers.Add("x-ms-version", apiversion);
request.Headers.Add("Authorization", auth);
//request.Headers.Add("Content-Length", upload_text.Length.ToString());
var bytes = System.Text.Encoding.ASCII.GetBytes(upload_text);
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
//read the content
Console.WriteLine("the response is:" + response.StatusCode);
}
}
private static String SignThis(String StringToSign, string Key, string Account)
{
String signature = string.Empty;
byte[] unicodeKey = Convert.FromBase64String(Key);
using (HMACSHA256 hmacSha256 = new HMACSHA256(unicodeKey))
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(
CultureInfo.InvariantCulture,
"{0} {1}:{2}",
"SharedKey",
Account,
signature);
return authorizationHeader;
}
Then in the Main() method, you can call UploadText() method, it works at my side.
old:
guide me how to write content to a simple file on azure storage
without using the azure client API.
For this, you can directly use Azure File Storage SDK Microsoft.Azure.Storage.File, version 11.1.1. And we always recommend using SDK instead of using rest api, because the SDK is easy to use.
Here is an example of using this SDK.
First, create a console project of .NET framework in visual studio. Then install this nuget package Microsoft.Azure.Storage.File, version 11.1.1.
The code:
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Auth;
using Microsoft.Azure.Storage.File;
using System;
namespace AzureFileTest2
{
class Program
{
static void Main(string[] args)
{
string accountName = "xxx";
string accountKey = "xxx";
CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
CloudFileClient cloudFileClient = storageAccount.CreateCloudFileClient();
//make sure the file share named test1 exists.
CloudFileShare fileShare = cloudFileClient.GetShareReference("test1");
CloudFileDirectory fileDirectory = fileShare.GetRootDirectoryReference();
CloudFile myfile = fileDirectory.GetFileReference("test123.txt");
if (!myfile.Exists())
{
//if the file does not exists, then create the file and set the file max size to 100kb.
myfile.Create(100 * 1024 * 1024);
}
//upload text to the file
//Besides using UploadText() method to directly upload text, you can also use UploadFromFile() / UploadFromByteArray() / UploadFromStream() methods as per your need.
myfile.UploadText("hello, it is using azure storage SDK");
Console.WriteLine("**completed**");
Console.ReadLine();
}
}
}
I'm trying to connect to the Bricklink REST API using OAuth (http://apidev.bricklink.com/redmine/projects/bricklink-api/wiki/Authorization).
It should be pretty straight forward. However, I'm currently stuck and keep getting a SIGNATURE_INVALID error. My current attempt is shown below. Any suggestions?
const string consumerKey = "";
const string consumerSecret = "";
const string tokenSecret = "";
const string tokenValue = "";
const string url = "https://api.bricklink.com/api/store/v1/items/part/3001";
var httpWebRequest = (HttpWebRequest) WebRequest.Create(url);
httpWebRequest.Method = "GET";
var timeStamp = ((int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
var nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(timeStamp));
var signatureBaseString = httpWebRequest.Method.ToUpper() + "&";
signatureBaseString = signatureBaseString + url.ToLower() + "&";
signatureBaseString = signatureBaseString + "oauth_consumer_key=" + consumerKey + "&";
signatureBaseString = signatureBaseString + "oauth_nonce=" + nonce + "&";
signatureBaseString = signatureBaseString + "oauth_signature_method=" + "HMAC-SHA1" + "&";
signatureBaseString = signatureBaseString + "oauth_timestamp=" + timeStamp + "&";
signatureBaseString = signatureBaseString + "oauth_token=" + tokenValue + "&";
signatureBaseString = signatureBaseString + "oauth_version=" + "1.0";
signatureBaseString = Uri.EscapeDataString(signatureBaseString);
Console.WriteLine(signatureBaseString);
var signatureEncoding = new ASCIIEncoding();
var keyBytes = signatureEncoding.GetBytes(consumerSecret + "&" + tokenSecret);
var signatureBaseBytes = signatureEncoding.GetBytes(signatureBaseString);
string signatureString;
using (var hmacsha1 = new HMACSHA1(keyBytes))
{
var hashBytes = hmacsha1.ComputeHash(signatureBaseBytes);
signatureString = Convert.ToBase64String(hashBytes);
}
signatureString = Uri.EscapeDataString(signatureString);
Console.WriteLine(signatureString);
string SimpleQuote(string x) => '"' + x + '"';
var header =
"OAuth realm=" + SimpleQuote("") + "," +
"oauth_consumer_key=" + SimpleQuote(consumerKey) + "," +
"oauth_nonce=" + SimpleQuote(nonce) + "," +
"oauth_signature_method=" + SimpleQuote("HMAC-SHA1") + "," +
"oauth_timestamp=" + SimpleQuote(timeStamp) + "," +
"oauth_token=" + SimpleQuote(tokenValue) + "," +
"oauth_version=" + SimpleQuote("1.0") + "," +
"oauth_signature= " + SimpleQuote(signatureString);
Console.WriteLine(header);
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, header);
var response = httpWebRequest.GetResponse();
var characterSet = ((HttpWebResponse) response).CharacterSet;
var responseEncoding = characterSet == ""
? Encoding.UTF8
: Encoding.GetEncoding(characterSet ?? "utf-8");
var responsestream = response.GetResponseStream();
if (responsestream == null)
{
throw new ArgumentNullException(nameof(characterSet));
}
using (responsestream)
{
var reader = new StreamReader(responsestream, responseEncoding);
var result = reader.ReadToEnd();
Console.WriteLine(result);
}
I know that consumerKey, consumerSecret, tokenSecret, and tokenValue are correct as I can connect using the bricklink-api (https://www.npmjs.com/package/bricklink-api) using JavaScript.
After studying https://oauth.net/core/1.0/#signing_process again, I finally got it right. Note, the Escape function is not essential I just happened to stumble upon that one while trying to make things work.
const string consumerKey = "";
const string consumerSecret = "";
const string tokenSecret = "";
const string tokenValue = "";
const string url = "https://api.bricklink.com/api/store/v1/items/part/3001";
string Escape(string s)
{
// https://stackoverflow.com/questions/846487/how-to-get-uri-escapedatastring-to-comply-with-rfc-3986
var charsToEscape = new[] {"!", "*", "'", "(", ")"};
var escaped = new StringBuilder(Uri.EscapeDataString(s));
foreach (var t in charsToEscape)
{
escaped.Replace(t, Uri.HexEscape(t[0]));
}
return escaped.ToString();
}
var httpWebRequest = (HttpWebRequest) WebRequest.Create(url);
httpWebRequest.Method = "GET";
var timeStamp = ((int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
var nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(timeStamp));
var signatureBaseString = Escape(httpWebRequest.Method.ToUpper()) + "&";
signatureBaseString += EscapeUriDataStringRfc3986(url.ToLower()) + "&";
signatureBaseString += EscapeUriDataStringRfc3986(
"oauth_consumer_key=" + EscapeUriDataStringRfc3986(consumerKey) + "&" +
"oauth_nonce=" + EscapeUriDataStringRfc3986(nonce) + "&" +
"oauth_signature_method=" + EscapeUriDataStringRfc3986("HMAC-SHA1") + "&" +
"oauth_timestamp=" + EscapeUriDataStringRfc3986(timeStamp) + "&" +
"oauth_token=" + EscapeUriDataStringRfc3986(tokenValue) + "&" +
"oauth_version=" + EscapeUriDataStringRfc3986("1.0"));
Console.WriteLine(#"signatureBaseString: " + signatureBaseString);
var key = EscapeUriDataStringRfc3986(consumerSecret) + "&" + EscapeUriDataStringRfc3986(tokenSecret);
Console.WriteLine(#"key: " + key);
var signatureEncoding = new ASCIIEncoding();
var keyBytes = signatureEncoding.GetBytes(key);
var signatureBaseBytes = signatureEncoding.GetBytes(signatureBaseString);
string signatureString;
using (var hmacsha1 = new HMACSHA1(keyBytes))
{
var hashBytes = hmacsha1.ComputeHash(signatureBaseBytes);
signatureString = Convert.ToBase64String(hashBytes);
}
signatureString = EscapeUriDataStringRfc3986(signatureString);
Console.WriteLine(#"signatureString: " + signatureString);
string SimpleQuote(string s) => '"' + s + '"';
var header =
"OAuth realm=" + SimpleQuote("") + "," +
"oauth_consumer_key=" + SimpleQuote(consumerKey) + "," +
"oauth_nonce=" + SimpleQuote(nonce) + "," +
"oauth_signature_method=" + SimpleQuote("HMAC-SHA1") + "," +
"oauth_timestamp=" + SimpleQuote(timeStamp) + "," +
"oauth_token=" + SimpleQuote(tokenValue) + "," +
"oauth_version=" + SimpleQuote("1.0") + "," +
"oauth_signature= " + SimpleQuote(signatureString);
Console.WriteLine(#"header: " + header);
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, header);
var response = httpWebRequest.GetResponse();
var characterSet = ((HttpWebResponse) response).CharacterSet;
var responseEncoding = characterSet == ""
? Encoding.UTF8
: Encoding.GetEncoding(characterSet ?? "utf-8");
var responsestream = response.GetResponseStream();
if (responsestream == null)
{
throw new ArgumentNullException(nameof(characterSet));
}
using (responsestream)
{
var reader = new StreamReader(responsestream, responseEncoding);
var result = reader.ReadToEnd();
Console.WriteLine(#"result: " + result);
}
For anyone who is looking for way simpler solution. This works with WooCommerce and probably with other services. For WooCommerce token/tokenSecret is null.
var client = new RestClient($"{StoreHttp}/wp-json/wc/v3/products")
{
Authenticator = OAuth1Authenticator.ForProtectedResource(ConsumerKey, ConsumerSecret, token, tokenSecret)
};
var request = new RestRequest(Method.GET);
RestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
Example with: RestSharp version: 108.0.3
Do not need to write code for signature creation. RestSharp does it all for you.
using System;
using RestSharp;
using RestSharp.Authenticators;
using RestSharp.Authenticators.OAuth;
using Newtonsoft.Json;
var client = new RestClient(URL);
var oAuth1 = OAuth1Authenticator.ForAccessToken(
consumerKey: ConsumerKey,
consumerSecret: ConsumerSecret,
token: Token,
tokenSecret: TokenSecret,
OAuthSignatureMethod.HmacSha256);
oAuth1.Realm = Realm; // if Realm has otherwise ignore
client.Authenticator = oAuth1;
var request = new RestRequest(URL, Method.Post);
request.AddHeader("Content-Type", "application/json");
string body = JsonConvert.SerializeObject(bodyObject);
request.AddParameter("application/json", body, ParameterType.RequestBody);
var response = client.Execute(request);
I am using the following code to send out message to one of my other ids. Can someone please explain what am I missing here. Both accounts are followers to each other and the option is also enabled to receive direct messages from everyone.
private static void sendMessage(string message)
{
//The facebook json url to update the status
string facebookURL = "https://api.twitter.com/1.1/direct_messages/new.json?user_id=1699575980&screen_name=MuneebZulfee&text=some message";
//set the access tokens (REQUIRED)
string oauth_consumer_key = "**************************";
string oauth_consumer_secret = "***************************";
string oauth_token = "******************************";
string oauth_token_secret = "*****************************";
// set the oauth version and signature method
string oauth_version = "1.0";
string oauth_signature_method = "HMAC-SHA1";
// create unique request details
string oauth_nonce = Convert.ToBase64String(new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
System.TimeSpan timeSpan = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc));
string oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();
// create oauth signature
string baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}" + "&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&screen_name={6}&text={7}&user_id={8}";
string baseString = string.Format(
baseFormat,
oauth_consumer_key,
oauth_nonce,
oauth_signature_method,
oauth_timestamp, oauth_token,
oauth_version,
Uri.EscapeDataString("MuneebZulfee"),
Uri.EscapeDataString("some message"),
Uri.EscapeDataString("1699575980")
);
string oauth_signature = null;
using (HMACSHA1 hasher = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(Uri.EscapeDataString(oauth_consumer_secret) + "&" + Uri.EscapeDataString(oauth_token_secret))))
{
oauth_signature = Convert.ToBase64String(hasher.ComputeHash(ASCIIEncoding.ASCII.GetBytes("POST&" + Uri.EscapeDataString(facebookURL) + "&" + Uri.EscapeDataString(baseString))));
}
// create the request header
string authorizationFormat = "OAuth oauth_consumer_key=\"{0}\", oauth_nonce=\"{1}\", " + "oauth_signature=\"{2}\", oauth_signature_method=\"{3}\", " + "oauth_timestamp=\"{4}\", oauth_token=\"{5}\", " + "oauth_version=\"{6}\"";
string authorizationHeader = string.Format(
authorizationFormat,
Uri.EscapeDataString(oauth_consumer_key),
Uri.EscapeDataString(oauth_nonce),
Uri.EscapeDataString(oauth_signature),
Uri.EscapeDataString(oauth_signature_method),
Uri.EscapeDataString(oauth_timestamp),
Uri.EscapeDataString(oauth_token),
Uri.EscapeDataString(oauth_version)
);
HttpWebRequest objHttpWebRequest = (HttpWebRequest)WebRequest.Create(facebookURL);
objHttpWebRequest.Headers.Add("Authorization", authorizationHeader);
objHttpWebRequest.Method = "POST";
objHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
using (Stream objStream = objHttpWebRequest.GetRequestStream())
{
byte[] content = ASCIIEncoding.ASCII.GetBytes(Uri.EscapeDataString("user_id=1699575980&screen_name=MuneebZulfee&text=some message"));
objStream.Write(content, 0, content.Length);
}
var responseResult = "";
try
{
//success posting
WebResponse objWebResponse = objHttpWebRequest.GetResponse();
StreamReader objStreamReader = new StreamReader(objWebResponse.GetResponseStream());
responseResult = objStreamReader.ReadToEnd().ToString();
}
catch (Exception ex)
{
//throw exception error
responseResult = "Twitter Post Error: " + ex.Message.ToString() + ", authHeader: " + authorizationHeader;
}
}
Try using Tweet Sharp
var twitterApp = new TwitterService("******************", "****************");
twitterApp.AuthenticateWith("**********-*********************", "****************");
twitterApp.SendDirectMessage(new SendDirectMessageOptions() { ScreenName = "username", Text = DateTime.UtcNow.Ticks.ToString() });
This does for me
I am trying to sign my requests to the amazon gateway. But every time when I try to send a POST request it tells me that my signature has been expired. Any ideas will be appreciated.
You have some problem with getting the time or something like that. I had the problem with the payload. So if you are making GET request your payload is an EMPTY STRING. Otherwise it should be hashed Json object. Here is example of how I do it in my application. The code can be raw, but I am 100000% it work, because I am using it every day.
const string RegionName = "eu-west-1"; //This is the regionName
const string ServiceName = "apigateway";
const string Algorithm = "AWS4-HMAC-SHA256";
const string ContentType = "application/json";
const string Host = "apigateway.eu-west-1.amazonaws.com";
const string SignedHeaders = "content-type;host;x-amz-date";
public static WebRequest RequestGet(string canonicalUri, string canonicalQueriString, string jsonString) {
string hashedRequestPayload = CreateRequestPayload("");
string authorization = Sign(hashedRequestPayload, "GET", canonicalUri, canonicalQueriString);
string requestDate = DateTime.UtcNow.ToString("yyyyMMddTHHmmss") + "Z";
WebRequest webRequest = WebRequest.Create("https://" + Host + canonicalUri);
webRequest.Method = "GET";
webRequest.ContentType = ContentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
return webRequest;
}
public static WebRequest RequestPost(string canonicalUri, string canonicalQueriString, string jsonString)
{
string hashedRequestPayload = CreateRequestPayload(jsonString);
string authorization = Sign(hashedRequestPayload, "POST", canonicalUri, canonicalQueriString);
string requestDate = DateTime.UtcNow.ToString("yyyyMMddTHHmmss") + "Z";
WebRequest webRequest = WebRequest.Create("https://" + Host + canonicalUri);
webRequest.Timeout = 20000;
webRequest.Method = "POST";
webRequest.ContentType = ContentType;
webRequest.Headers.Add("X-Amz-date", requestDate);
webRequest.Headers.Add("Authorization", authorization);
webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
webRequest.ContentLength = jsonString.Length;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(jsonString);
Stream newStream = webRequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
return webRequest;
}
private static string CreateRequestPayload(string jsonString) {
//Here should be JSON object of the model we are sending with POST request
//var jsonToSerialize = new { Data = String.Empty };
//We parse empty string to the serializer if we are makeing GET request
//string requestPayload = new JavaScriptSerializer().Serialize(jsonToSerialize);
string hashedRequestPayload = HexEncode(Hash(ToBytes(jsonString)));
return hashedRequestPayload;
}
private static string Sign(string hashedRequestPayload, string requestMethod, string canonicalUri, string canonicalQueryString) {
var currentDateTime = DateTime.UtcNow;
var accessKey = //Here place your app ACCESS_KEY
var secretKey = //Here is a place for you app SECRET_KEY
var dateStamp = currentDateTime.ToString("yyyyMMdd");
var requestDate = currentDateTime.ToString("yyyyMMddTHHmmss") + "Z";
var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, RegionName, ServiceName);
var headers = new SortedDictionary < string, string > {
{ "content-type", ContentType },
{ "host", Host },
{ "x-amz-date", requestDate }
};
string canonicalHeaders = string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
// Task 1: Create a Canonical Request For Signature Version 4
string canonicalRequest = requestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + SignedHeaders + "\n" + hashedRequestPayload;
string hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));
// Task 2: Create a String to Sign for Signature Version 4
string stringToSign = Algorithm + "\n" + requestDate + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
// Task 3: Calculate the AWS Signature Version 4
byte[] signingKey = GetSignatureKey(secretKey, dateStamp, RegionName, ServiceName);
string signature = HexEncode(HmacSha256(stringToSign, signingKey));
// Task 4: Prepare a signed request
// Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature
string authorization = string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
Algorithm, accessKey, dateStamp, RegionName, ServiceName, SignedHeaders, signature);
return authorization;
}
private static byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName) {
byte[] kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
byte[] kRegion = HmacSha256(regionName, kDate);
byte[] kService = HmacSha256(serviceName, kRegion);
return HmacSha256("aws4_request", kService);
}
private static byte[] ToBytes(string str) {
return Encoding.UTF8.GetBytes(str.ToCharArray());
}
private static string HexEncode(byte[] bytes) {
return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
}
private static byte[] Hash(byte[] bytes) {
return SHA256.Create().ComputeHash(bytes);
}
private static byte[] HmacSha256(string data, byte[] key) {
return new HMACSHA256(key).ComputeHash(ToBytes(data));
}
So for example if I want to get all the APIs that are deployed in the Gateway I am doing like this:
using(WebResponse response = webRequest.GetResponse()) {
StreamReader responseReader = new StreamReader(response.GetResponseStream());
string responseJson = responseReader.ReadToEnd();
} catch (WebException) {
//Doing something when exception has been thrown
}
Here is the interesting part of creating a API Key. First you need to make your raw payload and then pass it to the methods I gave you above:
string payload = "{ \"name\" : \"" + name + "\", \"description\" : \"" + description.Trim() + "\", \"enabled\" : \"True\", \"stageKeys\" : [ ] }";
WebRequest webRequest = RequestSignerAWS.RequestPost("/apikeys", "", payload);
And make sure you are getting the time of the creating the request, because this will cause you the problem you are having.
You can look or use the code in this project for sending requests to API gateway:
https://github.com/ronenfe/Addons.AwsSdk
It uses this code for the signing:
https://github.com/tsibelman/aws-signer-v4-dot-net .