You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单元测试SAML认证服务时遇InvalidSignatureException问题求助

解决SAML单元测试中签名无效的问题

问题背景

为便于单元测试,将SAML认证逻辑拆分到ExternalAuthenticationService层,控制器调用该服务完成认证:

控制器代码

[Route("samlConsume")]
public async Task<IActionResult> AssertionConsumerAsync()
{
    var samlLoginInfo = await externalAuthenticationService.AuthenticateAsync(HttpContext);
    // ...
}

服务代码

public async Task<LoginInfo> AuthenticateAsync(HttpContext context)
{
    var req = context.Request.ToGenericHttpRequest();
    var binding = new Saml2PostBinding();
    var saml2AuthnResponse = new Saml2AuthnResponse(config);

    binding.ReadSamlResponse(req, saml2AuthnResponse);
    if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
    {
        throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
    }

    binding.Unbind(req, saml2AuthnResponse);
    var sessionPrincipal = await saml2AuthnResponse.CreateSession(
       context, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal)
    );
    
    // 处理sessionPrincipal并返回LoginInfo
}

单元测试时,模拟HttpContext、生成测试证书并伪造SAML响应,执行AuthenticateAsync时出现错误:

Message: 
ITfoxtec.Identity.Saml2.Cryptography.InvalidSignatureException :
Signature is invalid.

Stack Trace:  Saml2Request.ValidateXmlSignature(SignatureValidation documentValidationResult)


解决方案

1. 确保签名证书与服务配置完全匹配

生成测试证书后,必须将证书的公钥添加到SAML服务的Saml2Configuration中,同时用对应的私钥签名伪造的SAML响应:

// 测试初始化时配置Saml2Configuration
var testCert = new X509Certificate2("test-cert.pfx", "test-password");
var testConfig = new Saml2Configuration();
// 添加允许的签名证书(公钥会被提取用于验证)
testConfig.AllowedSigningCertificates.Add(testCert);

2. 使用ITfoxtec库生成合规的签名SAML响应

不要手动构造SAML响应,直接用库的API生成带签名的测试响应,确保签名格式符合规范:

// 构造测试用SAML响应
var saml2AuthnResponse = new Saml2AuthnResponse(testConfig);
saml2AuthnResponse.Status = Saml2StatusCodes.Success;
// 设置断言主体等必要信息
saml2AuthnResponse.Assertion = new Saml2Assertion(testConfig);
saml2AuthnResponse.Assertion.Subject = new Saml2Subject(new Saml2NameIdentifier("test-user-id"));
saml2AuthnResponse.Assertion.Conditions = new Saml2Conditions
{
    NotBefore = DateTime.UtcNow.AddMinutes(-5),
    NotOnOrAfter = DateTime.UtcNow.AddMinutes(5)
};
// 用测试证书的私钥签名响应
saml2AuthnResponse.Sign(testCert);

// 将响应绑定到POST请求,映射到模拟HttpContext
var binding = new Saml2PostBinding();
var genericRequest = new GenericHttpRequest();
binding.Bind(saml2AuthnResponse, genericRequest);
// 将genericRequest中的表单参数复制到模拟HttpContext的Request.Form中
var mockHttpContext = new DefaultHttpContext();
foreach (var param in genericRequest.Form)
{
    mockHttpContext.Request.Form.TryAdd(param.Key, param.Value);
}

3. 临时关闭签名验证(仅用于单元测试)

如果仅需测试业务逻辑,可临时关闭签名验证(生产环境绝对禁止):

testConfig.SignatureValidationMode = SignatureValidationMode.None;

4. 检查测试证书的有效性

确保测试证书满足以下要求:

  • 包含可访问的私钥(cert.HasPrivateKey返回true)
  • 密钥用途包含DigitalSignature:
var cert = new X509Certificate2("test-cert.pfx", "test-password");
Debug.Assert(cert.HasPrivateKey, "测试证书必须包含私钥");
Debug.Assert(cert.KeyUsage.HasFlag(X509KeyUsageFlags.DigitalSignature), "证书密钥用途必须包含数字签名");

内容的提问来源于stack exchange,提问作者Scott Baker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:52:37