How to get raw url from Owin? - c#

How can I get raw url from Owin (the url what was passed to HTTP request), independently on Owin hosting?
For instance, both http://localhost/myapp and http://localhost/myapp/ contains in IOwinRequest.Path the /. The PathBase contains always /myapp and Uri.OriginalString contains always http://localhost/myapp/.
(In ASP.NET I would call HttpContext.Current.Request.RawUrl which returns either /myapp or /myapp/.)
Reason: Currently, I need it to do the server side redirect to add the trailing / if it is missing (independently on the hosting).

You can get the raw Url in Owin by accessing the HttpListenerContext that was used to receive the request.
public static string RealUrlFromOwin(HttpRequestMessage request)
{
var owincontext = ((OwinContext) request.Properties["MS_OwinContext"]);
var env = owincontext.Environment;
var listenerContext = (System.Net.HttpListenerContext) env["System.Net.HttpListenerContext"];
return listenerContext.Request.RawUrl;
}
This will not only recover things like a trailing / in the Url, but will also get the Url string before any decoding is applied, so you can distinguish between '!' and %21, for instance.

Related

PayU POST notification signature validation

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();

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'.

Get instance of ApiController class from a URL directly

I am looking for a way to call the appropriate method (get, post etc.) on an ApiController class based on the URL and request type etc. without making a http request.
Background: We have an API application with numerous controllers that needs to also accept requests from a remote server. Due to restrictions I cannot control there is no way to open ports between the two servers to allow the remote server to make the request directly so we decided to forward the data using websockets (SignalR). I can send (within reason) whatever information is required.
I have tried the below:
HttpRequestMessage request = new HttpRequestMessage();
var bld = new UriBuilder
{
Port = 123,
Path = "api/v1/search",
Query = "query=search_string"
};
request.RequestUri = bld.Uri;
var httpCfg = AppConfiguration.Get().HttpConfig; //this is the same config that UseWebApi was called with and contains the routes.
var route = httpCfg.Routes.GetRouteData(request);
var controllerSelector = new DefaultHttpControllerSelector(httpCfg);
var descriptor = controllerSelector.SelectController(request);
route contains the controller name (search) but the call to SelectController throws an exception with a 404 response in it (I presume this indicates I am missing something from the fake request). The same URI works when sent as a direct http request so the routes do work as best I can tell.
Is there a better way to do this, or if not what am I missing from the request that is causing the 404?

Prevent HTTP Request Headers from trimming

I have a RESTFul Webservice that allows user to download files. The user will send a request with a couple of HTTP request headers to specify the files to download.
However, I discovered that the http request headers will get trimmed automatically, for example if the user send the header value - "a", with a space at the end, it will get trimmed and thus the value becomes "a". How can I prevent the values from being trimmed?
Below is my code is to retrieve each header value:
string filename = context.IncomingRequest.Headers["filename"];
context refers to WebOperationContext class
Why don't you just read the raw request and extract what you need?
Request.InputStream.Position = 0;
var input = new StreamReader(Request.InputStream).ReadToEnd();
per the rfc2616 specification ( HTTP 1.1 - page 31 )
"leading or trailing LWS MAY be
removed without changing the semantics of the field value."
Unfortunately, I do not know of http software that does not do this. For example, see this comment -> cURL

How to clean up existing response in webapi?

There is a authentication library that I have to use that helpfully does things like
Response.Redirect(url, false);
inside of it's method calls. I can't change this libraries code and it's fine for MVC style apps but in angular SPA -> WebApi apps this is just awful.
I really need a 401 otherwise I get into trouble with CORS when my angular scripts, using $http, try to call out to the auth server on another domain in response to the 302, that's if it even could as the Response.Redirect also sends down the object moved html and the angle brackets cause an error to be thrown.
Since I have to make the call to the auth library first the Response.Redirect is already in the response pipeline and so I need to clean it up to remove the body content and convert the 302 into a 401. I thought I could just:
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent("data");
}
but this just gets appended to the response and doesn't replace it plus I also need the Location: header which I can't seem to access via WebApi methods.
So instead I've had to do this in my ApiController:
var ctxw = this.Request.Properties["MS_HtpContext"] as HttpContextWrapper;
var ctx = ctxw.ApplicationInstance.Context;
var url = ctx.Response.RedirectLocation;
ctx.Response.ClearContent();
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent(url);
}
But this seems terrible and counter to webapi "feel". Plus I'm tied to the controller in doing this. I can't get the wrapper in a MessageHandler for example.
What I'd like to do is monitor the response for a given route in a message handler or in an AuthorizationFilterAttribute, if its a 302, I want to read it's headers, take what I want, wipe it and replace it with my own "fresh" response as a 401. How can I do this?
You might want to write your own ActionFilter and override its OnActionExecuted method where you can access HttpActionExecutedContext. From there, you can check response code, for example, and overwrite response with whatever you want.
Ref: https://msdn.microsoft.com/en-us/library/system.web.http.filters.actionfilterattribute.onactionexecuted%28v=vs.118%29.aspx#M:System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuted%28System.Web.Http.Filters.HttpActionExecutedContext%29

Categories