Windows authentication on web.api - c#

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);

Related

Is Azure storage supported in Azure Static Web App functions?

I'm working on an API for an Azure Static Web App. The web app is implemented in Angular (although that isn't important for this question), and the API is implemented in C# (NET 6). Deployment to Azure is via a GitHub action.
I can create an HTTP trigger API endpoint that works fine, like so:
public static class Tester
{
[FunctionName("Tester")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "v1/tester")] HttpRequest req,
ILogger log)
{
return new OkObjectResult("Hello World");
}
}
I'm also able to access this directly via the SWA URL: https://<sitename>.azurestaticapps.net/api/v1/tester.
However, as soon as I add a reference to an Azure storage NuGet package to the project file (specifically Microsoft.Azure.WebJobs.Extensions.Storage.Blobs), making no other changes to the code, the API endpoint no longer works once deployed (although it will work locally).
On deploying the code with that package referenced in the .csproj, hitting the API endpoint gives a 503 status code with the response:
Function host is not running.
I enabled Application Insights for this static web app, and a CryptographicException is being thrown on startup:
An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information. For more information go to http://aka.ms/dataprotectionwarning Could not find any recognizable digits.
(The link in the message doesn't go anywhere useful).
I'm presuming this has something to do with the AzureWebJobsStorage setting, which cannot be set in an Azure Static Web App (for whatever reason).
Based on all of the above, it would seem that using Azure storage from within a static web app C# function is verboten. However, I can't find that stated explicitly online anywhere. Has anybody got this kind of thing to work?
I removed the following nuget packages to make it working:
Microsoft.Azure.EventGrid
Microsoft.Azure.WebJobs.Extensions.EventGrid
I decomposed my http functions to a separate project because SWA does not support the EventTriggers right now.

Problem on CORS configuration with Web Api 2, OWIN and Identity Server

I have a few web applications under the same domain, all using a stand alone Identity Server 3 app for login purposes. Under test environment, every single one of then are under the same domain (http://192.168.100.1, or by dns http://companyServer).
Recently, one application needed to request some data from another app, and I found the following error when debugging on Visual Studio:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://companyServer:60000/MyApp/Api/Company/Info?parameter=123. (Reason: CORS header 'Access-Control-Allow-Origin' not present).
We have a central library responsible for configuring Web API on our systems, it has the following (among other things):
public static IAppBuilder UseCebiUtilWebApi(this IAppBuilder app, CebiWebApiOptions options)
{
Logger.Debug("Configuring Web API");
app.UseCors(CorsOptions.AllowAll);
...
}
On the same method, we also configure Identity Server.
I also checked on my Login Server App, and there is the following code regarding CORS:
public class CompanyCorsPolicyService : DefaultCorsPolicyService
{
public CompanyCorsPolicyService()
{
base.AllowAll = true;
}
}
This method is being called on the project's Startup.cs.
As far as I know, every single end of my environmet should be enabling full CORS access, no matter the origin. But the header is still missing.
I've tried quite a few solutions on the internet:
Using "config.EnableCors" instead of "app.UseCors"
Overriding GrantResourceOwnerCredentials,
I have also tried setting up manually some CORS related headers on Web.Config, but I was unable to find the specific question here on SO.
I don't think identity server is related to this problem, but since that is the difference between my evironment and the solutions I've found, I decided to put it in here too.
Any ideas?
It's possible that the OPTIONSVerbHandler could be intercepting all OPTIONS (CORS pre-flight) requests.
Try disabling that so that ASP.Net can handle those requests instead.

Launching a WebApi application from a Windows App

I have a simple WebApi2 app that handles various REST requests. It's essentially a front end for various CRUD operations on an SQL Server Database. Up until now, I've never run it from outside of Visual Studio yet though and I usually don't do Windows specific stuff, but here I am.
My goal is to build this webapp's functionality into a Windows Desktop application (or at least be able to control the webapp from the windows program), mostly so the user can start the Webapp, stop it, see who is connecting to it, etc, but I've got no idea how to go about connecting this particular set of dots. It's actually a pretty tough thing to google.
The WebApp part also needs to be told some things at startup (just strings, so if the answer(s) involve executing various system command lines to tell the WebApp to start/stop/etc and I can pass in what I need on a command line somehow, that's fine).
Ultimately, the goal is to hand the user an install program and he doesn't have to know there is a webserver involved unless he really wants to.
So how would I go about accomplishing this part? (If this question is too vague, tell me why and I'll modify it as necessary).
One of the good things about Web API is the ability to be hosted outside of a web server such as IIS. For example you could host it inside your Windows Forms application. Here's an article with detailed instructions on how to achieve this.
You would have a Startup class that will be used for bootstrapping:
public class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
and then its just a matter of starting the listener:
using (WebApp.Start<Startup>("http://localhost:8080"))
{
Console.WriteLine("Web Server is running.");
Console.WriteLine("Press any key to quit.");
Console.ReadLine();
}
This will make available your Web API on port 8080 locally and your application can send HTTP requests to it.
So basically the keywords that you are looking for are: self hosting asp.net web api.

Why do I get the error "The service type ITraceWriter is not supported." from Azure?

I am trying to get my Web API 2 up and running on an Azure App Service. It works fine on my machine, on IIS 10, with the following tracing added, from the package Microsoft.AspNet.WebApi.Tracing:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.EnableSystemDiagnosticsTracing();
SystemDiagnosticsTraceWriter traceWriter = config.EnableSystemDiagnosticsTracing();
traceWriter.IsVerbose = true;
traceWriter.MinimumLevel = TraceLevel.Debug;
config.Services.Add(typeof(ITraceWriter), new TextFileTracer());
This works fine on my dev machine, but I get the error
The service type ITraceWriter is not supported.
as soon as I publish to Azure. I thought a modern ASP.NET app was supposed to be self contained, and not rely on services being present or configured on the host, and a very up to date host at that. Why is this happening?
According to your description, I tested your code on my Web API application and I got the server error as follows on my local side.
The service type ITraceWriter is not supported.
Parameter name: serviceType
As mentioned in this official document about setting the Trace Writer:
To enable tracing, you must configure Web API to use your ITraceWriter implementation. You do this through the HttpConfiguration object, as shown in the following code:
config.Services.Replace(typeof(ITraceWriter), new TextFileTracer());
Only one trace writer can be active. By default, Web API sets a "no-op" tracer that does nothing. (The "no-op" tracer exists so that tracing code does not have to check whether the trace writer is null before writing a trace.)
After replacing ITraceWriter service with the TextFileTracer instance, I could make it work as expected both on my side and Azure.

Check is a request is coming from the server local to the app with OWIN

I need to create an AuthroizationFilter for my Hangfire Dashboard.
Its running on an Azure VM and by design should only accept request from local requests.
I want to create an AuthorizationFilter that validates only those requests from the web browser on the same VM as the web app is running on.
I need to determine this form the OwinContext :-
public class MyRestrictiveAuthorizationFilter : IAuthorizationFilter
{
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
// In case you need an OWIN context, use the next line,
// `OwinContext` class is the part of the `Microsoft.Owin` package.
var context = new OwinContext(owinEnvironment);
// Allow all local request to see the Dashboard
return true;
}
}
I had a similar issue working on a custom CookieAuthenticationProvider where only IOwinContext was exposed. context.Request did not expose an IsLocal property, however the following was available:
context.Request.Uri.IsLoopback
The property was true for 127.0.0.1 and localhost requests.
What about checking the headers in the request context?
context.Request.Headers["Referer"]
If the value includes localhost or 127.0.0.1 or whatever you're restricting it to.
CAUTION: this header can be spoofed. There may be a better way to limit access to the dashboard. Does it need internet access?
Can you use HttpRequest.IsLocal? This will tell you if the IP address of the request is the same as the server's IP address.
return context.Request.IsLocal;

Categories