0

We have an ASP Core 2.0 App working nicely with Azure AD on a public network. Our Test environment is running in an Azure ASE. The user starts with a public address that passes through the Azure Application Gateway and gets routed to 1 of 2 App servers in the ASE. The application is registered in Azure AD with response URL's that specify the public address.

The problem is when the user redirects to login, the request address presented to Azure AD is an internal address from one of the 2 servers. Then the response URL's don't match and we get an error at login.

The question is how to present the public address to Azure AD so the response URL's match and the token is posted back to the app using the same? The app gateway, I'm told, is configured to populate x-forwarded-for header which has the original address. I don't see where in the web application this can be controlled. startup.cs

        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
         .AddAzureAd(options =>
         {
             Configuration.Bind("AzureAd", options);
             AzureAdOptions.Settings = options;
         })
         .AddCookie();

AccountController.cs

    public IActionResult SignIn()
    {
        var redirectUrl = _azureAdOptions.WebBaseUrl;
        return Challenge(
            new AuthenticationProperties { RedirectUri = redirectUrl },
            OpenIdConnectDefaults.AuthenticationScheme);
    }

I would think this is a common configuration - passing public to private servers with SSO integrated.

[Edit]

Based on the link provided in the comments, which was very helpful, we tried several things including explicitly setting UseforwardedHeaders in startup.cs even though this is supposed to be enabled by default. Nothing we did changed the URL bolded in the URL below.

https://login.microsoftonline.com/2ff13e34-f33f-498b-982a-7cb336e12bc6/oauth2/authorize?client_id=998c48ae-bbcf-4724-b6f4-6517e41d180a&redirect_uri=**http%3A%2F%2Flocalhost%3A2345%2Fsignin-oidc**&resource=https%3A%2F%2Fgraph.windows.net&response_type=id_token%20code&scope=openid%20profile&response_mode=form_post......

However, and maybe this is a clue, if we comment out the [Authorize] on the home controller and login after the user clicks a button to login, it works. Why?

Note: IDs/GUIDs above have been scrambled to protect the innocent

user2503078
  • 737
  • 1
  • 8
  • 24
  • Maybe this will help: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1 – juunas Jul 12 '18 at 06:14
  • @juunas that document was helpful, thank you, but didn't help resolve the problem. I updated the post based on the findings. – user2503078 Jul 16 '18 at 21:08

1 Answers1

0

I came across this post explaining how Application Gateway did not implement the standard x-forwarded-host headers. I'm hoping this gets fixed so the code below would not be required. The solution that worked in our configuration was to force both the public domain and scheme (HTTPS) on every request because the app gateway wasn't (and apparently couldn't be) configured to pass SSL to the backend servers.

Added to startup.cs

            app.Use((ctx, next) =>
            {
                ctx.Request.Host = new HostString(options.Value.CustomDomain;
                ctx.Request.Scheme = "https";
                return next();
            });

Now when the application redirects for any secure resource -- [Authorize] controller methods, or code that explicitly calls Challenge(x, y, z) the public domain on HTTPS is used as the origin host and scheme. Thanks to @juunas for pointing in the right direction.

user2503078
  • 737
  • 1
  • 8
  • 24