Lately I have to explain to one of our customers how to create attribute in Active Directory which can be protected with additional permissions from reading its content. Such possibility was introduced in Windows 2003 SP1 but when I looked for some information to point our customer to I didn’t found much documentation so I decided to blog about it. What are confidential attributes? These are ordinary Active Directory schema attributes for which confidentiality bit was set in searchFlags (I explain how to do that later in this post). Result of this operation is that Read permission is not enough for a user to read this attribute content. Such possibility can be useful if You need to store in AD some value which should not be readable by everyone who has an access to the object which contains this attribute. In my customer scenario this was a number called PESEL – in Poland this is number assigned to every citizen which lets You identify a person. In this scenario my customer wanted to store this number in AD for the purpose of data synchronization between different directories, but polish law forces organizations to protect such sensitive data. So this data can be visible only for a user, a specified subset of admin stuff and synchronization services account. First we have to extend the user object class with a new attribute, in our case we called it lb-UserPesel, below You will find simple LDIF file with this attribute definition (I used oidgen.exe to generate OIDs for this example but in production environment You should not use it. Instead of this You should request OIDs pool from Microsoft using MSDN page):
dn: CN=lb-UserPesel,CN=Schema,Cn=Configuration,DC=domain, DC=PL
changetype: add
objectClass: attributeSchema
lDAPDisplayName: lb-UserPesel
adminDescription: This attribute stores user’s sensitive personal number
attributeID: 1.2.840.113556.1.4.7000.233.28688.28684.8.223249.327329.421971.1060153
attributeSyntax: 2.5.5.3
oMSyntax: 27
isSingleValued: TRUE
showInAdvancedViewOnly: TRUE
This introduces new attribute in our AD schema. Next we have to create auxiliary class which will contain this attribute and will let us to extend standard user class with this attribute. Below is an example of simple LDIF file which will define auxiliary class called lb-SensitiveData which will contain our lbUserPesel attribute:
dn: CN=lb-SensitiveData,CN=Schema,Cn=Configuration,DC=Domain,DC=PL
changetype: add
objectClass: classSchema
lDAPDisplayName: lb-SensitiveData
adminDescription: This auxiliary class contains user’s sensitive data definitions
governSID: 1.2.840.113556.1.5.7000.111.28688.28684.8.265102.1812148.2063820.1081313
mayContain: 1.2.840.113556.1.4.7000.233.28688.28684.8.223249.327329.421971.1060153
objectClassCategory: 3
subClassOf: top
defaultHidingValue: TRUE
showInAdvancedViewOnly: TRUE
Last step is to extend user class auxiliary classes list with our newly created class:
dn: CN=User,CN=Schema,Cn=Configuration,DC=domain,DC=PL
changetype: modify
add: auxiliaryClass
auxiliaryClass: lb-SensitiveData
Now we can make our attribute confidential. To do this we have to set bit 0x80 (decimal 128) in searchFlags attribute value to 1. If this attribute has some value already of course we have to perform OR operation with previous value of searchFlags for this attribute. In our example we can view current searchFlags value with ldp.exe:
Expanding base 'CN=lb-UserPesel,CN=Schema,CN=Configuration,domain,DC=pl'...
Getting 1 entries:
>> Dn: CN=lb-UserPesel,CN=Schema,CN=Configuration,DC=domain,DC=pl
2> objectClass: top; attributeSchema;
1> cn: lb-UserPesel;
1> distinguishedName: CN=lb-UserPesel,CN=Schema,CN=Configuration,DC=domain,DC=pl;
1> instanceType: 0x4 = ( IT_WRITE );
(…)
1> searchFlags: 0x0 = ( );
1> lDAPDisplayName: lb-UserPesel;
(…)
1> objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=franz,DC=era,DC=pl;
Because it is empty now we can add new value of 128 with LDP.EXE (see image below).
We can check if our attribute has correct bit set performing bitwise AND search against Your schema. To do this You have to search in Your schema partition with some tool using:
searchFlags:1.2.840.113556.1.4.803:=128
as a search criteria. String ‘1.2.840.113556.1.4.803' performs bitwise AND operation ,and just to give You additional information ‘1.2.840.113556.1.4.804' performs bitwise OR operation for specified attribute. Using LDP.exe (see image below) You should be able to find all the attributes with confidential bit set.
OK, so now we have confidential attribute defined in our schema and we have to make it readable for specified persons. The right to read content of confidential attribute is controlled with CONTROL_ACCESS permission. Security principal which should be able to read this should has to have READ_ATTRIBUTE and CONTROL_ACCESS set on specific object. Please notice that confidential bit is set on the attribute in the schema, but rights to read should be controlled on the object level, not schema permissions. To set this on the attribute itself one should define new structural class not auxiliary because auxiliary class doesn’t has its own permissions. It inherits permission from the structural class in which it is used.
The sad news is that standard Windows GUI would not support You with this operation, but in fact … who cares about GUI if we have cool tools like DSACLS or LDP., You can set CONTROL_ACCESS right using DSACLS.EXE or LDP.EXE but the version of LDP must be from Windows 2003 R2 install disk). LDP.EXE. DSACLS syntax to set this permission on container or object is:
dsacls <dn> /G <security principal>:ca;<attrName>;
Using LDP.EXE (notice that this is LDP.EXE taken from Windows 2003 R2 CD) You have to select container or object, right click it and choose Advanced -> Security descriptor with SACL option (see image below).
And this should be all folks. I strongly recommend to make all these changes in test environment first – changing the schema and dealing with permissions in AD is very sensitive operation so testing before going into production will be a good idea.
Hi Tomek, Great information. I have also been trying out "Confidential Attributes". So if you don't mind I would like to comment in addition to what you said…: * Only W2K3 SP1 DCs recognize the bit and the Schema FSMO must be at least W2K3 SP1 * Most effective when ALL DCs are W2K3 SP1 * Attributes configured with this bit can only be accessed/read by: –> Members of the “administrators” group –> Members of the “account operators” group (among others has by default Full Control on user and group objects) –> All security principals with Full Control on objects with confidential attributes –> Security principals with at least the permissions “READ_PROPERTY” and “CONTROL_ACCESS” for the confidential attribute * The confidentiality bit CANNOT be used for base-schema attributes (category 1) Base-schema attributes have in the property “systemFlags” the “Schema Base Object” bit set (5th bit: 2^4=16) * Granting the “CONTROL_ACCESS” permission: –> W2K3SP1 ACL Editor hides “All Extended Rights” on object classes that don’t have any extended rights associated (e.g. contact objects) –> DSACLS “object DN” /G\:CA (this configures “All Extended Rights” at object level) –> DSACLS “object DN” /G \:CA;; (this configures “All Extended Rights” at container level for certain objects) –> Using DSACLS OR ACL Editor at object level (by configuring “All Extended Rights”) ALSO assigns other extended rights like password reset. As I know of it is not possible to assign CONTROL_ACCESS at attribute level through DSACLS or ACL Editor –> LDP from ADAM-R2 can set CA at attribute level!!! (WHICH IS OK!!)
I raised dsacls /G :ca;; not working with MSFT back in August. I believe a bug was filed, hopefully it will get fixed soon. It was still broken when I last checked in ADAM DSACLS (1.1.3790.2049)
Thank's Jorge. I don't mind and thank you for this valuable update. Of course I should put this information in my entry but now it is in Your great comment. Thank's once again.