From d76735ca9d8f4c3f7802455a9b9a9ced3a7aa136 Mon Sep 17 00:00:00 2001 From: Rohan Vazarkar Date: Tue, 8 Oct 2024 17:39:31 -0400 Subject: [PATCH] chore: fix tests, add test for laps aces --- test/unit/ACLProcessorTest.cs | 94 +++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 21 deletions(-) diff --git a/test/unit/ACLProcessorTest.cs b/test/unit/ACLProcessorTest.cs index f002a389..bd0360da 100644 --- a/test/unit/ACLProcessorTest.cs +++ b/test/unit/ACLProcessorTest.cs @@ -62,7 +62,7 @@ public async Task ACLProcessor_TestKnownDataAddMember() { var mockLdapUtils = new MockLdapUtils(); var mockUtils = new Mock(); var mockData = new[] { LdapResult.Fail() }; - mockUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); mockUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .Returns((string a, string b) => mockLdapUtils.ResolveIDAndType(a, b)); @@ -236,7 +236,7 @@ public async Task ACLProcessor_ProcessACL_Yields_Owns_ACE() { .ReturnsAsync((true, new TypedPrincipal(expectedSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -377,7 +377,7 @@ public async Task ACLProcessor_ProcessACL_GenericAll_Unmatched_Guid() { mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -410,7 +410,7 @@ public async Task ACLProcessor_ProcessACL_GenericAll() { mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -449,7 +449,7 @@ public async Task ACLProcessor_ProcessACL_WriteDacl() { mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -488,7 +488,7 @@ public async Task ACLProcessor_ProcessACL_WriteOwner() { mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -527,7 +527,7 @@ public async Task ACLProcessor_ProcessACL_Self() { mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -565,7 +565,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_Domain_Unmatched() { mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -598,7 +598,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_Domain_DSReplicationGetC mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -636,7 +636,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_Domain_All() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -675,9 +675,9 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_Domain_DSReplicationGetC mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); var mockData = new[] { LdapResult.Fail() }; - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(mockData.ToAsyncEnumerable()); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -715,7 +715,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_User_Unmatched() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -748,7 +748,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_User_UserForceChangePass mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -786,7 +786,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_User_All() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -823,7 +823,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_Computer_NoLAPS() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -856,7 +856,7 @@ public async Task ACLProcessor_ProcessACL_ExtendedRight_Computer_All() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -893,7 +893,7 @@ public async Task ACLProcessor_ProcessACL_GenericWrite_Unmatched() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -926,7 +926,7 @@ public async Task ACLProcessor_ProcessACL_GenericWrite_User_All() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -964,7 +964,7 @@ public async Task ACLProcessor_ProcessACL_GenericWrite_User_WriteMember() { mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -1004,7 +1004,7 @@ public async Task ACLProcessor_ProcessACL_GenericWrite_Computer_WriteAllowedToAc mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); - mockLDAPUtils.Setup(x => x.Query(It.IsAny(), It.IsAny())) + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) .Returns(Array.Empty>().ToAsyncEnumerable); var processor = new ACLProcessor(mockLDAPUtils.Object); @@ -1018,6 +1018,58 @@ public async Task ACLProcessor_ProcessACL_GenericWrite_Computer_WriteAllowedToAc Assert.False(actual.IsInherited); Assert.Equal(actual.RightName, expectedRightName); } + + [Fact] + public async Task ACLProcessor_ProcessACL_LAPS_Computer() { + var expectedPrincipalType = Label.Group; + var expectedPrincipalSID = "S-1-5-21-3130019616-2776909439-2417379446-512"; + var expectedRightName = EdgeNames.ReadLAPSPassword; + + var mockLDAPUtils = new Mock(); + var mockSecurityDescriptor = new Mock(MockBehavior.Loose, null); + var mockRule = new Mock(MockBehavior.Loose, null); + var collection = new List(); + mockRule.Setup(x => x.AccessControlType()).Returns(AccessControlType.Allow); + mockRule.Setup(x => x.IsAceInheritedFrom(It.IsAny())).Returns(true); + mockRule.Setup(x => x.IdentityReference()).Returns(expectedPrincipalSID); + mockRule.Setup(x => x.ActiveDirectoryRights()).Returns(ActiveDirectoryRights.ExtendedRight); + var lapsGuid = Guid.NewGuid(); + mockRule.Setup(x => x.ObjectType()).Returns(lapsGuid); + collection.Add(mockRule.Object); + + mockSecurityDescriptor.Setup(m => m.GetAccessRules(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(collection); + mockSecurityDescriptor.Setup(m => m.GetOwner(It.IsAny())).Returns((string)null); + mockLDAPUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); + mockLDAPUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) + .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); + + + var searchResults = new[] + { + //These first 4 should be filtered by our DN filters + LdapResult.Ok(new MockDirectoryObject( + "CN=7868d4c8-ac41-4e05-b401-776280e8e9f1,CN=Operations,CN=DomainUpdates,CN=System,DC=testlab,DC=local" + , new Dictionary() + { + {LDAPProperties.SchemaIDGUID, lapsGuid.ToByteArray()}, + {LDAPProperties.Name, LDAPProperties.LegacyLAPSPassword} + }, null,null)), + }; + mockLDAPUtils.Setup(x => x.PagedQuery(It.IsAny(), It.IsAny())) + .Returns(searchResults.ToAsyncEnumerable); + + var processor = new ACLProcessor(mockLDAPUtils.Object); + var bytes = Utils.B64ToBytes(UnProtectedUserNtSecurityDescriptor); + var result = await processor.ProcessACL(bytes, _testDomainName, Label.Computer, true).ToArrayAsync(); + + Assert.Single(result); + var actual = result.First(); + Assert.Equal(actual.PrincipalType, expectedPrincipalType); + Assert.Equal(actual.PrincipalSID, expectedPrincipalSID); + Assert.False(actual.IsInherited); + Assert.Equal(actual.RightName, expectedRightName); + } [Fact] public void GetInheritedAceHashes_NullSD_Empty() {