单元测试ExternalAuthenticationService遇空引用异常,缺失哪些配置?
问题:Saml2RedirectBinding.Bind抛出NullReferenceException,缺失必要配置项?
我正尝试为ExternalAuthenticationService类编写单元测试,测试RedirectToLogin方法并确保RelayStateQuery被正确填充:
public IActionResult RedirectToLogin(LoginInfo loginInfo) { var binding = new Saml2RedirectBinding(); var dict = new Dictionary<string, string> { { "SomeKey", info.SomeStringIWantToRoundTrip } }; binding.SetRelayStateQuery(dict); return binding.Bind(new Saml2AuthnRequest(config)).ToActionResult(); }
测试代码如下:
public class ExternalAuthenticationServiceTests { private IExternalAuthenticationService service; public ExternalAuthenticationServiceTests() { var testCertificate = GenerateCertificate("Test Certificate"); var config = new Saml2Configuration { CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None, Issuer = "http://wonderwoman.com", RevocationMode = X509RevocationMode.NoCheck, SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", SigningCertificate = testCertificate }; service = new ExternalAuthenticationService(config); } [Fact] public void RedirectToLogin_sets_tenantName_in_RelayStateQuery() { LoginInfo loginInfo = new() { SomeStringIWantToRoundTrip = "user location or whatever" }; var result = service.RedirectToLogin(loginInfo); } private X509Certificate2 GenerateCertificate(string subjectName) { // Generate a new RSA key pair using var rsa = RSA.Create(2048); // Create a certificate request CertificateRequest request = new($"CN={subjectName}", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // Set certificate validity dates DateTimeOffset now = DateTimeOffset.UtcNow; request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false)); request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, false)); request.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false)); request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false)); // Create a self-signed certificate X509Certificate2 certificate = request.CreateSelfSigned(now, now.AddYears(1)); // Return the generated certificate return certificate; } } }
运行测试时,还没添加断言就抛出异常:
Message:
System.NullReferenceException : Object reference not set to an instance of an object.Stack Trace:
Saml2RedirectBinding.BindInternal(Saml2Request saml2RequestResponse, String messageName) Saml2Binding`1.Bind(Saml2Request saml2Request) ExternalAuthenticationService.RedirectToLogin(LoginInfo loginInfo) line 39
我推测Saml2Configuration类缺少未配置的必要属性,但无法确定具体项,请问我遗漏了什么?
解答
这个空引用异常是因为Saml2AuthnRequest缺少必要的目标地址配置,而这依赖于Saml2Configuration中配置的身份提供者(IdP)信息。具体来说,你需要在Saml2Configuration中添加一个IdentityProvider,并设置其SingleSignOnServiceLocation,否则在生成AuthnRequest时无法确定跳转目标,导致绑定过程中出现空引用。
解决步骤
- 修改测试中的配置,添加IdentityProvider信息
var config = new Saml2Configuration { CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None, Issuer = "http://wonderwoman.com", RevocationMode = X509RevocationMode.NoCheck, SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", SigningCertificate = testCertificate }; // 添加必要的IdP配置 var idp = new Saml2IdentityProvider(new EntityId("http://test-idp.com")) { SingleSignOnServiceLocation = new Uri("http://test-idp.com/sso"), SigningCertificates = { testCertificate } // 测试环境可复用自签证书,实际场景需使用IdP的公钥证书 }; config.IdentityProviders.Add(idp); // 设置默认IdP,让AuthnRequest自动使用该配置 config.DefaultIdentityProvider = "http://test-idp.com";
- 可选:显式指定AuthnRequest的目标地址
如果服务类中未自动关联默认IdP,可在RedirectToLogin方法中显式设置:
var authnRequest = new Saml2AuthnRequest(config) { Destination = config.IdentityProviders.First().SingleSignOnServiceLocation.AbsoluteUri }; return binding.Bind(authnRequest).ToActionResult();
核心原因是SAML的AuthnRequest必须包含目标IdP的单点登录地址,你的配置中缺少这一关键信息,导致绑定过程中尝试访问未初始化的属性,最终抛出NullReferenceException。
内容的提问来源于stack exchange,提问作者Scott Baker
相关产品推荐
相关产品推荐

