HOWTO - Set Active Directory Delegated Privileges
I created a C # web service that allows our foreground support teams to view and update multiple selected Active Directory values using system.directoryservices
The fields I want to update are [job] title, department, telephone and employeeid.
I can use the "delegate" service account to update the [job], department, phone, etc., but when I try to update the employeeid, I get an "not authorized" error.
If I am using a domain admin account then the same code works fine.
I don't want to use a domain admin account for this web service, so what privileges do I need?
ANSWER
ADS_SCHEMA_ID_GUID_USER GUID allows you to update base user class information including employee ID
Based on MSDN article
vbscript is used to grant the user the service account of the selected delegated rights:
REM #
REM # Delegate AD property set admin rights to named account
REM # Based on: http://www.microsoft.com/technet/scriptcenter/topics/security/propset.mspx
REM #
Const TRUSTEE_ACCOUNT_SAM = "ad\ADStaffUpdates"
Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5
Const ADS_RIGHT_DS_READ_PROP = &H10
Const ADS_RIGHT_DS_WRITE_PROP = &H20
Const ADS_FLAG_OBJECT_TYPE_PRESENT = &H1
Const ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = &H2
Const ADS_ACEFLAG_INHERIT_ACE = &H2
Const ADS_SCHEMA_ID_GUID_USER = "{bf967aba-0de6-11d0-a285-00aa003049e2}"
Const ADS_SCHEMA_ID_GUID_PS_PERSONAL = "{77b5b886-944a-11d1-aebd-0000f80367c1}"
Const ADS_SCHEMA_ID_GUID_PS_PUBLIC = "{e48d0154-bcf8-11d1-8702-00c04fb96050}"
ad_setUserDelegation "OU=USERS, DC=AD, DC=COM", TRUSTEE_ACCOUNT_SAM, ADS_SCHEMA_ID_GUID_PS_USER
ad_setUserDelegation "OU=USERS, DC=AD, DC=COM", TRUSTEE_ACCOUNT_SAM, ADS_SCHEMA_ID_GUID_PS_PERSONAL
ad_setUserDelegation "OU=USERS, DC=AD, DC=COM", TRUSTEE_ACCOUNT_SAM, ADS_SCHEMA_ID_GUID_PS_PUBLIC
Function ad_setUserDelegation( _
ByVal strOU _
,ByVal strTrusteeAccount _
,ByVal strSchema_GUID _
)
Set objSdUtil = GetObject( "LDAP://" & strOU )
Set objSD = objSdUtil.Get( "ntSecurityDescriptor" )
Set objDACL = objSD.DiscretionaryACL
Set objAce = CreateObject( "AccessControlEntry" )
objAce.Trustee = strTrusteeAccount
objAce.AceFlags = ADS_ACEFLAG_INHERIT_ACE
objAce.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
objAce.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT OR ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT
objAce.ObjectType = strSchema_GUID
objACE.InheritedObjectType = ADS_SCHEMA_ID_GUID_USER
objAce.AccessMask = ADS_RIGHT_DS_READ_PROP OR ADS_RIGHT_DS_WRITE_PROP
objDacl.AddAce objAce
objSD.DiscretionaryAcl = objDacl
objSDUtil.Put "ntSecurityDescriptor", Array( objSD )
objSDUtil.SetInfo
End Function
Function ad_revokeUserDelegation( _
ByVal strOU _
,ByVal strTrusteeAccount _
)
Set objSdUtil = GetObject( "LDAP://" & strOU )
Set objSD = objSdUtil.Get( "ntSecurityDescriptor" )
Set objDACL = objSD.DiscretionaryACL
For Each objACE in objDACL
If UCase(objACE.Trustee) = UCase(strTrusteeAccount) Then
objDACL.RemoveAce objACE
End If
Next
objSDUtil.Put "ntSecurityDescriptor", Array(objSD)
objSDUtil.SetInfo
End Function
Sample code (at least moving parts)
string distinguishedname = "CN=Wicks\, Guy,OU=Users,DC=ad,DC=com"
using (DirectoryEntry myDirectoryEntry = new DirectoryEntry(string.Format("LDAP://{0}", distinguishedname), null, null, AuthenticationTypes.Secure))
{
try
{
myDirectoryEntry.Username = "serviceaccount";
myDirectoryEntry.Password = "pa55word";
myDirectoryEntry.Properties["employeeid"][0] = employeeID;
myDirectoryEntry.CommitChanges();
setresult.result = myDirectoryEntry.Properties["employeeid"][0].ToString();
}
catch ( Exception ex )
{
setresult.result = ex.Message;
}
} // end using
(I am sorry for my C #)
Do your service users have permission to change these fields through AD users and computers? if they are then maybe you can use impersonation and just making your service host machine "trusted for delegation" (in the AD properties for it) has always worked fine for me.