HTTPS MVC 5 Remote Request

I have the following attribute to make sure the page of the remote site opens in https mode.

public class RemoteRequireHttpsAttribute : RequireHttpsAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentException("Filter Context"); } if (filterContext != null && filterContext.HttpContext != null) { if (filterContext.HttpContext.Request.IsLocal) { return; } else { string val = ConfigurationManager.AppSettings["RequireSSL"].Trim(); bool requireSsl = bool.Parse(val); if (!requireSsl) { return; } } } base.OnAuthorization(filterContext); } } 

Local development now works fine, since I donโ€™t want it to open in https mode.

The Dev site opens the page in https mode - there is no problem (single node).

Where, how the site (load balancing - 2 nodes) that I am setting up right now gives me the following error. Please note that dev and prod sites have the same settings and web.config

Page not redirecting correctly

Firefox has detected that the server redirects the request to this address in a way that will never be completed.

This problem can sometimes be caused by disconnection or refusal to accept cookies.

Dev site url is similar to http://dev.datalab.something.org

Prod website URL is similar to http://datalab.something.org

And here is the challenge

 [RemoteRequireHttps] public ActionResult Index(string returnUrl, string error) 

What am I missing here?

Update 1: My administrator has confirmed that SSL termination has been configured at the balancer level. I browsed the iis site and I don't see the https bindings. I see only http bindings. Does he also need to configure https bindings?

Update 2: @AlexeiLevenkov pointed me in the right direction, and this post had the code I used, and it works. We moved the code into a separate answer.

+1
source share
3 answers

Your site is behind a load balancer that completes SSL - since all incoming traffic to your site is HTTP regardless of what the user sees. This leads to the fact that your code always tries to redirect to the HTTPS version and, therefore, to an infinite loop.

Parameters for correction:

  • Typically, the load balancer that terminates SSL sends the source IP / protocol through user headers. x-forwarded-proto and x-forwarded-for are common for this purpose. You may need to check with your network administrators if these headers are used or some additional configuration is required.
  • Alternatively, you can disable SSL termination, but it will add extra load to your server.
  • You can also configure a load balancer to talk to a server with the same protocol as the incoming request.

How to investigate such a problem:

  • Take a look at the http debugger (e.g. Fiddler) to see if you receive 30x redirect requests in a loop. If there are no redirects, the probable code is incorrect.
  • If you see repeated redirects, this most likely means that the site does not see the actual request information - there may be a protocol, missing cookies.
  • To continue your research, look at what devices are between the user and the server (CDN, proxy, load balancer ...) - everyone has good chances to lose some dates or conversion protocols.
+2
source

Not that I am against writing nice user attributes, it makes no sense maybe to redirect to web.config and use the transformations available for web.config to change the allowed value from false to true for production deployments?

 <rewrite> <rules> <rule name="SSL_ENABLED" enabled="false" stopProcessing="true"> <match url="(.*)" /> <conditions> <add input="{HTTPS}" pattern="^OFF$" /> </conditions> <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" /> </rule> </rules> </rewrite> 
+1
source

Move the fix to a separate answer, as pointed out by @AlexeiLevenkov.

 public class RemoteRequireHttpsAttribute : RequireHttpsAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentException("Filter Context"); } if(filterContext.HttpContext != null) { if (filterContext.HttpContext.Request.IsSecureConnection) { return; } var currentUrl = filterContext.HttpContext.Request.Url; if (currentUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.CurrentCultureIgnoreCase)) { return; } if (string.Equals(filterContext.HttpContext.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase)) { return; } if (filterContext.HttpContext.Request.IsLocal) { return; } var val = ConfigurationManager.AppSettings["RequireSSL"].Trim(); var requireSsl = bool.Parse(val); if (!requireSsl) { return; } } base.OnAuthorization(filterContext); } } 

and I also updated the ExitHttps attribute. It had similar problems ...

 public class ExitHttpsAttribute : FilterAttribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentException("Filter Context"); } if (filterContext.HttpContext == null) { return; } var isSecure = filterContext.HttpContext.Request.IsSecureConnection; var currentUrl = filterContext.HttpContext.Request.Url; if (!isSecure && currentUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.CurrentCultureIgnoreCase)) { isSecure = true; } if (!isSecure && string.Equals(filterContext.HttpContext.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase)) { isSecure = true; } if (isSecure) { //in these cases keep https // abort if a [RequireHttps] attribute is applied to controller or action if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof (RequireHttpsAttribute), true).Length > 0) { isSecure = false; } if (isSecure && filterContext.ActionDescriptor.GetCustomAttributes(typeof (RequireHttpsAttribute), true).Length > 0) { isSecure = false; } // abort if a [RetainHttps] attribute is applied to controller or action if (isSecure && filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof (RetainHttpsAttribute), true).Length > 0) { isSecure = false; } if (isSecure && filterContext.ActionDescriptor.GetCustomAttributes(typeof (RetainHttpsAttribute), true).Length > 0) { isSecure = false; } // abort if it not a GET request - we don't want to be redirecting on a form post if (isSecure && !String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { isSecure = false; } } if (!isSecure) { return; } // redirect to HTTP var url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; filterContext.Result = new RedirectResult(url); } } 
+1
source

Source: https://habr.com/ru/post/982251/


All Articles