< Summary

Class:SharpHoundCommonLib.LDAPQueries.LdapFilter
Assembly:SharpHoundCommonLib
File(s):D:\a\SharpHoundCommon\SharpHoundCommon\src\CommonLib\LdapQueries\LdapFilter.cs
Covered lines:77
Uncovered lines:30
Coverable lines:107
Total lines:262
Line coverage:71.9% (77 of 107)
Covered branches:13
Total branches:16
Branch coverage:81.2% (13 of 16)

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%10100%
CheckConditions(...)100%20100%
FixFilter(...)100%40100%
BuildString(...)100%20100%
AddAllObjects(...)100%10100%
AddUsers(...)100%10100%
AddGroups(...)100%10100%
AddPrimaryGroups(...)100%100%
AddGPOs(...)100%100%
AddOUs(...)100%10100%
AddDomains(...)100%100%
AddContainers(...)100%10100%
AddConfiguration(...)100%100%
AddComputers(...)100%10100%
AddCertificateTemplates(...)100%10100%
AddCertificateAuthorities(...)100%10100%
AddEnterpriseCertificationAuthorities(...)100%10100%
AddIssuancePolicies(...)100%100%
AddSchemaID(...)100%100%
AddComputersNoMSAs(...)100%10100%
AddFilter(...)0%200%
GetFilter()83.33%60100%
GetFilterList()100%10100%

File(s)

D:\a\SharpHoundCommon\SharpHoundCommon\src\CommonLib\LdapQueries\LdapFilter.cs

#LineLine coverage
 1using System.Collections.Generic;
 2using System.Linq;
 3
 4namespace SharpHoundCommonLib.LDAPQueries {
 5    /// <summary>
 6    ///     A class used to more easily build LDAP filters based on the common filters used by SharpHound
 7    /// </summary>
 8    public class LdapFilter {
 229        private readonly List<string> _filterParts = new();
 2210        private readonly List<string> _mandatory = new();
 11
 12        /// <summary>
 13        ///     Pre-filters conditions passed into filters. Will fix filters that are missing parentheses naively
 14        /// </summary>
 15        /// <param name="conditions"></param>
 16        /// <returns></returns>
 217        private static string[] CheckConditions(IEnumerable<string> conditions) {
 218            return conditions.Select(FixFilter).ToArray();
 219        }
 20
 221        private static string FixFilter(string filter) {
 322            if (!filter.StartsWith("(")) filter = $"({filter}";
 23
 324            if (!filter.EndsWith(")")) filter = $"{filter})";
 25
 226            return filter;
 227        }
 28
 29        /// <summary>
 30        ///     Takes a base filter and appends any number of LDAP conditionals in a LDAP "And" statement.
 31        ///     Returns the base filter if no extra conditions are specified
 32        /// </summary>
 33        /// <param name="baseFilter"></param>
 34        /// <param name="conditions"></param>
 35        /// <returns></returns>
 2936        private static string BuildString(string baseFilter, params string[] conditions) {
 5637            if (conditions.Length == 0) return baseFilter;
 38
 239            return $"(&{baseFilter}{string.Join("", CheckConditions(conditions))})";
 2940        }
 41
 42        /// <summary>
 43        ///     Add a wildcard filter will match all object types
 44        /// </summary>
 45        /// <param name="conditions"></param>
 46        /// <returns></returns>
 1047        public LdapFilter AddAllObjects(params string[] conditions) {
 1048            _filterParts.Add(BuildString("(objectclass=*)", conditions));
 49
 1050            return this;
 1051        }
 52
 53        /// <summary>
 54        ///     Add a filter that will match User objects
 55        /// </summary>
 56        /// <param name="conditions"></param>
 57        /// <returns></returns>
 358        public LdapFilter AddUsers(params string[] conditions) {
 359            _filterParts.Add(BuildString("(samaccounttype=805306368)", conditions));
 60
 361            return this;
 362        }
 63
 64        /// <summary>
 65        ///     Add a filter that will match Group objects
 66        /// </summary>
 67        /// <param name="conditions"></param>
 68        /// <returns></returns>
 369        public LdapFilter AddGroups(params string[] conditions) {
 370            _filterParts.Add(BuildString(
 371                "(|(samaccounttype=268435456)(samaccounttype=268435457)(samaccounttype=536870912)(samaccounttype=5368709
 372                conditions));
 73
 374            return this;
 375        }
 76
 77        /// <summary>
 78        ///     Add a filter that will include any object with a primary group
 79        /// </summary>
 80        /// <param name="conditions"></param>
 81        /// <returns></returns>
 082        public LdapFilter AddPrimaryGroups(params string[] conditions) {
 083            _filterParts.Add(BuildString("(primarygroupid=*)", conditions));
 84
 085            return this;
 086        }
 87
 88        /// <summary>
 89        ///     Add a filter that will include GPO objects
 90        /// </summary>
 91        /// <param name="conditions"></param>
 92        /// <returns></returns>
 093        public LdapFilter AddGPOs(params string[] conditions) {
 094            _filterParts.Add(BuildString("(&(objectcategory=groupPolicyContainer)(flags=*))", conditions));
 95
 096            return this;
 097        }
 98
 99        /// <summary>
 100        ///     Add a filter that will include OU objects
 101        /// </summary>
 102        /// <param name="conditions"></param>
 103        /// <returns></returns>
 1104        public LdapFilter AddOUs(params string[] conditions) {
 1105            _filterParts.Add(BuildString("(objectcategory=organizationalUnit)", conditions));
 106
 1107            return this;
 1108        }
 109
 110        /// <summary>
 111        ///     Add a filter that will include Domain objects
 112        /// </summary>
 113        /// <param name="conditions"></param>
 114        /// <returns></returns>
 0115        public LdapFilter AddDomains(params string[] conditions) {
 0116            _filterParts.Add(BuildString("(objectclass=domain)", conditions));
 117
 0118            return this;
 0119        }
 120
 121        /// <summary>
 122        ///     Add a filter that will include Container objects
 123        /// </summary>
 124        /// <param name="conditions"></param>
 125        /// <returns></returns>
 1126        public LdapFilter AddContainers(params string[] conditions) {
 1127            _filterParts.Add(BuildString("(&(!(objectClass=groupPolicyContainer))(objectClass=container))", conditions))
 128
 1129            return this;
 1130        }
 131
 132        /// <summary>
 133        ///     Add a filter that will include Configuration objects
 134        /// </summary>
 135        /// <param name="conditions"></param>
 136        /// <returns></returns>
 0137        public LdapFilter AddConfiguration(params string[] conditions) {
 0138            _filterParts.Add(BuildString("(objectClass=configuration)", conditions));
 139
 0140            return this;
 0141        }
 142
 143        /// <summary>
 144        ///     Add a filter that will include Computer objects
 145        ///
 146        ///     Note that gMSAs and sMSAs have this samaccounttype as well
 147        /// </summary>
 148        /// <param name="conditions"></param>
 149        /// <returns></returns>
 2150        public LdapFilter AddComputers(params string[] conditions) {
 2151            _filterParts.Add(BuildString("(samaccounttype=805306369)", conditions));
 2152            return this;
 2153        }
 154
 155        /// <summary>
 156        ///     Add a filter that will include PKI Certificate templates
 157        /// </summary>
 158        /// <param name="conditions"></param>
 159        /// <returns></returns>
 1160        public LdapFilter AddCertificateTemplates(params string[] conditions) {
 1161            _filterParts.Add(BuildString("(objectclass=pKICertificateTemplate)", conditions));
 1162            return this;
 1163        }
 164
 165        /// <summary>
 166        ///     Add a filter that will include Certificate Authorities
 167        /// </summary>
 168        /// <param name="conditions"></param>
 169        /// <returns></returns>
 1170        public LdapFilter AddCertificateAuthorities(params string[] conditions) {
 1171            _filterParts.Add(BuildString("(objectClass=certificationAuthority)",
 1172                conditions));
 1173            return this;
 1174        }
 175
 176        /// <summary>
 177        ///     Add a filter that will include Enterprise Certificate Authorities
 178        /// </summary>
 179        /// <param name="conditions"></param>
 180        /// <returns></returns>
 1181        public LdapFilter AddEnterpriseCertificationAuthorities(params string[] conditions) {
 1182            _filterParts.Add(BuildString("(objectCategory=pKIEnrollmentService)", conditions));
 1183            return this;
 1184        }
 185
 186        /// <summary>
 187        ///     Add a filter that will include Issuance Policies
 188        /// </summary>
 189        /// <param name="conditions"></param>
 190        /// <returns></returns>
 0191        public LdapFilter AddIssuancePolicies(params string[] conditions) {
 0192            _filterParts.Add(BuildString("(objectClass=msPKI-Enterprise-Oid)", conditions));
 0193            return this;
 0194        }
 195
 196        /// <summary>
 197        ///     Add a filter that will include schema items
 198        /// </summary>
 199        /// <param name="conditions"></param>
 200        /// <returns></returns>
 0201        public LdapFilter AddSchemaID(params string[] conditions) {
 0202            _filterParts.Add(BuildString("(schemaidguid=*)", conditions));
 0203            return this;
 0204        }
 205
 206        /// <summary>
 207        ///     Add a filter that will include Computer objects but exclude gMSA and sMSA objects
 208        /// </summary>
 209        /// <param name="conditions"></param>
 210        /// <returns></returns>
 6211        public LdapFilter AddComputersNoMSAs(params string[] conditions) {
 6212            _filterParts.Add(BuildString(
 6213                "(&(samaccounttype=805306369)(!(objectclass=msDS-GroupManagedServiceAccount))(!(objectclass=msDS-Managed
 6214                conditions));
 6215            return this;
 6216        }
 217
 218        /// <summary>
 219        ///     Adds a generic user specified filter
 220        /// </summary>
 221        /// <param name="filter">LDAP Filter to add to query</param>
 222        /// <param name="enforce">If true, filter will be AND otherwise OR</param>
 223        /// <returns></returns>
 0224        public LdapFilter AddFilter(string filter, bool enforce) {
 0225            if (enforce)
 0226                _mandatory.Add(FixFilter(filter));
 227            else
 0228                _filterParts.Add(FixFilter(filter));
 229
 0230            return this;
 0231        }
 232
 233        /// <summary>
 234        ///     Combines all the specified parts of the LDAP filter and merges them into a single string
 235        /// </summary>
 236        /// <returns></returns>
 18237        public string GetFilter() {
 18238            var filterPartList = _filterParts.ToArray().Distinct();
 18239            var mandatoryList = _mandatory.ToArray().Distinct();
 240
 18241            var filterPartsExceptMandatory = filterPartList.Except(mandatoryList).ToList();
 242
 18243            var filterPartsDistinct = string.Join("", filterPartsExceptMandatory);
 18244            var mandatoryDistinct = string.Join("", mandatoryList);
 245
 18246            if (filterPartsExceptMandatory.Count == 1)
 17247                filterPartsDistinct = filterPartsExceptMandatory[0];
 1248            else if (filterPartsExceptMandatory.Count > 1)
 1249                filterPartsDistinct = $"(|{filterPartsDistinct})";
 250
 18251            filterPartsDistinct = _mandatory.Count > 0
 18252                ? $"(&{filterPartsDistinct}{mandatoryDistinct})"
 18253                : filterPartsDistinct;
 254
 18255            return filterPartsDistinct;
 18256        }
 257
 1258        public IEnumerable<string> GetFilterList() {
 1259            return _filterParts.Distinct();
 1260        }
 261    }
 262}