2

I have two services running on Azure :

  • a web service ( angular app / expressjs )
  • an app service ( aspnet core app )

All the web service does is query the app service for the following endpoint : my-app-service.azurewebsites.net/.well-known/openid-configuration

My app service is setup to allow CORS requests coming from my web service at the code level via the IdentityServer4 dll and as mentioned in many websites I DID ensure CORS settings were neither overridden by web.config or azure CORS management page.

These are my HTTP request headers :

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Host:my-app-service.azurewebsites.net
Origin:http://my-web-service.azurewebsites.net
Pragma:no-cache
Referer:http://my-web-service.azurewebsites.net/

And these are my HTTP response headers

Content-Encoding:gzip
Content-Type:application/json
Date:Fri, 05 Jan 2018 17:22:53 GMT
Server:Kestrel
Set-Cookie:ARRAffinity=da4c4ff244aae03ae3c7548f243f7c2b5c22567a56a76a62aaebc44acc7f0ba8;Path=/;HttpOnly;Domain=Host:my-app-service.azurewebsites.net
Transfer-Encoding:chunked
Vary:Accept-Encoding
X-Powered-By:ASP.NET

As you can see, none of the Access-Control-* headers are present. I have added a custom middleware to the asp.net core app pipeline to trace the response headers and I can clearly see them present.

So somewhere Azure is stripping off my headers and I have no more clues where to look now.


Update #1

I forgot to specify that if everything runs on localhost, it works fine. But it does not on Azure.

Update #2

My identity server 4 code

[...]
using Microsoft.IdentityModel.Tokens;
using IdentityServer4.EntityFramework.Mappers;
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4;

namespace My.IdentityServer4
{
    public class Startup
    {
        private const string DEFAULT_DEVELOPMENT_AUTHORITY = "http://localhost:5000/";

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            // [... add db context. identity framework, default token provider]
            services.AddMvc();

            // Cors ( not required, identity server 4 manages it internally )
            //services.AddCors(options =>
            //    options.AddPolicy("AllowAllOrigins", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader()));

            string connectionString = Configuration.GetConnectionString("SQLServer");
            var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

            // configure identity server with in-memory stores, keys, clients and scopes
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddAspNetIdentity<ApplicationUser>()
                // this adds the config data from DB (clients, resources)
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                        builder.UseSqlServer(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                })
                // this adds the operational data from DB (codes, tokens, consents)
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                        builder.UseSqlServer(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));

                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                    options.TokenCleanupInterval = 30;
                });

            services.AddAuthentication()
                .AddOpenIdConnect("oidc", "OpenID Connect", options =>
                {
                    //TODO: enable HTTPS for production
                    options.RequireHttpsMetadata = false;
                    options.Authority = DEFAULT_DEVELOPMENT_AUTHORITY;
                    options.ClientId = "app"; // implicit
                    options.SaveTokens = true;
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role"
                    };
                });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // [... Some stuff before not useful for this snippet]

            // For debug purposes, print out request and response headers
            app.UseMiddleware<LogHeadersMiddleware>();

            app.UseStaticFiles();

            // Cors ( not required, identity server 4 manages it internally )
            //app.UseCors("AllowAllOrigins");

            app.UseIdentityServer();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }



    public class LogHeadersMiddleware
    {
        private readonly RequestDelegate next;
        private readonly ILogger<LogHeadersMiddleware> logger;

        public LogHeadersMiddleware(RequestDelegate next, ILogger<LogHeadersMiddleware> logger)
        {
            this.next = next;
            this.logger = logger;
        }

        public async Task Invoke(HttpContext context)
        {
            await this.next.Invoke(context);

            logger.LogInformation(
                $"------------------------\r\n" +
                $"*** Request headers ****\r\n" +
                string.Join("\r\n", context.Request.Headers.OrderBy(x => x.Key)) + "\r\n" +
                $"*** Response headers ***\r\n" +
                string.Join("\r\n", context.Response.Headers.OrderBy(x => x.Key)) + "\r\n" +
                $"------------------------\r\n");

        }
    }
}

Update #3 - CORS on Azure service app is not set

No CORS configured on Azure

Any hints ? Thanks

DarkUrse
  • 2,084
  • 3
  • 25
  • 33

2 Answers2

2

@NoName found the answer to my issue on this thread.

In a nutshell, https has to be enabled on Azure in order to work.

A warning from Azure in the logs would have been appreciated though. I wouldn't have lost days on this :S

DarkUrse
  • 2,084
  • 3
  • 25
  • 33
1

CORS on Azure service app is not set.

Actually, Azure website is supposed to manage CORS for you. You just need to set the CORS on the Azure service App. I also find a similar SO thread about it.

The good thing is that you can completely disable this middleware and manage CORS by your own means, you just have to remove every single allowed origin (including *) from the CORS settings blade in the portal.

enter image description here

Tom Sun - MSFT
  • 24,161
  • 3
  • 30
  • 47
  • Thank you for taking time to look at it. As I stated, I do not want to manage CORS via the Azure blade hence my screenshot with no value in it (update #3). I want to let the identityserver4 manage it via its own configuration table. – DarkUrse Jan 10 '18 at 08:17
  • If there is no value in the Azure portal CORS means that not turn on support CORS from server side. It is required if we want to use CORS. – Tom Sun - MSFT Jan 10 '18 at 08:24
  • This is from the link you gave me : `you just have to remove every single allowed origin (including *) from the CORS settings blade in the portal. Then you can use web.config or Web Api to handle it more specifically`. Which means that if I don't configure it on the azure interface, it will let my application deal with it. Or do I misunderstand it ? – DarkUrse Jan 10 '18 at 08:27
  • Sorry for making you misunderstanding. Based on my experience, you could do that with web.config. It also will map to server side setting. – Tom Sun - MSFT Jan 10 '18 at 08:32
  • I eventually want to do it with web API but I actually tried with web.config, however it didn't work either. Do you know how to trace all the headers sent and received by the IIS in between my kestrel server on Azure and the client ? I can see a log of the requests but no way to see the header detail. – DarkUrse Jan 10 '18 at 08:35
  • Have you refereced this [enable cors](https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api#enable-cors)? – Tom Sun - MSFT Jan 10 '18 at 08:41
  • 1
    This doesn't seem to be aspnet core link. But anyway in my case CORS is enabled via the IdentityServer4 code ( https://github.com/IdentityServer/IdentityServer4/blob/ec17672d27f9bed42f9110d73755170ee9265116/src/IdentityServer4/Hosting/CorsMiddleware.cs ) – DarkUrse Jan 10 '18 at 08:51
  • It still doesn't :) I'm just saying that CORS is enabled via web api from the identityserver4 dll. – DarkUrse Jan 10 '18 at 08:56