DenyAnonymousAuthorizationRequirement Error in Docker but works in Development - c#

I am getting the DenyAnonymousAuthorizationRequirement when trying to call a public API. Most of the API endpoints are secure but three are publicly available.
These three public APIs are called on the home page before the user logs in and surely this is not a unique situation so there must be a way you can have both in an application.
I am NOT seeing this error in the development environment but I am seeing it when I deploy to my docker container. I understand that DenyAnonymousAuthorizationRequirement is a part of the .NET core Policy-based authorization model.
What I understand from this article is I can specify endpoints to NOT apply the DenyAnonymousAuthorizationRequirement. This however is not working for me so either I am doing it wrong or this article doesn't apply to my situation.
Fortunately I am also in control of the API so I can provide the implementation.
[Route("[controller]")]
[ApiController]
public class MappingController : ControllerBase
{
[HttpGet]
[Route("businesses")]
[AllowAnonymous]
public async Task<IActionResult> GetBusinesses()
{
var result = await _mappingService.GetAllBizMapMarkersAsync();
return Ok(result);
}
}
In the app where I am getting the error I have specified in startup.cs what I thought would be an override for that endpoint based upon this article.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("Mapping", "/businesses").AllowAnonymous();
});
}
The app calls the API like this.
var response = await _client.GetAsync($"mapping/businesses");
This is the error.
[13:39:34 INF] Start processing HTTP request GET https://devapi.mysite.com/mapping/businesses
[13:39:34 INF] Sending HTTP request GET https://devapi.mysite.com:5150/mapping/businesses
[13:39:34 INF] Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
What can I try next?

Related

Is there any way to validate that a request to .NET Framework Web API is from our hosted portal?

I am using .NET Framework Web API, and I need to verify the API calls are from my hosted portal end.
Is there any method to validate request and block requests?
I used CORS to validate, and I don't know if that is the best practice to verify.
Your question is not clear. if you want to verify the API calls from your hosted portal and block other domain the best way is to use the Cross Origin Resource Sharing (CORS):
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: AllowPortalDomain,
policy =>
{
policy.WithOrigins("http://PortalDomain.com");
});
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseCors(AllowPortalDomain);
...
}
You can enable Cross-Origin Requests per controller or action:
[EnableCors("AllowPortalDomain")]
[HttpPost]
public IActionResult yourAPI(){...}
for more information see this link CORS
hope this helps!

Getting 'Access-Control-Allow-Origin' error when I call External WebApi

I found a lot of pages regards to this issue, but none of the Solutions worked.
I have a JavaScript Button in the View that is calling a WebApi method(C#)
$('#btn-Sign-in', this).click(function () {
var apiUrl = 'https://localhost:44391/api/test';
fetch(apiUrl).then(response => {
return response.json();
}).then(data => {
// Work with JSON data here
console.log(data);
}).catch(err => {
// Do something for an error here
});
});
This is My Webapi method that is calling external api:
[RoutePrefix("api")]
public class TestController : ApiBaseController
{
[HttpGet]
[Route("redirectforauth")]
[RequiresPermission("Home:View")]
[HttpGet]
[Route("test")]
[RequiresPermission("Home:View")]
public async Task<IHttpActionResult> ConnectExternal()
{
var request = new FlurlRequest("URL of an external website")
.SetQueryParam(...)
.SetQueryParam(...)
.SetQueryParam(...)
.SetQueryParam(...);
var redirectUrl = request.Url.ToInvariantString();
return Redirect(redirectUrl);
}
when I am running the project, I am getting this error:
CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
This error is due to your web application URL & C# API URL are not having same origins (not running on same port or same hosts). Two URLs have the same origin if they have identical schemes, hosts, and ports.
EX: Your C# URL https://localhost:44391 is different from your web application URL.
First, to make sure that you are getting the error due to your c# api & not due to the external api, comment out your external api request code inside your action, and return something directly from your api to web application. (If the error is from external Api, that external api needs to handle this to allow access to other origins.)
If you are getting the error due to your c# api & not due to the external api, one approach to do this is, by enabling CORS in your C# WebApi application. You can enable CORS per action, per controller, or globally for all Web API controllers in your application.
You can install this nuget package in your C# API application:
Microsoft.AspNet.WebApi.Cors
In App_Start/WebApiConfig.cs, add this code to the WebApiConfig.Register method:
config.EnableCors();
Next, add the [EnableCors] attribute to your TestController class, with your web application URL.
Ex: if your web application URL is localhost:3000, add it in origins as below.
[EnableCors(origins: "http://localhost:3000", headers: "*", methods: "*")]
public class YourController : ApiController {
// Your methods...
}
Now the AJAX request from your Web Client should work. The GET, PUT, and POST methods are all allowed.
For more details on how to enable CORS & how it works:
Enable cross-origin requests in ASP.NET Web API 2

Get Current URL as soon as available program.cs / startup.cs in ASP.NET Core

Goal: To GET the URL in browser ASAP on running the ASP.NET Core 2.2 Web application.
What I tried was nearly every sort of hackery inside of Startup.cs , which sure you can use DI for registering the IHttpContextAccessor to get access to HttpContext
Some people will say to use
var url = HttpContext?.Request?.GetDisplayUrl();
You can use this in a Controller, but if you go to definition you see that the HttpContext is coming from the ControllerBase of Mvc etc..
Seems to be several postings about this and no solutions.
I am seeing to build middleware - great, but I don't know how to really do that
I seen an article about middleware and call the Invoke Method, but How and Where etc..? Current URL in ASPCore Middleware?
Seems like I just want what I had in global.asax in "classic" .net with the URL etc..
I see that Program calls Startup.cs with the .UseStartup<Startup>();
Is it possible to get access to be able to END GOAL to get the URL like http://localhost:4444
All I want ...
var url = HttpContext?.Request?.GetDisplayUrl();
to show my URL as soon as .net core in a class library / startup / program.cs will let me see URL like http://localhost:4444
For handing request, you could try ASP.NET Core Middleware.
A simple middleware like below:
public class Startup
{
//rest code
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use((context,next) =>
{
var url = context.Request.GetDisplayUrl();
return next.Invoke();
});
//rest code
}
}
For using GetDisplayUrl(), add
using Microsoft.AspNetCore.Http.Extensions;

Windows authentication on web.api

I have a self-hosted Web API application (the server application) that uses Windows authentication.
Windows Auth is enabled in Startup.cs/Configuration by setting the following AuthenticationSchemes on System.Net.HttpListener
System.Net.HttpListener listener = (System.Net.HttpListener)appBuilder.Properties["System.Net.HttpListener"];
listener.AuthenticationSchemes = System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication
| System.Net.AuthenticationSchemes.Anonymous;
And Controllers then use the [Authorize] tag. I can then extract the Principal.Identity from the HttpRequestContext for every controller method to see who’s making the call.
It appears this is only working if the caller and server are on the same host. As soon as the calling application is on another host, all requests are blocked with a 401 unauthorized and no controller method is ever hit on the server. This is even if the calling application is executed under the same user account that the server. So is there a special config required so Windows authentication on web.api works across different machines?
Regards meisterd
In the Startup class of your WebAPI, add a call to use CORS. You may need to add Microsoft.Owin to you packages if you don't already have it. This should allow access to your api from other hosts.
It should look something like this:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
//... Your other startup code
appBuilder.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

Log to database when authorization fail on Web API [Net.Core]

I have a .Net Core Web API with Custom Policy-Based Authorization (policies that check for claims and claims values on a JWT).
I need to log (to a database) every time a user call a Web API function, even when the authorization fail (especially on failures).
To do that I override these methods OnActionExecuting and OnResultExecuted (because i want to log every request on one filter, and, in other filter, the result of the request). But, if the Authorization fail, both filters never were trigged.
That's because the Authorization filter goes before the other filters (and if the request is unauthorized, short-circuit the pipeline).
So, when a user call a method without authorization I can't log it (i'm using Serilog to write a log file on the server, and works fine when authorization fail, but I want to log it to the database like when authorization is fine).
I try to write some filter before or after Authorization but I couldn't do it. May be i'm not thinking in the right way, and is more simple.
I read all this, but i couldn't figured out yet:
ASP .Net Core Filters
ASP .NET Core Custom Policy-Based Authorization
Asp.Net Core policy based authorization ends with 401 Unauthorized
How do you create a custom AuthorizeAttribute in ASP.NET Core?
Custom authorization attribute in .NET Core
Thanks!
Have you tried the following options:
Using a global filter where you override the order, something like:
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc(options =>
{
options.Filters.Add(typeof(MyLoggingFilter), -2);
options.Filters.Add(typeof(MyAuthFilter), -1);
});
}
For attribute based filters you can implement IOrderedFilter
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
internal sealed class MyAuthorizationAttribute : Attribute, IAuthorizationFilter, IOrderedFilter
{
public int Order => -2;
}
Inject a logger to the AuthFilter itself
public MyAuthFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<MyAuthFilter>();
}
Sounds like you want to log higher in the .NET pipeline?
You could take a look at the DelegatingHandler class rather than filters. These handlers are executed much higher in the pipeline, before your auth filters.
public class MyLogMessageHandler : DelegatingHandler
{
protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Do logging with request or HttpContext.Current
}
}
In your global.asax.cs (or equiv), u would then register the handler:
GlobalConfiguration.Configuration.MessageHandlers.Add(new MyLogMessageHandler());
Take a look at When to use HttpMessageHandler vs ActionFilter?
Also, we have an API logging and analytics solution that may helpful especially if you're on Azure since there is an Azure extension. https://www.moesif.com/features (full disclosure I am the CEO)

Categories