Question

I've created a c# webservice that allows our front end support teams to view and update a few selected Active Directory values using system.directoryservices

Fields that I want to update are [job] title, department, telephone and employeeid.

I can use a service account with "delegates rights" to update [job] title, department, telephone etc. but when I try to update employeeid I get an "not authorised" error message.

If I use a domain admin account then the same code works fine.

I don't want to use a domain admin account for this webservice, so what privileges do I need?

Was it helpful?

Solution

ANSWER

The ADS_SCHEMA_ID_GUID_USER GUID allows you to update the base user class details, including the employee id

Based on MSDN article

The vbscript used to grant to the service account user 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

OTHER TIPS

A sample of the code (the moving parts at least)

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 do apologise for my c#)

do users of your service have the rights to modify those fields through AD users and computers? if they are then maybe you can use impersonation and just make your service host computer "trusted for delegation" (in AD properties for it) always worked fine for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top