< Summary

Class:SharpHoundCommonLib.LDAPQueries.LDAPFilter
Assembly:SharpHoundCommonLib
File(s):D:\a\SharpHoundCommon\SharpHoundCommon\src\CommonLib\LDAPQueries\LDAPFilter.cs
Covered lines:73
Uncovered lines:30
Coverable lines:103
Total lines:283
Line coverage:70.8% (73 of 103)
Covered branches:11
Total branches:14
Branch coverage:78.5% (11 of 14)

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%10100%
CheckConditions(...)100%10100%
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{
 6    /// <summary>
 7    ///     A class used to more easily build LDAP filters based on the common filters used by SharpHound
 8    /// </summary>
 9    public class LDAPFilter
 10    {
 1111        private readonly List<string> _filterParts = new();
 1112        private readonly List<string> _mandatory = new();
 13
 14        /// <summary>
 15        ///     Pre-filters conditions passed into filters. Will fix filters that are missing parentheses naively
 16        /// </summary>
 17        /// <param name="conditions"></param>
 18        /// <returns></returns>
 19        private static string[] CheckConditions(IEnumerable<string> conditions)
 220        {
 221            return conditions.Select(FixFilter).ToArray();
 222        }
 23
 24        private static string FixFilter(string filter)
 225        {
 426            if (!filter.StartsWith("(")) filter = $"({filter}";
 27
 428            if (!filter.EndsWith(")")) filter = $"{filter})";
 29
 230            return filter;
 231        }
 32
 33        /// <summary>
 34        ///     Takes a base filter and appends any number of LDAP conditionals in a LDAP "And" statement.
 35        ///     Returns the base filter if no extra conditions are specified
 36        /// </summary>
 37        /// <param name="baseFilter"></param>
 38        /// <param name="conditions"></param>
 39        /// <returns></returns>
 40        private static string BuildString(string baseFilter, params string[] conditions)
 1841        {
 3442            if (conditions.Length == 0) return baseFilter;
 43
 244            return $"(&{baseFilter}{string.Join("", CheckConditions(conditions))})";
 1845        }
 46
 47        /// <summary>
 48        ///     Add a wildcard filter will match all object types
 49        /// </summary>
 50        /// <param name="conditions"></param>
 51        /// <returns></returns>
 52        public LDAPFilter AddAllObjects(params string[] conditions)
 253        {
 254            _filterParts.Add(BuildString("(objectclass=*)", conditions));
 55
 256            return this;
 257        }
 58
 59        /// <summary>
 60        ///     Add a filter that will match User objects
 61        /// </summary>
 62        /// <param name="conditions"></param>
 63        /// <returns></returns>
 64        public LDAPFilter AddUsers(params string[] conditions)
 365        {
 366            _filterParts.Add(BuildString("(samaccounttype=805306368)", conditions));
 67
 368            return this;
 369        }
 70
 71        /// <summary>
 72        ///     Add a filter that will match Group objects
 73        /// </summary>
 74        /// <param name="conditions"></param>
 75        /// <returns></returns>
 76        public LDAPFilter AddGroups(params string[] conditions)
 377        {
 378            _filterParts.Add(BuildString(
 379                "(|(samaccounttype=268435456)(samaccounttype=268435457)(samaccounttype=536870912)(samaccounttype=5368709
 380                conditions));
 81
 382            return this;
 383        }
 84
 85        /// <summary>
 86        ///     Add a filter that will include any object with a primary group
 87        /// </summary>
 88        /// <param name="conditions"></param>
 89        /// <returns></returns>
 90        public LDAPFilter AddPrimaryGroups(params string[] conditions)
 091        {
 092            _filterParts.Add(BuildString("(primarygroupid=*)", conditions));
 93
 094            return this;
 095        }
 96
 97        /// <summary>
 98        ///     Add a filter that will include GPO objects
 99        /// </summary>
 100        /// <param name="conditions"></param>
 101        /// <returns></returns>
 102        public LDAPFilter AddGPOs(params string[] conditions)
 0103        {
 0104            _filterParts.Add(BuildString("(&(objectcategory=groupPolicyContainer)(flags=*))", conditions));
 105
 0106            return this;
 0107        }
 108
 109        /// <summary>
 110        ///     Add a filter that will include OU objects
 111        /// </summary>
 112        /// <param name="conditions"></param>
 113        /// <returns></returns>
 114        public LDAPFilter AddOUs(params string[] conditions)
 1115        {
 1116            _filterParts.Add(BuildString("(objectcategory=organizationalUnit)", conditions));
 117
 1118            return this;
 1119        }
 120
 121        /// <summary>
 122        ///     Add a filter that will include Domain objects
 123        /// </summary>
 124        /// <param name="conditions"></param>
 125        /// <returns></returns>
 126        public LDAPFilter AddDomains(params string[] conditions)
 0127        {
 0128            _filterParts.Add(BuildString("(objectclass=domain)", conditions));
 129
 0130            return this;
 0131        }
 132
 133        /// <summary>
 134        ///     Add a filter that will include Container objects
 135        /// </summary>
 136        /// <param name="conditions"></param>
 137        /// <returns></returns>
 138        public LDAPFilter AddContainers(params string[] conditions)
 1139        {
 1140            _filterParts.Add(BuildString("(objectClass=container)", conditions));
 141
 1142            return this;
 1143        }
 144
 145        /// <summary>
 146        ///     Add a filter that will include Configuration objects
 147        /// </summary>
 148        /// <param name="conditions"></param>
 149        /// <returns></returns>
 150        public LDAPFilter AddConfiguration(params string[] conditions)
 0151        {
 0152            _filterParts.Add(BuildString("(objectClass=configuration)", conditions));
 153
 0154            return this;
 0155        }
 156
 157        /// <summary>
 158        ///     Add a filter that will include Computer objects
 159        ///
 160        ///     Note that gMSAs and sMSAs have this samaccounttype as well
 161        /// </summary>
 162        /// <param name="conditions"></param>
 163        /// <returns></returns>
 164        public LDAPFilter AddComputers(params string[] conditions)
 2165        {
 2166            _filterParts.Add(BuildString("(samaccounttype=805306369)", conditions));
 2167            return this;
 2168        }
 169
 170        /// <summary>
 171        ///     Add a filter that will include PKI Certificate templates
 172        /// </summary>
 173        /// <param name="conditions"></param>
 174        /// <returns></returns>
 175        public LDAPFilter AddCertificateTemplates(params string[] conditions)
 1176        {
 1177            _filterParts.Add(BuildString("(objectclass=pKICertificateTemplate)", conditions));
 1178            return this;
 1179        }
 180
 181        /// <summary>
 182        ///     Add a filter that will include Certificate Authorities
 183        /// </summary>
 184        /// <param name="conditions"></param>
 185        /// <returns></returns>
 186        public LDAPFilter AddCertificateAuthorities(params string[] conditions)
 1187        {
 1188            _filterParts.Add(BuildString("(|(objectClass=certificationAuthority)(objectClass=pkiEnrollmentService))",
 1189                conditions));
 1190            return this;
 1191        }
 192
 193        /// <summary>
 194        ///     Add a filter that will include Enterprise Certificate Authorities
 195        /// </summary>
 196        /// <param name="conditions"></param>
 197        /// <returns></returns>
 198        public LDAPFilter AddEnterpriseCertificationAuthorities(params string[] conditions)
 1199        {
 1200            _filterParts.Add(BuildString("(objectCategory=pKIEnrollmentService)", conditions));
 1201            return this;
 1202        }
 203
 204        /// <summary>
 205        ///     Add a filter that will include Issuance Policies
 206        /// </summary>
 207        /// <param name="conditions"></param>
 208        /// <returns></returns>
 209        public LDAPFilter AddIssuancePolicies(params string[] conditions)
 0210        {
 0211            _filterParts.Add(BuildString("(objectClass=msPKI-Enterprise-Oid)", conditions));
 0212            return this;
 0213        }
 214
 215        /// <summary>
 216        ///     Add a filter that will include schema items
 217        /// </summary>
 218        /// <param name="conditions"></param>
 219        /// <returns></returns>
 220        public LDAPFilter AddSchemaID(params string[] conditions)
 0221        {
 0222            _filterParts.Add(BuildString("(schemaidguid=*)", conditions));
 0223            return this;
 0224        }
 225
 226        /// <summary>
 227        ///     Add a filter that will include Computer objects but exclude gMSA and sMSA objects
 228        /// </summary>
 229        /// <param name="conditions"></param>
 230        /// <returns></returns>
 231        public LDAPFilter AddComputersNoMSAs(params string[] conditions)
 3232        {
 3233            _filterParts.Add(BuildString("(&(samaccounttype=805306369)(!(objectclass=msDS-GroupManagedServiceAccount))(!
 3234            return this;
 3235        }
 236
 237        /// <summary>
 238        ///     Adds a generic user specified filter
 239        /// </summary>
 240        /// <param name="filter">LDAP Filter to add to query</param>
 241        /// <param name="enforce">If true, filter will be AND otherwise OR</param>
 242        /// <returns></returns>
 243        public LDAPFilter AddFilter(string filter, bool enforce)
 0244        {
 0245            if (enforce)
 0246                _mandatory.Add(FixFilter(filter));
 247            else
 0248                _filterParts.Add(FixFilter(filter));
 249
 0250            return this;
 0251        }
 252
 253        /// <summary>
 254        ///     Combines all the specified parts of the LDAP filter and merges them into a single string
 255        /// </summary>
 256        /// <returns></returns>
 257        public string GetFilter()
 9258        {
 259
 9260            var filterPartList = _filterParts.ToArray().Distinct();
 9261            var mandatoryList = _mandatory.ToArray().Distinct();
 262
 9263            var filterPartsExceptMandatory = filterPartList.Except(mandatoryList).ToList();
 264
 9265            var filterPartsDistinct = string.Join("", filterPartsExceptMandatory);
 9266            var mandatoryDistinct = string.Join("", mandatoryList);
 267
 9268            if (filterPartsExceptMandatory.Count == 1)
 8269                filterPartsDistinct = filterPartsExceptMandatory[0];
 1270            else if (filterPartsExceptMandatory.Count > 1)
 1271                filterPartsDistinct = $"(|{filterPartsDistinct})";
 272
 9273            filterPartsDistinct = _mandatory.Count > 0 ? $"(&{filterPartsDistinct}{mandatoryDistinct})" : filterPartsDis
 274
 9275            return filterPartsDistinct;
 9276        }
 277
 278        public IEnumerable<string> GetFilterList()
 1279        {
 1280            return _filterParts;
 1281        }
 282    }
 283}