Azure API - How do I setup CORS - asp.net

I have REST API, that is hosted in Azure. If I make request in interactive console with GET method ('/api/pets'), request goes through just fine. But when I make POST request (POST '/api/pets'), CORS error appears.
Response in interacive console throws this error:
startup.cs
public void ConfigureServices(IServiceCollection services)
{
.
.
.
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
}));
.
.
.
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors("CorsPolicy");
.
.
.
}
All API's CORS policy
<policies>
<inbound>
<cors>
<allowed-origins>
<origin>*</origin>
</allowed-origins>
<allowed-methods preflight-result-max-age="300">
<method>GET</method>
<method>POST</method>
<method>PUT</method>
<method>DELETE</method>
<method>HEAD</method>
<method>OPTIONS</method>
<method>PATCH</method>
<method>TRACE</method>
</allowed-methods>
<allowed-headers>
<header>*</header>
</allowed-headers>
<expose-headers>
<header>*</header>
</expose-headers>
</cors>
</inbound>
<backend>
<forward-request />
</backend>
<outbound />
<on-error />
</policies>
I also tried setting CORS policy on azure portal only in specific API, but it doesn't work
Everything works fine locally.

Can you try configure this using the portal?
Open your API in the Azure API Management section of the Azure portal
Select All operations, or a single operation
On the right, choose Inbound processing > Add policy
You will get a list of prefab policy templates. Choose the "CORS" one and configure it at will:
UPDATE:
Can you modify the XML as below
<cors>
<allowed-origins>
<origin>*</origin>
</allowed-origins>
<allowed-methods>
<method>*</method>
</allowed-methods>
<allowed-headers>
<header>*</header>
</allowed-headers>
<expose-headers>
<header>*</header>
</expose-headers>
</cors>

Few years ago I tried Outboud rules into API Managment Policies to add this headers to response:
<policies>
<inbound>
<base />
<cors allow-credentials="true">
...
</cors>
</inbound>
...
<outbound>
<base />
<set-header name="Access-Control-Allow-Origin" exists-action="override">
<value>#(context.Request.Headers.GetValueOrDefault("Origin",""))</value>
</set-header>
<set-header name="Access-Control-Allow-Credentials" exists-action="override">
<value>true</value>
</set-header>
</outbound>
...
</policies>
Also make sure that you are using app.UseCors() before response compression if exists and before app.UseEndpoints() or app.UseMvc()

Related

NLog ApplicationInsightsTarget unable to read application insights key from appsettings.json

I am trying to read the application insights instrumentation key from appsettings.json file in my ASP.NET Core 3.1 Web Application but all my tries went in vain so far as the target is still showing as unconfigured.
If I add the key directly in ApplicationInsightsTarget, then it is working fine.
Here is the content of appsettings.json file:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"AppInsightsKey": "Instrumentation-Key-From-Azure-Application-Insights-Resource"
}
Here is the content of nlog.config file:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
throwConfigExceptions="true"
internalLogLevel="info"
internalLogFile="c:\temp\internal-nlog-AspNetCore3.txt">
<!-- enable asp.net core layout renderers -->
<extensions>
<add assembly="Microsoft.ApplicationInsights.NLogTarget" />
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<!-- the targets to write to -->
<targets>
<!--Console Target for hosting lifetime messages to improve Docker / Visual Studio startup detection -->
<target xsi:type="Console" name="lifetimeConsole" layout="${configsetting:item=AppInsightsKey} ${level:truncate=4:lowercase=true}: ${logger}[0]${newline} ${message}${exception:format=tostring}" />
<target name="aiTarget" xsi:type="ApplicationInsightsTarget"
layout="${date:format=yyyy-MM-dd HH\:mm\:ss}: [LOCAL] - ${level} - ${message}${exception:format=ToString}">
<instrumentationKey>${configsetting:item=AppInsightsKey}</instrumentationKey>
<contextproperty name="threadid" layout="${threadid}" />
</target>
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Trace" writeTo="lifetimeConsole" />
<logger name="*" minlevel="Trace" writeTo="aiTarget" />
</rules>
</nlog>
As you can see from above, I was trying to grab the application insights key from appsettings.json file by ${configsetting:item=AppInsightsKey}, but in all occasions it's coming as empty.
I've tried with ${configsetting:name=AppInsightsKey} , which didn't help either.
This is the program.cs file content
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Web;
using System;
namespace ASPNETCoreWebAppNLogAppInsightsDemo
{
public class Program
{
public static void Main(string[] args)
{
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
logger.Debug("init main");
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
//NLog: catch setup errors
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseNLog(); // NLog: Setup NLog for Dependency injection
}
}
Then I've tried to embed the key in the console target layout, just to ensure nlog is able to read it correctly, which to my surprise is working perfectly fine. So, looks like the issue is with ApplicationInsightsTarget only.
I know, I can pull it from Environment variables and hence in Azure App service it is not required to read from appsettings.json, but I would like to understand about this behavior since already spent too much time fixing myself :-)
Any help will be appreciated.
Try replacing the old code:
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
With this new code:
var logger = LogManager.Setup()
.LoadConfigurationFromAppSettings()
.GetCurrentClassLogger();
The new code will load the appsettings.json, and sure that ${configsetting} are available during initialization of NLog Targets.

ASP.NET MVC CORS issue

I have an ASP.NET MVC application (.NET 4.6) where on one occasion I need to redirect to a different domain.
So the code is like this (only authenticated users can come to the controller):
public ActionResult UploadForDesign(int parcelId)
{
......
string url = "differentdomain/parcelId" ;
return ReDirect(url);
}
I am getting an error:
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin'.....
Failed to load resource: net::ERR_FAILED
I did the following in the control before redirect call
HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
and I still get the same error.
Also I tried the following in web.config, but didn't help much.
<httpProtocol>
<customHeaders>
<clear />
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
Now I had another test bare ASP.NET MVC app (.NET 4.5.2) with no authentication, and the above code works fine. I checked all the code and it looks the same except authentication in place and the framework version.
Any idea what to do?
You can try to use the WithOrigins method on your CORS policy and add whatever domain you need:
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder =>
.WithOrigins("http://localhost:4200/")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
Ahhh sorry. I believe you should be able to use something like:
var p = new CorsPolicy();
p.AllowAnyHeader = true;
p.AllowAnyMethod = true;
p.AllowAnyOrigin = false;
p.Origins.Add("http://localhost:4200/");

How can I configure an OpenID Connect for Steam in ASP.NET Core 2?

I am attempting to authenticate and login users through the Steam API using ASP.Net Core 2.
I'm having limited success. I think I need the following parameters:
providerURL: 'http://steamcommunity.com/openid',
stateless: true,
// How the OpenID provider should return the client to us
returnURL: 'http://localhost:4000/auth/openid/return',
realm: 'http://localhost:4000/',
I am attempting to add the authentication via the AddOpenIDConnect mechanism.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication().AddOpenIdConnect(steamOptions =>
{
steamOptions.ClientId = "<APIKEY>";
steamOptions.ClaimsIssuer = "https://steamcommunity.com/openid";
}
This doesn't work. Clearly, there has to be a better way to call this.
One noticeable thing I've encountered: a GET request with Postman returns an XML file:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="0">
<Type>http://specs.openid.net/auth/2.0/server</Type>
<URI>https://steamcommunity.com/openid/login</URI>
</Service>
</XRD>
</xrds:XRDS>
Is there any way we can force services.AddAuthentication() to parse XML?
I solved this with the AspNet.Security.OpenID.Steam library that Kévin Chalet just recently built. You'll need to use the 2.0.0-rc2-final for ASP.Net Core 2.
All you need to do is add services.AddAuthentication().AddSteam() into ConfigureServices, like so (it's not the only service in there):
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication().AddSteam();
}
Note that you'll need the other default services generated by the Asp.Net Core 2 Web MVC template and Identity installed.

Server application has enabled CORS yet client gets "Access-Control-Allow-Origin" error

I have an RESTful API and I've added this to allow Cross-origin request
public static void Register(HttpConfiguration config)
{
...
// Allow Cross-origin request
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors();
...
}
My client is an AngularJS application calling the server like this
var json = JSON.stringify({
Request: 'INIT'
}),
req = {
method: 'GET',
url: 'http://localhost:51615/api/Call/2/' + json
}
$http(req)
.then(function(response){
console.info('response', response)
})
.catch(function(error){
console.error(error);
})
Even thou Cross-origin should be allowed I still get this error
XMLHttpRequest cannot load
http://localhost:51615/api/Call/2/%7B%22Request%22:%22INIT%22%7D. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:86' is therefore not allowed
access. The response had HTTP status code 400.
How can this be?
Big thanks to #shaunhusain for pointing out that I should take a look at the network response in chrome. Here I saw that the problem was with unsafe data in my url string (the json part). Changing the request from get to post along with json as data and not part of the url fixed my problem
try with putting this two appsettings in web.config of your web api project
<configuration>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<appSettings>
</configuration>

Hangfire.io Dashboard mapped to IIS Virtual Directory

I'm having trouble getting the Hangfire (1.5.8) dashboard to work inside of an IIS Virtual Directoy. Everything works beautifully in my dev environment where my application is simply mapped to the root of localhost. Our beta server, on the other hand, uses Virtual Directories to separate apps and app pools.
It's an ASP.Net MVC site using Hangfire with an OWIN Startup class. It gets deployed to http://beta-server/app-name/. When I attempt to access either http://beta-server/app-name/hangfire or http//beta-server/hangfire I get a 404 from IIS.
For the purposes of troubleshooting this, my IAuthenticationFilter simply returns true.
Here is my Startup.cs, pretty basic:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
GlobalConfiguration.Configuration
.UseSqlServerStorage(new DetectsEnvironment().GetEnvironment());
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
AuthorizationFilters = new[] {new AuthenticationFilter()}
});
app.UseHangfireServer();
}
}
Does anyone have a working implementation that gets deployed to a Virtual Directory? Are there any OWIN middleware admin/management tools I can use to dig into what URL is getting registered within IIS?
I ended up fixing this simply by adding the HTTPHandler to the section in web.config.
<system.webServer>
<handlers>
<add name="hangfireDashboard" path="hangfire" type="System.Web.DefaultHttpHandler" verb="*" />
</handlers>
</system.webServer>
I had a similar issue in ASP.NET Core 2.0 and it required proper authorization setup (I use a middleware to protect the route, so I did not rely on authorization in my example):
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new [] {new HangfireDashboardAuthorizationFilter()}
});
/// <summary>
/// authorization required when deployed
/// </summary>
public class HangfireDashboardAuthorizationFilter : IDashboardAuthorizationFilter
{
///<inheritdoc/>
public bool Authorize(DashboardContext context)
{
// var httpContext = context.GetHttpContext();
// Allow all authenticated users to see the Dashboard (potentially dangerous).
// handled through middleware
return true; // httpContext.User.Identity.IsAuthenticated;
}
}
There is not need to change anything in web.config.
For more information check Hangfire documentation about this topic.
I had the exact same problem. In my case, this was because of bad configuration - the Startup class was not called. So try to add the following to your config file:
<add key="owin:appStartup" value="YourProject.YourNamespace.Startup, YourProject" />
<add key="owin:AutomaticAppStartup" value="true" />
Hope this helps.
Martin

Resources