Recently, we've had a push to enable 2FA on all of the internet-facing services we offer. A manager asked, "how many users do we have to worry about?" We have three basic types of users:
- Those who only have access to the Remote Desktops
- Those who only have access to the various applications
- Those who have access to both the Remote Desktops and to the various appliations
All such access is unprivileged. All accesses are managed via Active Directory group memberships.
- Our RDSH users are in a "remote desktops" group.
- Our application users are in a mix of groups. Fortunately, we long ago implemented standard naming for our groups. All group-names for one application-class start with "
T_
"; all group-names for the other application-class start with "E_
"
Fortunately, the above means that I could get an answer for the manager by way of LDAP queries. A user's membership in an Active Directory is conveyed via the user-object's meberOf attribute. This means that the basic query-objects I needed to consider were:
-
RDSH Users: In LDAP-speak, this works out to
CN=<RDSH_GROUP>,cn=users,dc=<F>,dc=<Q>,dc=<D>,dc=<N>
-
"T_" Application-group: In LDAP-speak, this works out to
CN=T_*
-
"E_" Application group: In LDAP-speak, this works out to
CN=E_*
LDAP queries generally operate on object-sets. Sets are denoted by parentheses. Using the previously-mentioned groups, a single-element set for each of my group-memberships would be:
(memberof=CN=<RDSH_GROUP>,cn=users,dc=<F>,dc=<Q>,dc=<D>,dc=<N>)
(memberof=CN=T_*)
(memberof=CN=E_*)
Where things get really freaking ugly is when you need to combine these into appropriate queries. Combining query-objects is a matter of using the booleans:
- "&": the logical AND operator
- "|": the logical OR operator
- "!": the logical NOT operator
- If you're familiar with logical operators, you'll notice that there isn't a built in eXclusive OR type of operator.
Why I say things are ugly is that you apply a given operator within a set and the syntax is a little non-intutive:
- ANDing sets: Uses the syntax
(&(SET1)(SET2)(...)(SET_N))
. Basically, this says, "AND all of the following sets within this AND-set. An AND-set can consist of 2+ sets for evaluation - ORing sets: Similarly, this uses the syntax
(|(SET1)(SET2)(...)(SET_N))
. Basically, this says, "OR all of the following sets within this OR-set. An OR-set can consist of 2+ sets for evaluation - NOTin sets: Similarly, this uses the syntax
(!(SET1)(SET2)(...)(SET_N))
. Basically, this says, "OR all of the following sets within this NOT-set. An NOT-set can consist of 2+ sets for evaluation
Where it gets really ugly is when a logical operation acually requires two or more sub operations. For example:
- When you want to tell if a user is a member of one group but not another, you need to do something like:
(&(GROUP1)(!(GROUP2))
- Similarly, when you want to tell if a user is a member of one group but not a member of both of two other groups, you would do something like
(&(GROUP1)(!(&(GROUP2)(GROUP3))
- Similarly, when you want to tell if a user is a member of one group but not a member of either of two other groups, you would do something like
(&(GROUP1)(!(|(GROUP2)(GROUP3))
As you can probably tell, as the number of selectors goes up, so does the ugliness.
At any rate, back to my original queries:
- Getting a list of all people with RDSH access, my query looks like:
(memberof=CN=<RDSH_GROUP>,cn=users,dc=<F>,dc=<Q>,dc=<D>,dc=<N>)
- Getting a list of people with membership in either of the application groups, my query looks like:
(|(memberof=CN=T_*)(memberof=CN=T_*))
- Getting a list of people with RDSH access and with membership in either of the application groups, my query looks like:
(&(memberof=CN=<RDSH_GROUP>,cn=users,dc=<F>,dc=<Q>,dc=<D>,dc=<N>)(|(memberof=CN=T_*)(memberof=CN=T_*)))
- Getting a list of people with RDSH access but not access to either of the other groups , my query now looks like:
(&(memberof=CN=<RDSH_GROUP>,cn=users,dc=<F>,dc=<Q>,dc=<D>,dc=<N>)(!(|(memberof=CN=T_*)(memberof=CN=T_*))))
- Conversely, getting a list of people without RDSH access but with access to either of the other groups, my query now looks like:
(&(!(memberof=CN=<RDSH_GROUP>,cn=users,dc=<F>,dc=<Q>,dc=<D>,dc=<N>))(|(memberof=CN=T_*)(memberof=CN=T_*)))
All that ugliness aside, I was able to get the manager the answer to his question and was able to do it quickly. This post is mostly a result of him asking "what the hell does all that gobbledygook mean" when I sent him the queries I ran to get him the answer. I'd sent that as part of the thread for the same reason I'm writing this: so I have the queries the next time the information is asked for again (and don't have to re-work it all out in my head again).
Top comments (0)