.MapWhen executing for all calls - asp.net-core

I have a large already running application built on .net core 1.0.4. I have a need to add a micro api to this application, and am attempting to integrate a fairly simple http basic auth middleware into the pipeline only for calls to the api controller.
In my startup.csconfigure method, I have the following.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//run basic auth only on API calls
app.MapWhen(context => context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase), appBuilder =>
{
app.UseMiddleware<BasicAuthenticationMiddleware>();
app.UseMvc();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/site/error");
}
app.UseStaticFiles();
app.UseIdentity();
app.UseDefaultFiles();
app.UseStatusCodePages();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Site}/{action=Login}/{id?}");
});
}
It's my understanding that the pipeline would branch for all calls that start with /api into the Basic middle ware. My issue is that with this code, ALL calls regardless of the path are hitting the .MapWhen path, and essentially breaking the entire site.

Related

How to set the redirect URI when using Microsoft sign-in in a .NET 5 application?

I have created a .NET 5 application with Microsoft sign-in based on this explanation.
It is working fine when running locally. However, something is going wrong when running the application in Amazon EKS. This became clear to me after reading error message I saw in the browser and after reading the network traffic.
This is how this looks like.
What becomes clear is that there is something wrong with "redirect_uri" (containing http instead of https). This is really frustrating as my application is using https. I use https when opening the application in my browser. It is important to mention that this does not occur when running the application locally on my laptop. What I hope for is that there is a simple way to set the "redirect_uri" property that is used in my code. In this way, I can guarantee that the right redirect uri is used.
Here is the source code I would like to change:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var configSettings = new ConfigSettings();
Configuration.Bind("ConfigSettings", configSettings);
services.AddSingleton(configSettings);
services.AddSingleton<IAuthResponseFactory, AuthResponseFactory>();
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
services.AddHealthChecks();
services.Configure<HealthCheckPublisherOptions>(options =>
{
options.Delay = TimeSpan.FromSeconds(2);
options.Predicate = (check) => check.Tags.Contains("ready");
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
{
Predicate = (check) => check.Tags.Contains("ready")
});
endpoints.MapHealthChecks("/health/live", new HealthCheckOptions());
});
}
So how do I change my source in a way that I can set the redirect uri correctly?
Looks like you need to enable header forwarding.
Step 1: configure the ForwardedHeadersOptions
services.Configure<ForwardedHeadersOptions>(options =>
{
options.RequireHeaderSymmetry = false;
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// TODO : it's a bit unsafe to allow all Networks and Proxies...
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
Step 2: UseForwardedHeaders in the public void Configure(IApplicationBuilder app, IHostingEnvironment env) method
app.UseForwardedHeaders();
Step 3: Only use UseHttpsRedirection for production
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// Forward http to https (only needed for local development because the Azure Linux App Service already enforces https)
app.UseHttpsRedirection();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
See How to set redirect_uri protocol to HTTPS in Azure Web Apps and .net Core X Forwarded Proto not working

gettting 401 on Hangfire with LocalRequestsOnlyAuthorizationFilter

We are trying to use hangfire with LocalRequestsOnlyAuthorizationFilter. We have deployed the application to IIS. When trying to access the hangfire dashboard from same machine where IIS is deployed, we are getting 401 on hangfire dashboard URL "/jobs". All we are trying to do here is allow to view the dashboard as long as request is coming from same machine where hangfire is deployed. Below is our config on startup.cs file
public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseHangfireDashboard("/jobs", new DashboardOptions()
{
Authorization = new[] { new LocalRequestsOnlyAuthorizationFilter() }
});
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHangfireDashboard();
});
backgroundJobs.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));
}
We checked both remote and local ip and both are same. Is there anything else we are missing here? Just to make sure application is running or not on IIS, we are added the another page and that page is working fine.
Change your Authorization to AuthorizationFilters,
app.UseHangfireDashboard("/jobs", new DashboardOptions()
{
AuthorizationFilters = new[] { new LocalRequestsOnlyAuthorizationFilter() }
});
Also, from this post check to make sure ASP.net is correctly installed and integrated pipeline is used for your application pool
This is also another good resource to go through in validating your IIS configuration

User.Identity with empty properties when running app on Kestrel

I have two situations during windows authentication using Active Directory domain identities:
When I running my app with IIS I'm getting object WindowsPrincipal filled with information
When I running my app with Kestrel I'm getting object ClaimsPrincipal without any informatiion about the user information
What could be the problem?
My ConfigureService:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<IdentityUser, IdentityRole>().AddRoleManager<RoleManager<IdentityRole>>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationContext>();
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
services.AddAuthorization();
services.AddScoped<IUserManagementManager, UserManagementManager>();
services.AddScoped<IRolesManagementManager, RolesManagementManager>();
}
Configure:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseResponseCaching();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Authentication}/{action=Index}");
});
}
How did you configure Windows Authentication in the Kestrel? I found that the attribute of IsAuthenticated in your image is false. This may cause you can not get any information about the ClaimsPrincipal.
You can use invoke AddAuthentication and AddNegotiate in Startup.ConfigureServices to add authentication services in Kestrel.
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
More information about how to config windows Authentication in the Kestrel you can refer to this link: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-5.0&tabs=visual-studio

ASP.NET Core 3.1 with Razor pages, api controllers and IdentityServer4

I'm creating a boilerplate for ASP.NET Core 3.1 projects with Razor page, api controller and IdentityServer4. The full source code is in my Github.
The configuration in the Startup.cs is
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options => {
options.Authority = "https://localhost:44301";
options.RequireHttpsMetadata = false;
});
services.AddIdentityServer()
.AddDeveloperSigningCredential()
//not something we want to use in a production environment
.AddInMemoryIdentityResources(InMemoryConfig.GetIdentityResources())
.AddTestUsers(InMemoryConfig.GetUsers())
.AddInMemoryClients(InMemoryConfig.GetClients());
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseIdentityServer();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
});
app.UseOpenApi();
app.UseSwaggerUi3();
}
I configured the IdentityServer4 with InMemoryConfig. If I use Postman, I have a valid token as result.
The problem occurs when I call the webapi from the url https://localhost:44301/api/Account. When I decorate the apicontroller with [Authorize], I'm using Postman to call it and I pass as authorization the bearer token I've just create and I already receive 404 Not Found. If I try to use Swagger for calling this function and I pass the token, there is no result.
The Swagger page is recognizing correctly all apis. Without the [Authorize] decoration I can test my apis.
When I add the authorization and I add the token to my request, Swagger doesn't show anything, oh well, 404.
I don't know if this is a configuration problem or something different.
Update
I googled a lot and I found a post on the ASP.NET core repo and I tried to update ConfigureService like
// this order seems important for .NET:
// first AddIdentityServer then AddAuthentication
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(InMemoryConfig.GetIdentityResources())
.AddTestUsers(InMemoryConfig.GetUsers())
.AddInMemoryClients(InMemoryConfig.GetClients());
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
// necessary, even if you don't use BearerAuth.
.AddJwtBearer();
then I changed
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseIdentityServer();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// this order seems important for .NET
// first UseAuthorization and then UseAuthentication
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
});
app.UseOpenApi();
app.UseSwaggerUi3();
}
Now I receive 401 Unauthorized instead of 404 Non found. Apparently, ASP.NET Core redirects automatically to a login page.

.Net Core Middleware hitting multiple times on page request

I am logging a user's audit to the database on every page click and I thought doing this in the middleware was acceptable (And good?) as it gets fired on every HTTP request. However, when I proceed to a new page, the code in the middleware (userService.AddUser()) is being hit 3 times and I am unsure why.
Here is the code:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IUserService userService)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
// My own code.
app.Use(async (context, next) =>
{
// The database insert
userService.AddUser();
await next.Invoke();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
I am probably missing some knowledge as of why this doesn't work.
Thanks
It's being called multiple times due to images not being found on said page.
In the console of the browser, a third party library cannot find an image which is calling a 404.
sort_both.png:1 Failed to load resource: the server responded with a
status of 404 ()
If this happens to you, I would check the console window in case images and or files are missing.