RestSharp isn't consistent when calling wordpress/woocomerce site - c#

In my dev environment, I have a wordpress/woocommerce site locally all hosted under IIS.
Using the following code restsharp works:
var fullEndPoint = string.Concat(site, "/wp-json/wc/v3/", endpoint)
var client = new RestSharp.RestClient(fullEndPoint)
{
Authenticator = OAuth1Authenticator.ForProtectedResource(consumerkey, woosecret, "", "")
};
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddJsonBody(serializedData);
client.Execute(request);
When I change the fullEndPoint, consumerkey and woosecret to be our main test site which mirrors our live site (running on apache/linux), I receive
Sorry you are not allowed to create Resource.
If I post to our test site the same data using postman, it goes through and works.
For the purposes of testing, if I then change the above declaration of client to be:
var client = new RestClient("https://wordpress.mytestsite.com/wp-json/wc/v3/products?oauth_consumer_key=ck_a24ad9ddea2d9fe71d9172c415fd51b4dc83a6dc&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1627038994&oauth_nonce=T9gfeZGdmNx&oauth_version=1.0&oauth_signature=OJB1TBpLpA%2Bet0A%2FDFbozOT9nf8%3D");
where fullendpoint is the code shown in postman's code windows for Restsharp, again the code works, so I know the error is misleading. So Why doesn't restsharp work in the initial way for me when I point to my test site?
Edit:
If I change client such that I'm now setting it up as:
var client = new RestSharp.RestClient(fullEndPoint)
{
Authenticator = OAuth1Authenticator.ForClientAuthentication(consumerkey, woosecret, username, password)
};
where username and password equal the user set up in woo commerce against the consumer key for read/write access, I still receive an access denied error

Related

How to fix issue calling Amazon SP-API, which always returns Unauthorized, even with valid Token and Signature

I went through the guide of for getting setup to call the new SP-API (https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md), and during the process checked off all of the api areas to grant access to (i.e. Orders, Inventory, etc). I am using the C# library provided by Amazon (https://github.com/amzn/selling-partner-api-models/tree/main/clients/sellingpartner-api-aa-csharp). I successfully get an access token and successfully sign the request, but always get the following error:
Access to requested resource is denied. / Unauthorized, with no details.
I am trying to perform a simple get to the /orders/v0/orders endpoint. What am I doing wrong?
Below is my code:
private const string MARKETPLACE_ID = "ATVPDKIKX0DER";
var resource = $"/orders/v0/orders";
var client = new RestClient("https://sellingpartnerapi-na.amazon.com");
IRestRequest restRequest = new RestRequest(resource, Method.GET);
restRequest.AddParameter("MarketPlaceIds", MARKETPLACE_ID, ParameterType.QueryString);
restRequest.AddParameter("CreatedAfter", DateTime.UtcNow.AddDays(-5), ParameterType.QueryString);
var lwaAuthorizationCredentials = new LWAAuthorizationCredentials
{
ClientId = AMAZON_LWA_CLIENT_ID,
ClientSecret = AMAZON_LWA_CLIENT_SECRET,
RefreshToken = AMAZON_LWA_REFRESH_TOKEN,
Endpoint = new Uri("https://api.amazon.com/auth/o2/token")
};
restRequest = new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restRequest);
var awsAuthenticationCredentials = new AWSAuthenticationCredentials
{
AccessKeyId = AMAZON_ACCESS_KEY_ID,
SecretKey = AMAZON_ACCESS_SECRET,
Region = "us-east-1"
};
restRequest = new AWSSigV4Signer(awsAuthenticationCredentials).Sign(restRequest, client.BaseUrl.Host);
var response = client.Execute(restRequest);
If you followed the SP-API guide, then you created a Role (which is the IAM ARN your app is registered with) and a User which has permissions to assume that role to make API calls.
However, one thing the guide is not clear about is that you can't make API calls using that user's credentials directly. You must first call the STS API's AssumeRole method with your User's credentials (AMAZON_ACCESS_KEY_ID/AMAZON_ACCESS_SECRET), and it will return temporary credentials authorized against the Role. You use those temporary credentials when signing requests.
AssumeRole will also return a session token which you must include with your API calls in a header called X-Amz-Security-Token. For a brief description of X-Amz-Security-Token see https://docs.aws.amazon.com/STS/latest/APIReference/CommonParameters.html
You also get this error if your sp app is under review, drove me nuts!
If you using c# take look to
https://github.com/abuzuhri/Amazon-SP-API-CSharp
AmazonConnection amazonConnection = new AmazonConnection(new AmazonCredential()
{
AccessKey = "AKIAXXXXXXXXXXXXXXX",
SecretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
RoleArn = "arn:aws:iam::XXXXXXXXXXXXX:role/XXXXXXXXXXXX",
ClientId = "amzn1.application-XXX-client.XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
ClientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
RefreshToken= "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
});
var orders= amazonConnection.Orders.ListOrders();
In our situation, we had to explicitly add an IAM policy to the user we defined as making the API call. Please see the link below and confirm that the user you have calling the API has the policy assigned to them:
https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md#step-3-create-an-iam-policy
Somehow we went through the step-by-step setup twice, and adding this explicit policy was missed. Initially I believe it was added 'inline' as instructed, but that does not seem to work.
I dont think is a duplicated question, buy the solution may apply: https://stackoverflow.com/a/66860192/1034622

C# console application authentication session

How could someone implement the az login (Azure CLI) experience in a C# Console application?
In that case, a browser window is opened, the user authenticates and after that he can access the private resources.
My guess is that the authentication token is stored somewhere, but where? Session variable, file..?
Update
I found out that there is a folder ~/.azure storing the relevant information. So the question is more on the first part (starting a browser and getting the resulting token).
How could someone implement the az login (Azure CLI) experience in a C# Console application?
1.Starting a browser with Process.Start(#"http://url");. After user enter his credential, you will get the authorization code. Copy it.
2.Get an authorization code.
3.Get access token with following code:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("ContentType", "application/json");
var requestURl = new Uri($"https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/token");
string body = "{\"client_id\": \"3c35ed0b-a441-4c57-9d1c-3a3b0392d9c3\",\"code\":\"the_code_you_copy_in_the_second_step\",\"redirect_uri\": \"https://localhost\",\"grant_type\": \"authorization_code\",\"client_secret\": \"xxxxxxxxxxxxxx\",\"scope\": \"user.read\"}";
var stringContent = new StringContent(body, Encoding.UTF8, "application/json");
var response = client.PostAsync(requestURl, stringContent).Result;
}
4.The result:
For more detials about how to get authorization code and access token you could refer to this article.

HttpClient certificate when hosted in IIS/Asp.NET Application not work

I have a strange problem.
I need to perform an SSL request using a CER client certificate, to a server that requires authentication by that certificate.
I am using the code below:
var cert = X509Certificate.CreateFromCertFile("cert.cer");
var handler = new WebRequestHandler();
handler.ClientCertificates.Add(cert);
var http_client = new HttpClient(handler);
http_client.BaseAddress = new Uri("https://service.com/");
var str_json = JsonConvert.SerializeObject(new
{
Field = "Value1",
Fiesl2 = "Value2"
});
var byteContent = new ByteArrayContent(Encoding.UTF8.GetBytes(str_json));
byteContent.Headers.Remove("Content-Type");
byteContent.Headers.Add("Content-Type", "application/json");
var res = http_client.PostAsync("ResourcePath", byteContent).Result;
res.EnsureSuccessStatusCode(); //THe error 401 ocurrs here
var res_body = res.Content.ReadAsStringAsync().Result;
This code works perfectly when I squeeze into a ConsoleApplicaiton or a WebApplication in IIS Express.
But when I squeeze exactly the same code in Local IIS or IIS Server, I get the 401-Unauthorized error. The strange thing is that using Fiddler, in this case I can not even see the request attempt.
I've already checked that path is not the problem.
The problem occours in .NET 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1 and etc..
Can anyone help me out, is it any configuration that should be performed in IIS. I've researched a lot, but I did not find that specific error.
A .cer file at client side does not contain private key, so usually it won't work if mutual SSL/TLS is required by the server. You need to get a valid certificate with private key (usually a .pfx file).

Retrieving user information in Azure Function (C#) from Angular-cli application

I'm having troubles retrieving user information inside an Azure Function and have no idea how to do this. I've tried different things already, but nothing seems to work...
First of all, I created an Angular-cli application and am able to login using the "adal-angular5" npm-package.
When I want to retrieve information from a HttpTriggering Azure function, I can't seem to find how to get more information about the user using the token from the angular app (or how to validate the logged in user). I'm including it in the headers of the message.
headers.append('Authorization', `Bearer ${this.adal5Service.userInfo.token}`);
I've created an app registration in Azure AD including my reply URL, Permissions to "Microsoft Graph" and "Windows Azure Active Directory"
Does anyone know how to do this? (If more information should be necessary to solve... just tell me, and I'll happily provide that)
Things I tried already
Code below with both requestUrl's (one is in comment) and with/without sending the token in the header
using (var client = new HttpClient())
{
//var requestUrl = $"https://graph.windows.net/me?api-version=1.6";
var requestUrl = $"https://graph.microsoft.com/v1.0/me/";
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = client.SendAsync(request).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
var user = JsonConvert.DeserializeObject<AdUser>(responseString);
return user;
}

Azure AD authentication with asp.net Identity for authorisation

I tried to look for all over internet but couldn't see how I can achieve what I was asked to. Here is my enterprise app which uses Asp.net Identity for form based authentication. I had extended User and Role along with Groups to provide authorization in my code. (note: not using any group/role directives).
Now I was asked to look at possibility of changing code to accommodate Azure Active Directory authentication. I tried reading on how you can register app, send user to Azure site for authentication, get back token etc. However I'm stuck at 'what-afterwards?' I have authenticated user How can I use my existing Asp.net Identity model where user was stored in sql database. How to use this token to relate the existing user.
Moreover, when I change my project to allow Azure AD, it removes Aspnet.Identity package as its not compatible with Azure AD !!
I even tried manually keeping both packages side by side, I got to point where user is sent to authenticate on Azure, diverted back to home page and again to login on Azure AD in never ending loop.
to summarize the question, How can I authenticate user from AAD and keep using existing Roles and groups authorization.
Edit:
I tried creating separate web service which will authenticate user and send JWT token. which works find if I call it directly on browser, however, when I tried to call this service from my web app I get weird error
Application with identifier 'a2d2---------------' was not found in the directory azurewebsites.net
Weird part here is name of directory is 'azurewebsites.net' and not the default directory I'm using.
Update
Here is code which throws error
public async Task<ActionResult> Login(string returnUrl)
{
try
{
// get the access token
AuthenticationContext authContext = new AuthenticationContext(authority, new TokenCache());
var clientCredential = new ClientCredential(clientId, password);
//Error on below line
AuthenticationResult result = await authContext.AcquireTokenAsync(resourceId, clientCredential);
// give it to the server to get a JWT
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
......
try this:
var client = new RestClient("https://login.microsoftonline.com/{tenant-
Id}/oauth2/v2.0/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("grant_type", "password");
request.AddParameter("application/x-www-form-urlencoded",
"grant_type=password&client_id={client-Id}&client_secret={client-
secret}&scope={scopeurl}&userName={username}&password={password}",
ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
var json = response.Content;
var JSONObject = JObject.Parse(json);
var token = (string)JSONObject["access_token"];
I had a similar issue so I created an Office 365 owin security plugin. I shared the code on github. It's based on the katana project at codeplex.
You can find the source code at https://github.com/chadwjames/wakizashi.
You will need to register your application here. When registering the application set the call back uri to https://yourdomain/signin-office365
The Application ID is your Client Id and the Password is your Client Secret.
Once you have it registered you can modify the Startup.Auth.cs and add something like this to the ConfigureAuth method.
//setup office 365
var office365Options = new Office365AuthenticationOptions
{
ClientId = ConfigurationManager.AppSettings["ada:ClientId"],
ClientSecret = ConfigurationManager.AppSettings["ada:ClientSecret"],
Provider = new Office365AuthenticationProvider
{
OnAuthenticated = async context =>
{
await
Task.Run(
() => context.Identity.AddClaim(new Claim("Office365AccessToken", context.AccessToken)));
}
},
SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie
};
office365Options.Scope.Add("offline_access");
app.UseOffice365Authentication(office365Options);
When I have more time I hope to create a nuget package for this.

Categories