In my last post we discussed the DACL and how to get the Access List from a Directory Entry object. We finished the post by grabbing our (D)ACL as an AuthorizationRuleCollection.
In this post we are going to look at what that collection contains; a set of AuthorizationRule objects. Just to make things a little more interesting, the AuthorizationRuleCollection can contain two types of rule - Access Rules (for the DACL) and Audit Rules (for the SACL). As we are looking at the DACL rather than the SACL we will be looking at a type that is inherited from the AuthorizationRule called an AccessRule. If you were dealing with Audit Rules you would use the AuditRule type but we're not looking at those - we know that we only have AccessRule objects because we called the GetAccessRules method. If we wanted the SACL, or Audit Rules, then we'd call... yes you guessed it... GetAuditRules.
So we have our AccessRule objects. What does an AccessRule actually consist of? You can look on MSDN but frankly that won't help you too much. There isn't many properties or methods. This is because we actually want to deal with an object that is inherited from THAT one! Specifically, we want to deal with ActiveDirectoryAccessRule objects. So lets put this in perspective. We have our AuthorizationRule collection, but what do we actually want to work with?
System.Object - everything inherits from this
System.Security.AccessControl.AuthorizationRule - what we started with
System.Security.AccessControl.AccessRule - we know we want a DACL
System.Security.AccessControl.ObjectAccessRule - adds some stuff, don't worry about this
System.DirectoryServices.ActiveDirectoryAccessRule - Bingo!
This is one of the real gotchas of developing with ACLs because unless you know to jump to a class in another namespace you could get as far as an ObjectAccessRule and get stuck there. Thankfully, once you know you know and it's not really as bad as all that. Yes, phew :) All we need to do is just cast our AuthorizationRule all the way to an ActiveDirectoryAccessRule:
foreach (ActiveDirectoryAccessRule rule in aclRules)
{
// do stuff
}
So now, at last, we have our rule and we can have a poke around it. Now bear with me on this one because it's a little cryptic, but you need to know what every part of a rule does.
BREAKOUT:
Here's a little something for you to consider as this point. Any ACL editor you write should be able to deal with EVERY aspect of an ACL. Why? Well, it's down to the way the API works.
As we'll see later, the API provides ways to delete and add rules, but not to edit rules. You cannot just edit a particular attribute of an ACL without having to worry what all the rest do because there is no method to do that. This means that if you are working on existing rules, you effectively have to rebuild them from scratch with any appropriate change and then re-add them. If you start ignoring stuff on the existing rule when you rebuild it from scratch then you'll lose information.
For example, lets say you have an ACL that says "Allow John Smith to Add, Remove and List the Contents of all types of Foobar objects but only if they are direct children of the current object". If you miss one of the ACL properties, you could miss the fact that this only applies to Foobar objects. You could then end up with "Allow John Smith to Add, Remove and List Contents of all types of objects that are direct children of the current object." You can see that this could lead to all sorts of undesirable consequences!
An interesting aside is that the permissions editor for Active Directory / ADAM (ADSIEdit Security) does not fully support all aspects of the Active Directory permissions model. Yes, I know thats crazy. It is possible though to do some clever things with inherited permissions and objects they apply to that will be wiped out if you use the security tools. They are quite advanced permissions and it's unlikely you would come across them. I guess the tools MS provide cover 99% of cases and they figured that was good enough, and besides they probably doubted anyone would be doing anything that advanced programatically.
So what can our rule contain?
- AccessControlType - Enumerator that determines whether this is an Allow or Deny rule. It's a bit clunky, but lets say you want to Allow A and B rights to an object and Deny X and Y rights. You will actually need two rules to do this, one for the Allow and one for the Deny. Note also that if you Allow A and B rights and Deny B and C, for example, then B will be denied as the denial ALWAYS overrides.
- AccessMask - This is the access mask we set to do the rule search earlier, so it's not really that important other then for interest
- ActiveDirectoryRights - OK, this is the meaty bit :) We'll give this better coverage later
- IdentityReference - This is where the identity of the user/group to whom this ACL is applied is stored. If you remember on our previous post we discussed SIDs and NT Accounts - well this is where that information will be.
- InheritanceFlags - Sets whether inheritance applies to containers or leaves... we'll always use Container or a bitwise of Container and Leaf
- InheritanceType - Determines how far down the tree below this object the ACL applies
- InheritedObjectType - this is the type of object that can inherit this rule. For example, you could say 'only allow Computer objects to inherit this Rule'. It is stored as an object GUID and we'll show how to work out what it is later.
- IsInherited - shows whether this is an inherited rule. If it is, then chances are we'll show it in our ACL editor as a read-only rule as it should be changed up the tree where it actually originates
- ObjectFlags - info flag that we shouldn't need to worry about unless we build in some checking code
- ObjectType - an object to which this rule applies, which in reality will be some kind of property in the AD Schema. For example if this is a read permission rule then this could say 'allow reading of property X'
- PropagationFlags - shouldn't ever need to worry about this as it's related to inheritance but the inheritance is more important
Even though I've explained the properties a bit, you're probably not much better off than when you started. I think it best to give an example of a rule and we can see where the various attributes fit into things.
Lets say you have a rule like the following:
"Allow John Smith to Read or Change the displayName property of all objects of type User on every child object of this DirectoryEntry, but not this entry itself"
In terms of our object properties, we say the following:
"[AccessControlType: Allow] [IdentityReference: SID for John Smith] [ActiveDirectoryRights: Read and Change] [ObjectType: Object GUID for displayName] [InheritedObjectType: Object GUID for User] [InheritanceType: Descendents]"
By this point we should have a basic understanding of the kind of information that we have on an ActiveDirectoryAccessRule, which is the basic building block for an ACL. In my next post I'll look at a bit more detail at what information some of these properties actually contain and where we can find what they mean.