Asp core doesn't enforce client certificate - asp.net

I have an API app created using asp core. I'm trying to enforce use of client certificates as described here.
I did tell Kestrel to require certificates in Program.cs:
webBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o => o.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
});
And I did add event handler in Startup.cs:
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
}
};
});
When I debug the API running locally it still doesn't require any certificates. If I provide certificate anyway, the breakpoint in the event handler is never hit.

Related

How to establish HTTPS/ssl/tls Backend <=> Frontend connection using angular 13?

I have a API-REST service in ASP.NET CORE web-api NET 6. I am using client certificate authentication with the following configuration.
builder.WebHost.ConfigureKestrel(options =>
{
options.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.ServerCertificate = serverCertificate;
listenOptions.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
listenOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
listenOptions.CheckCertificateRevocation = false;
//listenOptions.AllowAnyClientCertificate();
listenOptions.ClientCertificateValidation = (certificate, chain, errors) =>
{
if (chain.Build(certificate))
//Add certificate verification
return true;
return false;
};
});
options.ListenLocalhost(7120, op =>
{
op.UseHttps(serverCertificate);
op.Protocols = HttpProtocols.Http1AndHttp2;
op.UseConnectionLogging();
});
});
It works perfectly from POSTMAN adding the client certificate issued by my CA and its intermediate certificate.
I get this error in Angular. (ERR_BAD_SSL_CLIENT_AUTH_CERT)
I have the CORS already configured.
How can I send the client's certificate from Angular to the backend or how do I establish communication?
there is no need that your frontend app (spa) knows any thing about tls or domain or IP your server has
you have environment variable
//development
baseUrl:'localhost:5001'
//production
// enviroment.prod.ts
baseUrl:'/api/'
when your in production build for it
simply do not use certificate for developement

Should GRPC net and Azure app service work

In this video for .Net 7 and GRPC
https://www.youtube.com/watch?v=et_2NBk4N4Y
the say that GRPC should work on azure linux app service.
I have implemented following this guide with no success.
https://github.com/Azure/app-service-linux-docs/blob/master/HowTo/gRPC/use_gRPC_with_dotnet.md
this is my program.cs
var builder = WebApplication.CreateBuilder(args);
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
#if Debug
builder.WebHost.ConfigureKestrel(options =>
{
// Setup a HTTP/2 endpoint without TLS.
options.ListenLocalhost(5253, o => o.Protocols =
HttpProtocols.Http2);
});
#endif
#if RELEASE
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(8080);
options.ListenAnyIP(5253, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
});
});
#endif
// Add services to the container.
builder.Services.AddGrpc();
builder.Services.AddGrpcReflection();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.MapGrpcService<MobileAppsService>();
app.MapGrpcReflectionService();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
app.Run();
Try test with Postman and only get Error: Received RST_STREAM with code 0
all work run local.

asp.net core identity and identityserver

I'm following this walkthrough on integrating asp.net core identity with IdentityServer but have hit a few roadblocks.
Where I'm updating the ConfigureServices method, if I follow the guide and use
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
I can no longer access any of the account related functions. The routing for the register link changes from
~/Identity/Account/Register
to
~/?area=Identity&page=%2FAccount%2FRegister
Which breaks all account related functions
If I leave it at
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
Then the routing still works, I can enter my credentials via the login page and the login is successful, but
SignInManager.IsSignedIn(User)
returns false, so I'm guessing something is fundamentally broken here.
I have added identityserver to my ConfigureServices:
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.IdentityResources.GetIdentityResources())
.AddInMemoryApiResources(Config.APIResources.GetApiResources())
.AddInMemoryClients(Config.Clients.GetClients())
.AddAspNetIdentity<IdentityUser>();
Any ideas what needs to change - I'm guessing its something in the latest version of asp.net core that has caused this has it?
The Identity UI is implemented using Razor Pages. For endpoint-routing to map these, add a call to MapRazorPages in your UseEndpoints callback:
app.UseEndpoints(endpoints =>
{
// ...
endpoints.MapRazorPages();
});
In Net Core 2.1 Microsoft have removed the AccountController and moved all the Identity logic to Razor pages (there is no alternative now available) which makes the logic difficult to follow (it reminds me of ASP classic or PHP). The Quickstart in the documentation relies entirely on the AccountController remaining in place (no longer the case) and guess this needs to be rewritten as Razor pages before anything will work. However, there is not a lot of point in doing this whilst the authentication mechanism is broken.
I used the following Startup.cs to demonstrate that authentication no longer works in IdentityServer4 when added to a new Net Core 2.1 project. It should work but shows the following behaviour when accessing a controller method protected by [Authorize] and the challenge presented as a Login page.
1) Entering the incorrect credentials causes the 'Invalid login attempt' text to be displayed
2) Entering correct credentials fails to authenticate and this can be seen by there being no Logout link or debugging and observing User.isAuthenticated is false
A couple of changes can be made to the Startup.cs in order to show authentication works when IdentityServer is disabled and the standard authentication enabled. Simply comment out the block commencing 'services.AddIdentityServer(options =>
' to disable IdentityServer. Next comment out 'useIdentityServer()' and uncomment 'useAuthentication()' and all the authentications work correctly again.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.Lax;
});
// Add authentication options
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("offline_access");
});
// Identity Context
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration["IdentityConnection"],
sqlOptions => sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().
Assembly.GetName().Name));
},
ServiceLifetime.Scoped
);
// Configure default Identity implementation
services.AddDefaultIdentity<ApplicationUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultUI()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
// Add application services.
services.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, EmailSender>();
services.AddMvc();
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer(options =>
{
options.UserInteraction.LoginUrl = "/Identity/Account/Login";
options.UserInteraction.LogoutUrl = "/Identity/Account/Logout";
})
.AddDeveloperSigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
//app.UseAuthentication(); // not needed, since UseIdentityServer adds the authentication middleware
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
I'm not sure how to the authentication working in IdentityServer4 since have not followed how it would work in Net Core 2.1. Has anyone got further than me and got this server working?
Figured this out in the end. Seems like a weird bug as MSFT migrates to Razor pages.
All I needed to do was add in the Scaffolding UI and it just started working

asp.core windows authentication integration tests fails with No authentication handler is configured

I have a ASP.Core web app that uses windows authentication I am trying to setup integration tests for.
inside the startup the authorization is configured as follows
services.Configure<IISOptions>(options =>
{
options.ForwardWindowsAuthentication = true;
});
services.AddAuthorization(options =>
{
options.AddPolicy("SiteRead", policy => policy.RequireAssertion(
context => context.User.HasClaim(
x => x.Value == "groupSidHere"
)));
});
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
The test is as follows
var server = new TestServer(builder);
var client = server.CreateClient();
var response = await client.GetAsync("/");
response.EnsureSuccessStatusCode();
The test fails with the following response
InvalidOperationException: No authentication handler is configured to handle the scheme: Automatic
All the documentation I have been able to find for integration tests doesn't cover this scenario(windows auth). Has anyone found a solution to this?
See this issue, they say:
We ended up solving our need for Windows auth with TestServer by creating a little library that will inject some windows auth services into the pipeline to emulate the behavior provided by IIS - you can find it at
You will find their library "IntelliTect.AspNetCore.TestHost.WindowsAuth" here.
I faced the same issue, and that library worked for me!
And it actually inject real windows authentication data, not just a mock data.

How to make [Authorize] trigger openId middleware

I'm trying out some features of ASP.NET 5 and I'm struggling a bit with authentication. I've managed to use most of this sample app to connect to my Azure AD to log in, but I can't figure out how to restrict parts of my web app to authenticated users only. The article that accompanies the sample app I used states that
You can trigger the middleware to send an OpenID Connect sign-in
request by decorating a class or method with the [Authorize]
attribute, or by issuing a challenge
Since I'd like to avoid repeating the same challenge code everywhere, I opted for the attribute approach, but it doesn't work at all. All it seems to do is block access to unauthorized users, without redirecting to the login page the way the challenge does.
Since I intended the app I am building to be more private than public, I've also tried creating a global policy and opening up some select features using the AllowAnonymous attribute. This works, but again the unauthorized pages are simply shown as blank, instead of a challenge being issued.
This is the policy code I'm using currently, taken from here:
var policy = new AuthorizationPolicyBuilder()
//This is what makes it function like the basic [Authorize] attribute
.RequireAuthenticatedUser()
.Build();
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new AuthorizeFilter(policy));
});
Am I missing some setup to the authorization attribute or the policy that issues the challenge?
For posterity and most likely my future self as well:
I was missing the AutomaticAuthentication property in the OpenIdConnectOptions. The sample app was set up like this:
// Configure the OWIN Pipeline to use Cookie Authentication
app.UseCookieAuthentication(options =>
{
// By default, all middleware are passive/not automatic. Making cookie middleware automatic so that it acts on all the messages.
options.AutomaticAuthentication = true;
});
// Configure the OWIN Pipeline to use OpenId Connect Authentication
app.UseOpenIdConnectAuthentication(options =>
{
options.ClientId = Configuration.Get("AzureAd:ClientId");
options.Authority = String.Format(Configuration.Get("AzureAd:AadInstance"), Configuration.Get("AzureAd:Tenant"));
options.PostLogoutRedirectUri = Configuration.Get("AzureAd:PostLogoutRedirectUri");
options.Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed,
};
});
To get everything to work I had to make small adaptations to make it look like this:
app.UseCookieAuthentication(options => { options.AutomaticAuthentication = true; });
// Configure the OWIN Pipeline to use OpenId Connect Authentication
app.UseOpenIdConnectAuthentication(options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ClientId = Configuration.Get("AzureAd:ClientId");
options.Authority = String.Format(Configuration.Get("AzureAd:AadInstance"), Configuration.Get("AzureAd:Tenant"));
options.PostLogoutRedirectUri = Configuration.Get("AzureAd:PostLogoutRedirectUri");
options.Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed,
};
options.AutomaticAuthentication = true;
});

Resources