Hopefully I'm just missing something really simple/obvious - why, and more importantly, how do you maintain (or force) the protocol during the redirect to Login
?
To illustrate:
- the original protocol is
https
one would think this should be the "default" for something likelogin
, but as shown, the redirect (seems) doesn't maintain it.
Stuff I tried:
There is a
RequireHttps
attribute that one could use, but:- seems "weird" that it would take 2 redirects to get "there"
- in situations where you have a load balancer and/or have SSL "offloaded" elsewhere (not in server), then this would then be a redirect loop (SSL is between client and front-end net/ssl lb, and
http
to your box(es)/application). This is actually my production case...
I have already set IIS URL re-write as well (aka canonical rule to https for entire site),
and that seems "ignored" (too)(rule does not check for "https" otherwise it suffers same redirect loop).tried and failed to set absolute URL in
LoginPath
(inCookieAuthenticationOptions
)..because you can't do that...
Thanks for advice or pointers...
Update
As to the "why"?
- in situations where you have a load balancer and/or have SSL "offloaded" elsewhere (not in server), then this would then be a redirect loop (SSL is between client and front-end net/ssl lb, and
http
to your box(es)/application). This is actually my production case..
Further tinkering got me to the above, as shown in this (localhost - my local dev box, not server) request sequence (the above issue manifests in a production load balanced environment where SSL processing is "up the stack" - e.g. ARR):
- the protocol is in fact maintained
- the issue seems exactly related to the situation where the application and the "infrastructure" don't "match". It seems similar to the situation where in code, you would do a
Request.IsSecureConnection
in a "load balanced"/"web farm" environment (say ARR where thecert
is in your ARR, not in your host/s). That check will always returnfalse
in such a situation..
So the question really is on guidance on how to get around this?
Update 2
Many thanks to Richard for changing my "direction" in trying to resolve this. I originally was looking for a way to:
set/tell OWIN/Identity to use a secure URL (explicitly) and "override" the way it evaluates
LoginPath
. TheSecure
(only) option in handling cookies somehow led me that way (if I can explicitly say cookies in HTTPS only, then it sort of gave me an impression of being able to do so forLoginPath
..one way or the other)a "hacky" way in my mind was to just deal with it client side (Javascript).
In the end, Richard's answer took me to URL Rewriting (though still not on the LB side because that's beyond my control). I'm currently working off of (based on my environment):
<rule name="Redirect to HTTPS" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_CLUSTER_HTTPS}" pattern="^on$" negate="true" />
<add input="{HTTP_CLUSTER_HTTPS}" pattern=".+" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{SCRIPT_NAME}/{REQUEST_URI}" redirectType="SeeOther" />
</rule>
and see some light at the end of the tunnel.
Update 3
Awesome thanks again to Richard for the sleuthing! Latest answer got me sleuthing too and it turns out there's quite a few posts here on SO related to CookieApplyRedirectContext...so now this what I have in place (which is specific to my case), and is what I was originally going after:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
//This is why. If I could explicitly set this, then I (thought) I should
//be able to explicitly enforce https (too..as a setting)
//for the LoginPath...
CookieSecure = CookieSecureOption.Always,
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = .....
,
OnApplyRedirect = context =>
{
Uri absoluteUri;
if (Uri.TryCreate(context.RedirectUri, UriKind.Absolute, out absoluteUri))
{
var path = PathString.FromUriComponent(absoluteUri);
if (path == context.OwinContext.Request.PathBase + context.Options.LoginPath)
{
context.RedirectUri = context.RedirectUri.Replace("http:", "https:");
}
}
context.Response.Redirect(context.RedirectUri);
}
}
});