5

I'm trying to deploy an ASP.NET MVC web application, which uses individual user accounts, to an AWS server, which is using an elastic load balancer (ELB). I've deployed the site to IIS on the AWS app server, connected it to my AWS SQL server, and it works as expected on the server (and indeed when I run it in Visual Studio or deploy to an internal server).

The problem comes when accessing it remotely, which of course goes via the ELB.

So basically, if I'm logged in, it's fine. If I'm not logged in, the login page is fine but nothing else is. My thinking, along with a colleague from our internal team who works with AWS (he isn't able to help me btw, I've asked!) is that when I get redirected to the login page, it's a HTTP request and not HTTPS, and that's the cause of the issue, but no matter what I've tried I can't get it to redirect with HTTPS. I've tried:

  • adding rules in my web.config file to pick up forwarded requested and redirect them to HTTPS - which doesn't seem to have made any noticeable difference
  • various different attributes added to either my FilterConfig or the Login action
  • adding rules directly in IIS using URL Rewrite

Obviously my workaround is to get everyone to go to the login page and start there rather than just the root URL, but I'd really like to get this sorted as if redirecting doesn't work here, I can see it not working elsewhere and potentially causing issues.

Update as requested: I don't actually have any control over my ELB as that's done by a different team, but my understanding from speaking to the team is that it accepts traffic as HTTPS and then passes it on to the server as HTTP.

  • Please update your question to include the configuration of your ELB listeners. It sounds like your ELB is configured to accept HTTPS (load balancer port), and pass traffic on to your server as HTTP (instance port), but would like to verify. You can view this from the AWS Web Console under EC2 > Load Balancing > Load Balancers. If not making the request as HTTPS is indeed the issue, this is also where you would be able to fix it. – Anthony Neace Oct 28 '16 at 15:41
  • @AnthonyNeace updated - I'm pretty sure that you're correct and that's how it's set up – alfredbulbasaur Oct 28 '16 at 15:57
  • In your `web.config` file, what is the `loginUrl` value in the `forms` element? – Matt Houser Oct 28 '16 at 15:57
  • @MattHouser I don't have a `forms` element in my `web.config` - I have ``, which I believe was from the original ASP.NET MVC template – alfredbulbasaur Oct 28 '16 at 16:01
  • 1
    Then what is in your MVC application that's enforcing the sign-in redirect? There's something in your MVC app that's (a) requiring `DashboardController` to require authorization, and (b) what page to redirect to to get the user to sign-in. – Matt Houser Oct 28 '16 at 16:03
  • @MattHouser on each of my controllers I have an attribute called `ExpiredPasswordAttribute` which extends `AuthorizeAttribute` - basically what that is doing is checking if the user is logged in, and if so it checks to see when they last set their password, and if that exceeds a limit set then it redirects them to the Manage/ChangePassword page to change it. I'm not aware of it explicitly stating anywhere in my application to redirect to Account/Login when you're not signed in; I'm assuming it's a convention within ASP.NET MVC. – alfredbulbasaur Oct 28 '16 at 16:07

1 Answers1

3

Your MVC application is configured to redirect to an absolute http URL rather than a relative URL when the user needs to sign-in.

For new MVC applications that are based on the Owin middleware, this is configured in App_Start/Startup.Auth.cs.

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    {
        // Enables the application to validate the security stamp when the user logs in.
        // This is a security feature which is used when you change a password or add an external login to your account.  
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    }
});

and add the following after the OnValidateIdentity property:

OnApplyRedirect = ApplyRedirect  

Then, later in the class, add the following function:

private static void ApplyRedirect(CookieApplyRedirectContext context)
{
    Uri absoluteUri;
    if (Uri.TryCreate(context.RedirectUri, UriKind.Absolute, out absoluteUri))
    {
        context.Response.Redirect(absoluteUri.PathAndQuery);
        return;
    }

    context.Response.Redirect(context.RedirectUri);
}

Basically, this is converting the absolute URL to a relative URL. The relative URL then is passed back to the browser. Since the redirect is relative, it should maintain the https URL.

Matt Houser
  • 33,983
  • 6
  • 70
  • 88
  • I have updated my answer based on an MVC Owin application which returns an absolute `Location:` redirect. This answer provides a way to convert it to relative. – Matt Houser Oct 28 '16 at 16:40
  • This makes sense - it's not currently making any difference on my pre-production server but then I'm not getting redirected at all on there at present, just a 500 error so I suspect that I've broken something else along the way. Will give it a proper try once I've sorted everything with this environment. – alfredbulbasaur Oct 28 '16 at 17:37
  • It seems that I wasn't actually getting a 500 error, must have been something with my cache as when I tried it on a different computer it worked fine, then when I cleared cookies etc it worked fine. But this has resolved the issue - many many thanks! – alfredbulbasaur Oct 28 '16 at 17:50