[英]OnCertificateValidated not running - Self-Signed Certificate Client Authentication - ASP.NET Core and Kestrel
I would like to authenticate clients connecting to my ASP.NET Core Web API (.NET 5) running on Kestrel using certificate-based authentication.我想使用基于证书的身份验证对连接到在 Kestrel 上运行的 ASP.NET Core Web API (.NET 5) 的客户端进行身份验证。
In my Startup.cs
I have the following in ConfigureServices
:在我的
Startup.cs
我在ConfigureServices
有以下内容:
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
// More code to verify certificates
},
OnAuthenticationFailed = context =>
{
// More code
}
};
});
// Other services
And in Configure
:在
Configure
:
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
// Endpoints
});
And in Program.cs
I have included:在
Program.cs
我包含了:
webBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o =>
o.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
});
If I connect to the API in a browser, it prompts me for a certificate, but after I select a certificate, neither the OnCertificateValidated
nor the OnAuthenticationFailed
events are triggered.如果我连接到API的浏览器,它提示我要证书,但我选择一个证书后,无论是
OnCertificateValidated
也不OnAuthenticationFailed
事件被触发。 After some further testing, I realized that the entire options configuration delegate inside the AddCertificate
call in Startup.cs
never runs.经过一些进一步的测试,我意识到
Startup.cs
AddCertificate
调用中的整个选项配置委托永远不会运行。 This makes me think I am missing some kind of configuration for Kestrel, but I do not know what that is.这让我觉得我缺少某种 Kestrel 的配置,但我不知道那是什么。 As a note, my Web API does NOT use IIS hosting.
请注意,我的 Web API 不使用 IIS 托管。 What else do I need to do to use self-signed certificate-based authentication?
我还需要做什么才能使用基于自签名证书的身份验证?
The code I have so far is based on the instructions found in the documentation here: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-5.0到目前为止,我拥有的代码基于此处文档中的说明: https : //docs.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-5.0
Ok, so in the end I was able to solve my own problem.好的,所以最后我能够解决我自己的问题。 There were two different parts to solving it, but ultimately it only required a few small modifications to my project code.
解决它有两个不同的部分,但最终只需要对我的项目代码进行一些小的修改。
Recognizing client certificates识别客户端证书
Firstly, the server was not recognizing the self-signed client certificates as valid certificates.首先,服务器未将自签名客户端证书识别为有效证书。 This can be solved by either 1. adding all of the client certificates (or a root CA that signs them all) to the trusted certificate store of the operating system or 2. adding a
ClientCertificateValidation
callback to kestrel to determine whether or not a certificate is accepted or rejected.这可以通过以下任一方式解决: 1. 将所有客户端证书(或对所有证书进行签名的根 CA)添加到操作系统的可信证书存储中,或者 2. 将
ClientCertificateValidation
回调添加到 kestrel 以确定证书是否为接受或拒绝。
Example of #2 (an adjustment to the ConfigureHttpsDefaults
lambda in Program.cs
) is below: #2 的示例(对
Program.cs
的ConfigureHttpsDefaults
lambda 的调整)如下:
webBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(opts =>
{
opts.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
opts.ClientCertificateValidation = (cert, chain, policyErrors) =>
{
// Certificate validation logic here
// Return true if the certificate is valid or false if it is invalid
};
});
});
As a side note, calling opts.AllowAnyClientCertificate()
is a shorthand for adding a ClientCertificateValidation
callback that always returns true, making ALL self-signed certificates valid.作为旁注,调用
opts.AllowAnyClientCertificate()
是添加始终返回 true 的ClientCertificateValidation
回调的简写,使所有自签名证书都有效。
Required Authorization所需授权
After applying either of these approaches, my API would accept queries from valid certificates, but my extra certificate validation logic in the OnCertificateValidated
event was still not running.应用这些方法之一后,我的 API 将接受来自有效证书的查询,但我在
OnCertificateValidated
事件中的额外证书验证逻辑仍未运行。 This is because, according to comments on ASP.NET Core issue #14033 , this event's extra certificate validation will never run unless authorization is enabled for the endpoint being accessed.这是因为,根据对ASP.NET Core 问题 #14033 的评论,除非为正在访问的端点启用授权,否则此事件的额外证书验证将永远不会运行。 This makes sense because this event is often used to generate a
ClaimsPrincipal
from a certificate per the ASP.NET Core Docs on the subject .这是有道理的,因为此事件通常用于根据主题上的 ASP.NET Core Docs的证书生成
ClaimsPrincipal
。 Setting ASP.NET to use authorization and requiring authorization for API calls (eg, by applying the [Authorize]
attribute to all controllers) causes the additional authentication checks to run for those API calls.将 ASP.NET 设置为使用授权并要求对 API 调用进行授权(例如,通过将
[Authorize]
属性应用于所有控制器)会导致对这些 API 调用运行额外的身份验证检查。
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
// Adding this and adding the [Authorize] attribute
// to controllers fixes the problem.
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
// Endpoints
});
After this, my OnCertificateValidated
event was called for every connection and I was able to perform additional authentication logic and reject invalid certificates.在此之后,每个连接都会调用我的
OnCertificateValidated
事件,并且我能够执行额外的身份验证逻辑并拒绝无效证书。
The accepted answer was very helpful for me (thanks!) but it did not solve my problem entirely.接受的答案对我很有帮助(谢谢!)但它并没有完全解决我的问题。
I found that the ClientCertificateValidation
function is not the only place the certificate is validated (and rejected).我发现
ClientCertificateValidation
函数不是验证(和拒绝)证书的唯一地方。 Using AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate...
使用
AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate...
AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate...
also caused another validation to be triggered, after ClientCertificateValidation
was handled. AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme). AddCertificate...
还导致在处理ClientCertificateValidation
之后触发另一个验证。
To solve the problem for me, I had to configure a CustomTrustStore
in lines to the CertificateAuthenticationOptions:
为了解决我的问题,我必须在
CertificateAuthenticationOptions:
行中配置CustomTrustStore
CertificateAuthenticationOptions:
AddCertificate(options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust;
options.CustomTrustStore = new X509Certificate2Collection { rootCert };
options.RevocationMode = X509RevocationMode.NoCheck;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
if (validationService.ValidateCertificate(context.ClientCertificate))
{
context.Success();
}
else
{
context.Fail("invalid cert");
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
context.Fail("invalid cert");
return Task.CompletedTask;
}
};
});
Where rootCert
is initiated with: rootCert
是通过以下方式启动的:
var rootCert = new X509Certificate2("RootCert.pfx", "1234");
And RootCert.pfx
is added as file to the project.并且
RootCert.pfx
作为文件添加到项目中。
Since we're using the built-in validation now from AddAuthentication(.).AddCertificate
, we should disable the earlier validation with AllowAnyCertificate()
(This validation does not know about our custom root trust):由于我们现在使用
AddAuthentication(.).AddCertificate
的内置验证,我们应该使用AllowAnyCertificate()
禁用较早的验证(此验证不知道我们的自定义根信任):
builder.WebHost.ConfigureKestrel(kso =>
{
kso.ConfigureHttpsDefaults(cao => {
cao.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
cao.AllowAnyClientCertificate();
cao.CheckCertificateRevocation = false;
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.