2

I'm having an ASP.NET Core application hosted on a linux container in the SAP Cloud environment (Cloud-Foundry).

I am implementing Azure AD authentication using the Microsoft.AspNetCore.Authentication.AzureAD.UI libraries.

The authentication fails because no matter what protocol I initially access the web application, it generates the redirect_uri with the http protocol.

This fails because it does not match the https url defined in the app-registration in Azure.

AADSTS50011: The reply url specified in the request does not match the reply urls configured for the application

In the options, you can pass in the CallbackPath, but this only accepts a relative path (must start with /). Otherwise it's coming from the redirect_url which is automatically generated based on the scheme, host, port and path extracted from the current request.

What I don't understand is that even when I access the application directly in the browser with https, it still uses http in the redirect_uri.

I guess the underlying problem is that the application hosted in Cloud Foundry accepts http requests.

Here's the code parts of how I implemented the Azure AD Authentication.

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        .AddAzureAD(options => Configuration.Bind("Authentication:AzureAD", options));

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
   {
       options.Authority = options.Authority + "/v2.0";            // Microsoft identity platform
       options.TokenValidationParameters.ValidateIssuer = true;   
   });


 app.UseHsts();
 app.UseHttpsRedirection();


  "Authentication": {
    "AzureAD": {
      "Instance": "https://login.microsoftonline.com/",
      "ClientId": "{app-application-id}",
      "TenantId": "{my-tenant-id}"
    }
  }
Ronald
  • 1,990
  • 6
  • 24
  • 39

2 Answers2

4

Tony Ju provided an excellent link to a similar issue, helping me to narrow down and eventually fix my issue.

However, that solution only provides code examples, I'd like to write a little bit more how I got to the final implementation.

The problem is related when your application is behind a proxy server and/or load balancers. The proxy obscures information about the initial request, such as the original schema, making services in your application that rely on this information behave incorrect (such as the return_url).

There is an excellent documentation about how to configure your ASP.NET Core application.

From the document, here's the root cause of my issue.

When HTTPS requests are proxied over HTTP, the original scheme (HTTPS) is lost and must be forwarded in a header.

And the Cloud Foundry Security documentation tells the following:

Protocols All traffic from the public internet to the Cloud Controller and UAA happens over HTTPS. Inside the boundary of the system, components communicate over a publish-subscribe (pub-sub) message bus NATS, HTTP, and SSL/TLS.

In short, you need to forward certain HttpHeaders with the use of a standard Middleware.

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = 
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

app.UseForwardedHeaders();

However there is a known issue with .net core 2.1 when your app is deployed on a linux machine with no IIS as a proxy. This becomes even more visible when you add the UseHttpRedirection middleware.

Taken from this blog post:

OAuth and OIDC also fail in this configuration because they generate incorrect redirects. Calls to UseIISIntegration add and configure forwarded headers middleware when running behind IIS, but there’s no matching automatic configuration for Linux (Apache or Nginx integration). The fix for this issue is discussed in more detail in the doc article Forward the scheme for Linux and non-IIS reverse proxies.

This post eventually also provides the working fix for the current situation.

    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | 
            ForwardedHeaders.XForwardedProto;
        // Only loopback proxies are allowed by default.
        // Clear that restriction because forwarders are enabled by explicit 
        // configuration.
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
    });

Looks like this is no longer needed for .net core 3, but SAP has not yet updated their dotnet container yet, so I cannot verify it at the time of writing.

Ronald
  • 1,990
  • 6
  • 24
  • 39
1

Your issue is similar to this one. The difference is that you deployed the app in cloudfoundry, the other one deployed the app in Azure web app.

If your app is forced to use https, you can simply force the redirect_uri to use https.

If you want a common solution that both http and https will work(the premise is that you have configured both http and https as the redirect url in azure portal), you can try to find the real proto in the headers.

Tony Ju
  • 14,891
  • 3
  • 17
  • 31
  • Thank you for pointing out this link, which is indeed the same as mine. So the issue seems to be related with linux environments and proxies. There are some interesting points I did not know such as the `ForwardHeadersOptions`. I temporary shelved this to focus on some other features, but will pick it up again next week. I'll update as it moves along. – Ronald Dec 18 '19 at 11:14