// Copyright 2012-2025 The NATS Authors // Licensed under the Apache License, Version 2.0 namespace ZB.MOM.NatsNet.Server.Tests.Auth; using ZB.MOM.NatsNet.Server; using ZB.MOM.NatsNet.Server.Auth; using Shouldly; using Xunit; public class AuthHandlerExtendedTests { [Fact] public void ValidateProxies_ProxyRequiredWithoutProtocol_ReturnsError() { var opts = new ServerOptions { ProxyRequired = true, ProxyProtocol = false }; var err = AuthHandler.ValidateProxies(opts); err.ShouldNotBeNull(); err!.Message.ShouldContain("proxy_required"); } [Fact] public void ValidateProxies_ProxyRequiredWithProtocol_ReturnsNull() { var opts = new ServerOptions { ProxyRequired = true, ProxyProtocol = true }; var err = AuthHandler.ValidateProxies(opts); err.ShouldBeNull(); } [Fact] public void GetAuthErrClosedState_ProxyNotTrusted_ReturnsProxyNotTrusted() { var err = new AuthProxyNotTrustedException(); AuthHandler.GetAuthErrClosedState(err).ShouldBe(ClosedState.ProxyNotTrusted); } [Fact] public void GetAuthErrClosedState_ProxyRequired_ReturnsProxyRequired() { var err = new AuthProxyRequiredException(); AuthHandler.GetAuthErrClosedState(err).ShouldBe(ClosedState.ProxyRequired); } [Fact] public void GetAuthErrClosedState_OtherError_ReturnsAuthenticationViolation() { var err = new InvalidOperationException("bad credentials"); AuthHandler.GetAuthErrClosedState(err).ShouldBe(ClosedState.AuthenticationViolation); } [Fact] public void GetAuthErrClosedState_NullError_ReturnsAuthenticationViolation() { AuthHandler.GetAuthErrClosedState(null).ShouldBe(ClosedState.AuthenticationViolation); } [Fact] public void CheckClientTlsCertSubject_NullCert_ReturnsFalse() { AuthHandler.CheckClientTlsCertSubject(null, _ => true).ShouldBeFalse(); } [Fact] public void ProcessUserPermissionsTemplate_ExpandsAccountVariable() { var lim = new Permissions { Publish = new SubjectPermission { Allow = new List { "{{account}}.events" } }, }; var (result, err) = AuthHandler.ProcessUserPermissionsTemplate(lim, "myaccount", null); err.ShouldBeNull(); result.Publish!.Allow![0].ShouldBe("myaccount.events"); } [Fact] public void ProcessUserPermissionsTemplate_ExpandsTagVariable() { var lim = new Permissions { Subscribe = new SubjectPermission { Allow = new List { "{{tag.region}}.alerts" } }, }; var tags = new Dictionary { ["region"] = "us-east" }; var (result, err) = AuthHandler.ProcessUserPermissionsTemplate(lim, "acc", tags); err.ShouldBeNull(); result.Subscribe!.Allow![0].ShouldBe("us-east.alerts"); } } public class JwtProcessorOperatorTests { [Fact] public void ReadOperatorJwtInternal_EmptyString_ReturnsError() { var (claims, err) = JwtProcessor.ReadOperatorJwtInternal(string.Empty); claims.ShouldBeNull(); err.ShouldNotBeNull(); } [Fact] public void ReadOperatorJwtInternal_InvalidPrefix_ReturnsFormatError() { var (claims, err) = JwtProcessor.ReadOperatorJwtInternal("NOTAJWT.payload.sig"); claims.ShouldBeNull(); err.ShouldBeOfType(); } [Fact] public void ReadOperatorJwt_FileNotFound_ReturnsError() { var (claims, err) = JwtProcessor.ReadOperatorJwt("/nonexistent/operator.jwt"); claims.ShouldBeNull(); err.ShouldBeOfType(); } [Fact] public void ValidateTrustedOperators_EmptyList_ReturnsNull() { var opts = new ServerOptions(); JwtProcessor.ValidateTrustedOperators(opts).ShouldBeNull(); } }