7

I would like to allow CORS requests to a common internal API from all internal websites (*.myintra.net) and also from all localhost ports (for when we are debugging various apps locally in IIS Express, i.e. http://localhost:12345, http://localhost:54321, etc).

This answer shows me how to use SetIsOriginAllowedToAllowWildcardSubdomains() to allow all subdomains.

This answer shows me how to allow any localhost port by using a SetIsOriginAllowed() delegate function.

However, it seems that these options do not work together. My configuration:

private bool AllowLocalhost(string origin)
{
    var uri = new Uri(origin);
    return (uri.Host == "localhost");
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        string[] corsList = "https://*.myintra.net,https://some.specificurl.com".Split(",");
        options.AddPolicy("CorsPolicy", builder =>
        {
            builder
            .WithOrigins(corsList.ToArray())
            .SetIsOriginAllowedToAllowWildcardSubdomains()
            .SetIsOriginAllowed(origin => AllowLocalhost(origin)) // disallows calls from myapp.myintra.net since it doesn't uri.Host match "localhost"
            ...();
        });
    });
    ...
}

I can swap the order of the configuration:

.SetIsOriginAllowed(origin => AllowLocalhost(origin))
.SetIsOriginAllowedToAllowWildcardSubdomains()

But then the AllowLocalhost() function is never called. I suppose it makes sense that only one works at a time, since the first check may return true, only to have the second one return false.

Ideally, I'd like a solution that doesn't involve me having to reimplement the allow wildcard logic inside of my AllowLocalhost() function.

Also worth noting that I really only need this in a development environment. Production would need to allow wildcards, but disallow localhost no matter the port.

djs
  • 1,660
  • 1
  • 17
  • 35
  • 1
    The logic that supports `SetIsOriginAllowedToAllowWildcardSubdomains` is [hidden behind an `internal` extensions class](https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/CORS/src/Infrastructure/CorsPolicyExtensions.cs#L9-L34), so there's no _clean_ way to get to it. – Kirk Larkin Mar 09 '20 at 22:34
  • were you ever able to find a solution for this? – josh Nov 25 '20 at 23:05

1 Answers1

6

That's the way I implemented it:

I'm checking the origin with the IsOriginAllowed:

    public void ConfigureServices(IServiceCollection services)
    {
        // ...

        services.AddCors(options =>
        {
            options.AddPolicy(name: "AllowedCorsOrigins",
                builder =>
                {
                    builder
                        .SetIsOriginAllowed(IsOriginAllowed)
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                });
        });
        // ...

Activate Cors as always:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
        // ...
        app.UseCors("AllowedCorsOrigins");
        // ...

That's the method, that should do the trick. Accept all requests from example.com and another-example.com including all subdomains. And if the ASPNETCORE_ENVIRONMENT the Service is running contains "DEV" than also allow localhost.

private static bool IsOriginAllowed(string origin)
{
    var uri = new Uri(origin);
    var env = System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "n/a";

    var isAllowed = uri.Host.Equals("example.com", StringComparison.OrdinalIgnoreCase)
                    || uri.Host.Equals("another-example.com", StringComparison.OrdinalIgnoreCase)
                    || uri.Host.EndsWith(".example.com", StringComparison.OrdinalIgnoreCase)
                    || uri.Host.EndsWith(".another-example.com", StringComparison.OrdinalIgnoreCase);
    if (!isAllowed && env.Contains("DEV", StringComparison.OrdinalIgnoreCase))
        isAllowed = uri.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase);

    return isAllowed;
}
Kay Meister
  • 61
  • 1
  • 3
  • 1
    Does this allow http and https requests? If so it might be good to add an additional check: `uri.Scheme == Uri.UriSchemeHttps` to prevent http calls (if that is wanted). – eddex Jun 16 '21 at 07:57
  • Great answer! Exactly what I needed. – kenswdev Oct 31 '21 at 17:10