I have a Controller Action in which I:
Forward a URL to a 3rd party that the 3rd party re-directs the client to if an operation is successful.
The client then connects to the 3rd party and performs an operation.
If successful the 3rd party re-directs (using a 302) the client to the URL we told them at step 1.
This all works. Problem is the URL the Controller on the server tells the 3rd party about us built using:
var urlHelper = new UrlHelper(System.Web.HttpContext.Current.Request.RequestContext);
var responseUrl = urlHelper.Action("Action", "Controller", new { id }, Request.Url.Scheme);
responseURL now looks like:
"https://some.internal.domain/App/Action/1234".
The client however accessed the site using an address like:
"https://example.com/App/Action/1234".
and they cannot access https://some.internal.domain externally.
So how can I build the absolute URL for the 3rd party to re-direct the client to using the URL the client is accessing the site from?
UPDATE: The above method should have worked it turns out the problem is am behind a Reverse Proxy (have re-worded the title to reflect this).
I came across a similar problem. You basically have two options.
Use the URL Rewrite Module to rewrite your entire response by replacing/rewriting all pattern matched with https://some.internal.domain to https://example.com/App. You'll probably want to add certain conditions like only rewrite if the response type is of type html/text and what not.
Use an extension method. This method requires the Reverse Proxy in question to forward additional headers identifying where the original request came from (e.g. Azure Application Gateway sends a header named X-Original-Host but I think most other reverse proxies use X-Forwarded-For or some variant like Winfrasoft X-Forwarded-For). So based on the example provided you could do something like.
The helper could look like this
public static class UrlHelpers
{
public static string GetUrlHostname(this UrlHelper url)
{
var hostname = url.RequestContext.HttpContext.Request.Headers["X-Original-Host"] ?? url.RequestContext.HttpContext.Request.Url.Host;
return hostname;
}
}
And then to use it based on your example.
var urlHelper = new UrlHelper(System.Web.HttpContext.Current.Request.RequestContext);
var responseUrl = urlHelper.Action("Action", "Controller", new { id }, Request.Url.Scheme, urlHelper.GetUrlHostname());
Related
I know this is possible using Puppeteer in js, but I'm wondering if anyone has figured out how to proxy on a page level in PuppeteerSharp (different proxies for different tabs)?.
it seems I can catch the request, but I'm not sure how to adjust the proxy.
page.SetRequestInterceptionAsync(true).Wait();
page.Request += (s, ev) =>
{
// what to do?
}
Edit
I am aware that I can set the proxy at the browser level like so;
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = false,
Args = new[] { "--proxy-server=host:port" }
});
var page = await browser.NewPageAsync();
await page.AuthenticateAsync(new Credentials() { Username = "username", Password = "password" });
But this is not what I'm trying to do. I'm trying to set the proxy for each page within a single browser instance. I want to test lots of proxies so spawning a new instance of the browser just to set the proxy is too much overhead.
You can use different browser instances for each logical instances. I mean instead of trying to set different proxy for each page/tab with different proxy just create new browser instance and set proxy via launch args.
If this solution doesn't fit your needs, check this question. There is library for NodeJS which give ability to use different proxy per each page/tab. You can check that library source code and implement same things inside your C# application.
That library is using very simple method. Instead of sending requests via puppeter's browser/page library send request via nodejs http tools. It can be done by using method page.setRequestInterception. So library intercept each request from page, after that gather data and send request via http tools. I used C# a long time ago. So maybe I am wrong, but you can try to use HttpWebRequest or something similar. After you get result you should use method request.respond and pass response results there. In this way you can put any kind of proxy inside your application. Check here code of library.
how do you use identitymodel for c# to get a authorize code?
i need to make two seperate calls because the server infrastructure, one /auth and one /token, i have to work with apparently does not work with just one endpoint like google can do.
theres this: authorize url
but that only creates the request, im missing something like this for the authorize endpoint:
var client = new HttpClient();
var response = await client.RequestTokenAsync(new TokenRequest
{
Address = "https://demo.identityserver.io/connect/token",
GrantType = "custom",
ClientId = "client",
ClientSecret = "secret",
Parameters =
{
{ "custom_parameter", "custom value"},
{ "scope", "api1" }
}
});
i did choose this library because it is shown here as certified.
You first have to get the authorization code (using the authorization code flow) and you need to redirect the users browser to the ru variable as it is described here.
In theory, just a link pointing to that variable, like
Login to IdentityServer
In the response back you should eventually get back the authorization code. From that code you can then use IdentityModel to get the final tokens.
I have been contemplating on a dilemma for hours. I have a Visual Studio Solution that contains a WCF, WebForms, UWP, Xamarin and a SharedLibrary Projects.
I intend to use the WCF project as the backend which talks to the database and process Email and SMS integration and feed the other apps.
OPTION A
Currently, The WCF is hosted on an Azure App Service which makes it accessible via POST, GET, etc from the url which is: https://mywcfprojectlink.azurewebsites.net/service1.svc/GetUsers
With such arrangements, I can perform a POST request to get data from the apps:
string response = string.Empty;
string url = "https://mywcfprojectlink.azurewebsites.net/service1.svc/GetUsers";
try
{
var values = new Dictionary<string, string>
{
{ "data", Encryption.EncryptString(dat.ToString()) } //dat is incoming method param
};
string jsonString = JsonConvert.SerializeObject(values);
var cli = new WebClient();
cli.Headers[HttpRequestHeader.ContentType] = "application/json";
response = cli.UploadString($"{url}", jsonString);
var result = JsonConvert.DeserializeObject<string>(response);
topic.InnerText = Encryption.DecryptString(result.ToString());
}
catch (Exception)
{
return string.Empty;
}
The method above is a simple one as I have other ones where I Deserialize with Models/Classes.
OPTION B
I equally have access to the methods defined in service1 by adding the project reference to my WebForms which surprisingly is also compatible with xamarin but not with UWP. Nevertheless, I am interested in the WebForms scenario. Below is an example method:
using BackEnd;
//Service1 service1 = new Service1();
//var send = service1.GetUsers(dat.ToString()); //dat is incoming method param
//topic.InnerText = send;
Obviously, using the Option B would eliminate the need to encrypt, decrypt, serialize or deserialize the data being sent. However, I have serious performance concerns.
I need to know the better option and if there is yet another alternative (probably an Azure Resource), you can share with me.
If you decide to use https endpoint of the Azure website, option A is secure because of SSL encryption. So you don't have to encrypt/decrypt it by yourself. The only tip is to create a proper authorization mechanism. For example use TransportWithMessageCredential. An example is provided in below article https://www.codeproject.com/Articles/1092557/WCF-Security-and-Authentication-in-Azure-WsHttpBin
In My application the scenario like i want to read the client requested URL from ASP.NET WEB API.
Example:
https://xxx.test.com/test.html page is calling https://api.test.com/api/home/get/1 WEB method.
The requested url https://xxx.test.com/test.html need to read from the web method.
The below code is returning IP Address. It is not returning domain url.
// GET api/home/get/5
public string Get(int id)
{
return HttpContext.Current.Request.UserHostAddress;
}
Please suggest me.
Thanks in Advance.
Look to HttpContext.Current.Request.UrlReferrer.OriginalString. Note that this data was set by the client, so you can't trust it's 100% accurate.
Try this :
string url = HttpContext.Current.Request.Url.AbsoluteUri;
// http://localhost:1302/TESTERS/Default6.aspx
string path = HttpContext.Current.Request.Url.AbsolutePath;
// /TESTERS/Default6.aspx
string host = HttpContext.Current.Request.Url.Host;
// localhost
If you're behind a load balancer or other reverse proxy, when asking for HttpContext.Current.Request.UserHostAddress, you won't get the IP of the client, instead you'll get the IP of the load balancer. In that case, look to HttpContext.Current.Request.Headers["X-Forwarded-For"] for the browser's IP address. Note that if you aren't behind such hardware, this is a great attack vector.
You can try HttpRequest.UrlReferrer. The MSDN reference can be found here
I would like to take the original URL, truncate the query string parameters, and return a cleaned up version of the URL. I would like it to occur across the whole application, so performing through the global.asax would be ideal. Also, I think a 301 redirect would be in order as well.
ie.
in: www.website.com/default.aspx?utm_source=twitter&utm_medium=social-media
out: www.website.com/default.aspx
What would be the best way to achieve this?
System.Uri is your friend here. This has many helpful utilities on it, but the one you want is GetLeftPart:
string url = "http://www.website.com/default.aspx?utm_source=twitter&utm_medium=social-media";
Uri uri = new Uri(url);
Console.WriteLine(uri.GetLeftPart(UriPartial.Path));
This gives the output: http://www.website.com/default.aspx
[The Uri class does require the protocol, http://, to be specified]
GetLeftPart basicallys says "get the left part of the uri up to and including the part I specify". This can be Scheme (just the http:// bit), Authority (the www.website.com part), Path (the /default.aspx) or Query (the querystring).
Assuming you are on an aspx web page, you can then use Response.Redirect(newUrl) to redirect the caller.
Here is a simple trick
Dim uri = New Uri(Request.Url.AbsoluteUri)
dim reqURL = uri.GetLeftPart(UriPartial.Path)
Here is a quick way of getting the root path sans the full path and query.
string path = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery,"");
This may look a little better.
string rawUrl = String.Concat(this.GetApplicationUrl(), Request.RawUrl);
if (rawUrl.Contains("/post/"))
{
bool hasQueryStrings = Request.QueryString.Keys.Count > 1;
if (hasQueryStrings)
{
Uri uri = new Uri(rawUrl);
rawUrl = uri.GetLeftPart(UriPartial.Path);
HtmlLink canonical = new HtmlLink();
canonical.Href = rawUrl;
canonical.Attributes["rel"] = "canonical";
Page.Header.Controls.Add(canonical);
}
}
Followed by a function to properly fetch the application URL.
Works perfectly.
I'm guessing that you want to do this because you want your users to see pretty looking URLs. The only way to get the client to "change" the URL in its address bar is to send it to a new location - i.e. you need to redirect them.
Are the query string parameters going to affect the output of your page? If so, you'll have to look at how to maintain state between requests (session variables, cookies, etc.) because your query string parameters will be lost as soon as you redirect to a page without them.
There are a few ways you can do this globally (in order of preference):
If you have direct control over your server environment then a configurable server module like ISAPI_ReWrite or IIS 7.0 URL Rewrite Module is a great approach.
A custom IHttpModule is a nice, reusable roll-your-own approach.
You can also do this in the global.asax as you suggest
You should only use the 301 response code if the resource has indeed moved permanently. Again, this depends on whether your application needs to use the query string parameters. If you use a permanent redirect a browser (that respects the 301 response code) will skip loading a URL like .../default.aspx?utm_source=twitter&utm_medium=social-media and load .../default.aspx - you'll never even know about the query string parameters.
Finally, you can use POST method requests. This gives you clean URLs and lets you pass parameters in, but will only work with <form> elements or requests you create using JavaScript.
Take a look at the UriBuilder class. You can create one with a url string, and the object will then parse this url and let you access just the elements you desire.
After completing whatever processing you need to do on the query string, just split the url on the question mark:
Dim _CleanUrl as String = Request.Url.AbsoluteUri.Split("?")(0)
Response.Redirect(_CleanUrl)
Granted, my solution is in VB.NET, but I'd imagine that it could be ported over pretty easily. And since we are only looking for the first element of the split, it even "fails" gracefully when there is no querystring.