0

I am designing an MVC based web application serving as a reporting dashboard, pulling data from a few different sources. In addition to my Home/View Controller, I've designed API Controllers per each service/data source and I am using Jquery/Ajax to query my API Endpoints.

I am also using Microsoft.Identity.Web/Web.UI to add authorization/authentication into my application and each Controller requires an authenticated user.

The issue I am having, the request being made by my JS of course asks for data from one of my API Controllers, then the API actually redirects me to login (even though I already have an authenticated cookie based session). The redirect is being blocked with the following error:

Access to XMLHttpRequest at 'https://login.microsoftonline.com/...(redirected from 'https://X.X.X.X:XX/v1/MicrosoftPlanner/') from origin 'https://X.X.X.X:XX' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I have attempted unsuccessfully to utilize Microsoft's CORS to allow the redirect - my last attempt was to allow everything like so:

ConfigureServices

public void ConfigureServices(IServiceCollection services)
        {
            string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');

            services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                    .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
                        .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
                            .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
                            .AddInMemoryTokenCaches();

            services.Configure<ParkMyCloudApiCredentials>(Configuration.GetSection("ParkMyCloud"));
            services.Configure<ServiceNowApiCredentials>(Configuration.GetSection("ServiceNow"));

            services.AddCors();

            services.AddControllersWithViews(options =>
            {
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            });
            services.AddRazorPages()
                    .AddMicrosoftIdentityUI();

            services.AddOptions();
        }

Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.CongfigureExceptionHandler();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseCors(builder =>
            {
                builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
            });

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });
        }

I am going off Microsoft Documentation here: https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-5.0#preflight-requests

It is my understanding that this is the absolute least restrictive, thus should serve as a basic case that would succeed. However, still have yet to figure out how to resolve this.

I know I could potentially use a proxy, but I am trying to avoid work arounds.

I've also looked at other posts on here, and thus far I haven't seen a solution that has also worked for me.

2 Answers2

1

From this doc, we can see that:

A CORS preflight request is used to determine whether the resource being requested is set to be shared across origins by the server. And The OPTIONS requests are always anonymous, server would not correctly respond to the preflight request if anonymous authentification is not enabled.

Access to XMLHttpRequest at 'https://login.microsoftonline.com/...(redirected from 'https://X.X.X.X:XX/v1/MicrosoftPlanner/') from origin 'https://X.X.X.X:XX' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

To fix the above issue, if you run the App(s) on local for testing purpose with CORS, you can try to enable anonymous authentification.

Besides, if your App(s) are hosted on IIS, you can try to install IIS CORS module and configure CORS for the app.

Zhi Lv
  • 10,958
  • 1
  • 6
  • 16
  • Thank you for the response. I tried what you suggested. I already had Anonymous Auth enabled, but I installed the CORS Module to my IIS Server, reran through the set up and I still can't overcome the issue. – Noah Eldreth Dec 17 '20 at 13:08
1

I contacted Microsoft dev assistance and it turns out you can't apply a CORS policy to the Azure AD login endpoint. I am attempting a work around with ADAL/MSAL.JS implicit grant flow.

  • [Microsoft docs](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/application-proxy-understand-cors-issues#option-5-extend-the-lifetime-of-the-access-token) (option 5 section) also state that this issue can't be resolved if it's specific to login.microsoftonline.com redirection. – Lukas Apr 08 '21 at 13:07
  • were you ever able to get a work around to work? – Lukas Apr 08 '21 at 14:52
  • I was able to resolve my issue, though I couldn't do so via frontend JS. What I actually ended up doing was splitting the application into 2 separate projects within 1 solution - a MVC Client Website and a Web API. The API is registered with Azure AD and my Client site has permissions in AD to request a token to API on behalf of the user. Without the ability to utilize JavaScript to persist a page - just updating content with silent requests - I had to be a bit creative in A. transferring data from C# to JS and B. persisting continuity between requests. – Noah Eldreth Apr 08 '21 at 18:17
  • The API now connects to all 3rd party interfaces. This bypasses my CORS Issue as requests all happen now server side, and now that I use JWT's in my requests I do not require a redirect to the Microsoft login endpoint. – Noah Eldreth Apr 08 '21 at 18:19