PayU POST notification signature validation - c#

I'm integrating PayU API service in my web (.NET MVC Core 2.1) application.
After client pays order, PayU sends notification confirmation as POST request to my api method.
Example of PayU confirmation notification.
In heareds notification placed MD5 signature.
OpenPayu-Signature:
sender=checkout;
signature=c33a38d89fb60f873c039fcec3a14743;
algorithm=MD5;
content=DOCUMENT
string incoming_signature = c33a38d89fb60f873c039fcec3a14743;
What I supposed to do to verify that notification:
Here is instruction to verify notification signature.
1.Combine the body of the incoming notification with the value of second_key(second key is avaliable in my account page in payu ):
string concatenated = JSONnotification + second_key;
2.Select an expected signature value by applying the hashing function (e.g. md5) in the received chain of characters:
string expected_signature = md5(concatenated)
3.Compare the strings: expected_signature and incoming_signature:
bool signature_is_correct = (expected_signature == incoming_signature);
Problem is checksums is not matching.
I Handle this notification in my controller method:
[HttpPost]
[AllowAnonymous]
[Route("notify")]
public IActionResult TransactionConfirm([FromBody] dynamic content)
content variable parsed as a object
and I accessing JsonBody string as content.ToString()
method.
Is it possible to hashes isn't matched because method content.ToString() can return not the same string like in request body?
Is there any ways to handle json as argument in .Net Core method? (I've already tried to placed JObject, but method ToString() also returned string that generated to hash isn't matching)

To compute a matching hash, you need to read the incoming request as is, without deserializing it. So yes, your generated JSON probably differs from the sent one (whitespace characters).
I'm not really familiar with ASP.NET Core, but in the old ASP.NET, you could read the request content using:
var json = new System.IO.StreamReader(Request.InputStream).ReadToEnd();

Related

How to pass a parameter to a Post action method which contain "&" inside our ASP.NET MVC 5

I have the following Post action method which accept username & password:
[HttpPost]
public ActionResult UserInfo(string username, string password)
{
and I am testing it using FireFox RESTCleint add-in, where I am passing the URL + the Header as application/x-www-form-urlencoded + the username/password, as follows:
Things are working well, but in case the username or the password contain this character &, then the logic will break, as it seems ASP.NET will assume that what comes after & is a new parameter and not part of the parameter value. How can I fix this issue?
And is it an issue with my code or with the FireFox plugin or with encoding the parameters?
Second question, if I want to specify the technical specification for calling this Acton method from external applications, then what is the data encoding needed for the parameters?
Thanks

Using Digest Authentication with Shelly Power Product, cannot get 200 code from second GET requests

I'm working on getting some Shelly Power products (API Documents Here) able to be called from a .NET 6 Minimal API application.
Following the Digest Authentication documentation from Shelly and the RFC 7616, I have an extension method for the HttpClient that basically takes an HttpRequestMessage for the URL http:///rpc/Switch.GetStatus?id=0. After setting the normal headers (Accept, User-Agent, etc.) for that HttpRequestMessage, it passes that HttpRequestMessage as a parameter to that extension method.
After passing the HttpRequestMessage to the extension method, it is cloned into a new HttpRequestMessage, with the content, version, and headers. After that, the first SendAync() call is made, and the 401 response is generated containing the WWW-Authentication header. After parsing out the realm, nonce, and qop, the rounds of hashing is done according to the specs. Shelly uses SHA256 instead of MD5 (as they should) but overall follows the standard for hashing. After this, the newly formed Authentication Header string is created and it is formatted as such:
Digest username="admin", realm="shellyplugus-083af2018b68", nonce="633e7ba8", cnonce=8724224, response="9B15CEBA6E5FD862271954AC2C40948D6237511B83748143FF763A0E76B1A346", algorithm=SHA-256
The following code is the creation of an AuthHeaderObject, the creation of the string above, and gets added to the cloned HttpRequestMessage (called "digestRequest" here):
var digestAuthHeaders = new DigestAuthHeader(
"Digest", realm, username, password, nonce, qop, clientNonce, "SHA-256");
var digestRequestHeader = digestAuthHeaders.DigestRequestHeader();
digestRequest.Headers.Add("Authorization", digestRequestHeader);
The 2nd SendAsync() passing the cloned request and completion option enum.
var authRes = await client.SendAsync(digestRequest, httpCompletionOption);
The issue after this is that I am still getting a 401 response. Not even getting another code indicating another issue. It is just acting like the same request has been made.
Should I forgo the cloning of the HttpRequestMessage and simply create a new one? Does anything immediately standout that is incorrect? I want to note that Shelly only specifies that Authorization string only contain the values included, it does not require uri, qop, opaque, and some of the others.
Looks like there is a direct way to do this by using HttpClientHanlder and setting the NetworkCredentials property, then passing the Handler to the HttpClient.

Read the URL parameter which is set after the hash symbol using ASP.NET Core MVC

Let's say we have a controller like this:
public class HomeController : Controller
{
[HttpGet]
public IActionResult Foo(string token)
{
return RedirectToAction(nameof(Index));
}
}
When I type the following URL address in the webbrowser:
https://localhost:44348/home/foo#dsfdsf
I would like to be able to read the dsfdsf after the hash symbol and bind it to the token variable.
Now I'm receiving null value. I'm getting such URL from the 3rd party app and I need to consume the response somehow and read the data from the query string.
I played with [FromQuery] attribute but I haven't managed it to work so far.
Any ideas?
Cheers
I have a work around for you, but first of all lets get more into the problem.
The strings after the hash symbol which are called Fragment values are not query parameters but they are strings to be read by the client-side (living in the browser) and the server cannot read them because they are not sent to the server by the browser.
Some authentication providers like Google and Azure send the access token as Fragment value for security reasons so that they are not transferred over the internet after they get sent as direct response from the authentication provider.
The only way you can come around that is to use javascript to convert the fragment values to query parameters by replacing the '#' with '?' and redirecting to the endpoint in your server controller.
I suppose the easiest way is to handle all that from server, meaning you get get the request in server, send a javascript code to the browser on the fly, that replaces the '#' into '?' and redirects to your second endpoint which reads the token as strong parameter.
Here how you can do it in ASP.NET Core 3.1:
[AllowAnonymous]
[HttpGet("authredirect")]
[Produces("text/html")]
public virtual ContentResult ConvertUrlFragmentToQueryParamThenRedirect()
{
return Content("<html><script>window.location.href=window.location.href.replace('#', '?').replace('authredirect', 'authparams')</script></html>", "text/html");
}
[AllowAnonymous]
[HttpGet("authparams")]
public virtual void GetAccessToken([FromQuery] string access_token)
{
// now you have your access token server side here
}
Please remember to set your redirectUrl to the correct one, in this case 'YOUR REDIRECT URL/authredirect'.

Processing Post Request from Slack

I've setup an asp.net MVC web application to capture post request. I've set breakpoints to see what info is coming through. When an interactive button is clicked, my breakpoint is hit but the object has no details. It simply says {Object} when i hover over value. When I use Postman and send a raw JSON body, it displays the JSON. May I ask how am i suppose to process the slack object that is sent?
public void Post(object value)
{
// breakpoint here
}
For interactive messages Slack send a standard POST request with a single form-data encoded parameter called payload in the body. This parameter contains the data of the actual request as JSON string.
You can simulate this with Postman by using the following parameters:
Request type: POST
Header: Content-Type: application/x-www-form-urlencoded
Body: form-data, with key=payload and value = JSON string.
So the body is not fully JSON as you assumed, but contains a form parameter with a JSON encoded string. If you change your app accordingly, it will work.
In c# you can access the content of the payload parameter with Request["payload"] (see this answer or details).
Then you still need to decode the JSON string into an object of course. An easy approach is to use JavaScriptSerializer.Deserialize. (see this answer for details and alternative approaches).

C# WebAPI - getting URL with parameters passed as QueryString

I've been searching for this problem but non was identical to my case.
I have the following controller:
public HttpResponseMessage GetMyService(int aType, [FromUri] string streamURL)
streamURL is a parameter that gets a full URL sent by the client.
The client calls the service like that:
http://www.myservice.com/.../GetMyService/?aType=1&streamURL=http://www.client.com/?p1=100&p2=200
The problem is that at then end, I get the [FromUri] string streamURL parameter as http://www.client.com/?p1=100 without the &p2=200
This is known and reasonable, but I cannot place any encoding/decoding functionality as the URL is cut at the very beginning.
Any help would be appreciated..
THX
The client should properly URL encode the value of the streamURL query string parameter when making the request in order to conform to the HTTP protocol specification:
http://www.myservice.com/.../GetMyService/?aType=1&streamURL=http%3A%2F%2Fwww.client.com%2F%3Fp1%3D100%26p2%3D200
So basically there's nothing you could do on the server side, you should fix the client.

Categories