18

First question!


Environment

MVC, C#, AppHarbor.

Problem

I am calling an openid provider, and generating an absolute callback url based on the domain.

On my local machine, this works fine if I hit http://localhost:12345/login

Request.Url; //gives me `http://localhost:12345/callback`

However, on AppHarbor where I'm deploying, because they are using non-standard ports, even if I'm hitting it at "http://sub.example.com/login"

Request.Url; //gives me http://sub.example.com:15232/callback

And this screws up my callback, because the port number wasn't in the original source url!

I've tried

  • Request.Url
  • Request.Url.OriginalString
  • Request.RawUrl

All gives me "http://sub.example.com:15232/callback".

Also to clear up that this isn't a Realm issue, the error message I am getting from DotNetOpenAuth is

'http://sub.example.com:14107/accounts/openidcallback' not under realm 'http://*.example.com/'. 

I don't think I've stuffed that up?

Now, I'm about to consider some hacky stuff like

  • preprocessor commands (#IF DEBUG THEN PUT PORT)
  • string replace (Request.URL.Contains("localhost"))

All of these are not 100% solutions, but I'm sick of mulling over what could be a simple property that I am missing. I have also read this but that doesn't seem to have an accepted answer (and is more about the path rather than the authority). So I'm putting it towards you guys.

Summary

So if I had http://localhost:12345/login, I need to get http://localhost:12345/callback from the Request context.

And if I had "http://sub.example.com/login", I should get "http://sub.example.com/callback", regardless of what port it is on.

Thanks! (Sleep time, will answer any questions in the morning)

Community
  • 1
  • 1
Daryl Teo
  • 5,394
  • 1
  • 31
  • 37

6 Answers6

23

This is a common problem in load balanced setups like AppHarbor's - we've provided an example workaround.

Update: A more desirable solution for many ASP.NET applications may be to set the aspnet:UseHostHeaderForRequestUrl appSetting to true. We (AppHarbor) have seen several customers experience issues using it with their WCF apps, which is why we haven't enabled it by default and stil recommend the above solution for those situations. You can configure it using AppHarbor's "Configuration Variables" to inject the appsettings when deployed. More information can be found in this article.

runesoerensen
  • 3,234
  • 2
  • 22
  • 21
1

I recently ran into an issue where I compared a URL to the current URL, and then highlighted navigation based on that. It worked locally, but not in production.

I had http://example.com/path/to/file.aspx as my file, but when viewing that file and running Request.Url.ToString() it produced https://example.com:81/path/to/file.aspx in a load balanced production environment.

Now I am using Request.Url.AbsolutePath to just give me /path/to/file.aspx, thus ignoring the schema, hostname, and port numbers.

When I need to compare it to the URL on each navigation item I used: New Uri(theLink.Href).AbsolutePath

Chris Barr
  • 29,851
  • 23
  • 95
  • 135
0

If you use the UrlBuilder class in the framework you can easly get around this. On the builder class if you set the port to -1 then the port number will be removed:

new UriBuilder("http://sub.example.com:15232/callback"){ Port = -1}

returns : http://sub.example.com/callback

To keep the port number on a local machine just check Request.IsLocal and don't apply -1 to the port.

I would wrap this into a extension method to keep it clean.

jdphenix
  • 15,022
  • 3
  • 41
  • 74
Almond
  • 1,563
  • 1
  • 14
  • 20
0

I see that this is an old thread. I had this issue running MVC5, on IIS 7.5, with an Apache proxy in front. Outside of the server, I would get "Empty Response", since the asp.net app gets the Url from apache with the custom port.

In order to have the app redirect to a subpath without including the "custom" port, forget the Response/Request objects, and use the Transfer method. For instance, if I want that users are automatically redirected to the login page in case they are not logged already:

if (!User.Identity.IsAuthenticated)   
    Server.TransferRequest("Account/Login");
rll
  • 5,509
  • 3
  • 31
  • 46
0

My initial thoughts are get the referrer variable and check if that includes a port, if so use it otherwise don't.

If that’s not an option because a proxy might remove the referrer header variable then you might need to use some client side script to get the location and pass it back to the server.

I'm guessing that AppHarbor use port forwarding to the IIS server so even though publicly the site is on port 80 IIS has it hosted on another port so it can't know what port the client connected on.

Robert
  • 3,328
  • 2
  • 24
  • 25
  • I ended up using UrlReferrer (this doesn't have the port for some reason GRR!) but your post led me towards there. I'm not immediately sure of any ramifications, but thanks anyway :) – Daryl Teo Oct 07 '11 at 02:45
  • did you try using some javascript to get the port? you could pass it in the querystring or post it back. – Robert Oct 07 '11 at 16:37
  • That's pretty hacky, not something I want to rely on. – Daryl Teo Oct 08 '11 at 05:28
0

Something like

String port = Request.ServerVariables["SERVER_PORT"] == "80" ? "" : ":" + Request.ServerVariables["SERVER_PORT"];
String virtualRoot = Url.Content("~/");
destinationUrl = String.Format("http://{0}{1}{2}", Request.ServerVariables["SERVER_NAME"], port + virtualRoot, "/callback");
Steve
  • 2,988
  • 2
  • 30
  • 47