locked
Invoke SetPassword C# LDAP provider...Whos got the fix?? RRS feed

  • Question

  • Howdy: 

    According to several many other forums, there seems to be a consistent issue with the Invoke("SetPassword, string password) in DirectoryEntry, in that it does not work!  Any clues as to how to work through this problem?  The code below throws an exception every time..."server is unwilling to processs the request". 

    As suggested in many forums, re-arranging the CommintChanges and order of operations was no help either.  With the WinNT provider this works like a champ, but LDAP no workie.

    This fails against 2k and 2k3 domains...I am domain admin in both running from an XP system that is logged into the domain when it is run.

    private void createUser()
    {
     DirectoryEntry adEntry = new DirectoryEntry("LDAP://mydomain");
            DirectoryEntry userEntry = adEntry.Children.Add("BobUser", "User");
            userEntry.Invoke("Put", new object[] { "Description", "User Description"});
            userEntry.CommitChanges();
            userEntry.Invoke("SetPassword", new object[] { "12345Abcd#" });
            userEntry.CommitChanges();
    }

     

    Thanks in advance if anyone can point out my errors.

    hagan3

    Thursday, March 2, 2006 1:18 AM

Answers

  • Your code should look like the following.  You need to add CN= to the username.  This is not neccessary with the Winnt Provider but required for LDAP.  It would also be better to use the properties property to set the User Description rather than through invoke,

    private void createUser()
    {
     DirectoryEntry adEntry = new DirectoryEntry("LDAP://mydomain");
            DirectoryEntry userEntry = adEntry.Children.Add("CN=BobUser", "User"}
            userEntry.Properties["Description"].Add("User Description");
            userEntry.CommitChanges();
            userEntry.Invoke("SetPassword", new object[] { "12345Abcd#" });
            userEntry.CommitChanges();
    }

    Thursday, March 9, 2006 12:14 AM
  • setPassword has been driving me crazy too, but for different reasons. I had my domain admin create an account operator account for my .NET Web service to use and by passing the userid/pw into the DirectoryEntry constructor it works. Here is the code I am using (VB.NET) I think I found it on google. Hope this helps-

    searchRoot = New DirectoryEntry(String.Format("LDAP://{0}/{1}", strDomainController, rootDN), strServiceAccountUserID, strServiceAccountPassword, AuthenticationTypes.Secure Or AuthenticationTypes.Sealing Or AuthenticationTypes.ServerBind)
    searcher = New DirectorySearcher(searchRoot)
    searcher.Filter = String.Format("sAMAccountName={0}", username)
    searcher.SearchScope = SearchScope.Subtree
    searcher.CacheResults = False
    results = searcher.FindAll()

    For Each result In results
     userEntry = result.GetDirectoryEntry()
            Exit For
    Next

    If userEntry Is Nothing Then
     Throw New InvalidOperationException("User not found in this domain.")
    End If

    userEntry.Invoke("setPassword", New Object() {newPassword})
    userEntry.CommitChanges()


    My problem is I am trying to run this code in a Web service and can't seem to get it to work consistently. I can run this successfully on a machine that is not part of any domain and as something as restricted as the IUSR account. However, within the production domain I can't run it unless I elevate the rights for the virtual directory. There is a lot of discussion on forums.asp.net regarding setPassword which you might want to read as well.

    Wednesday, March 8, 2006 3:35 PM

All replies

  • setPassword has been driving me crazy too, but for different reasons. I had my domain admin create an account operator account for my .NET Web service to use and by passing the userid/pw into the DirectoryEntry constructor it works. Here is the code I am using (VB.NET) I think I found it on google. Hope this helps-

    searchRoot = New DirectoryEntry(String.Format("LDAP://{0}/{1}", strDomainController, rootDN), strServiceAccountUserID, strServiceAccountPassword, AuthenticationTypes.Secure Or AuthenticationTypes.Sealing Or AuthenticationTypes.ServerBind)
    searcher = New DirectorySearcher(searchRoot)
    searcher.Filter = String.Format("sAMAccountName={0}", username)
    searcher.SearchScope = SearchScope.Subtree
    searcher.CacheResults = False
    results = searcher.FindAll()

    For Each result In results
     userEntry = result.GetDirectoryEntry()
            Exit For
    Next

    If userEntry Is Nothing Then
     Throw New InvalidOperationException("User not found in this domain.")
    End If

    userEntry.Invoke("setPassword", New Object() {newPassword})
    userEntry.CommitChanges()


    My problem is I am trying to run this code in a Web service and can't seem to get it to work consistently. I can run this successfully on a machine that is not part of any domain and as something as restricted as the IUSR account. However, within the production domain I can't run it unless I elevate the rights for the virtual directory. There is a lot of discussion on forums.asp.net regarding setPassword which you might want to read as well.

    Wednesday, March 8, 2006 3:35 PM
  • Your code should look like the following.  You need to add CN= to the username.  This is not neccessary with the Winnt Provider but required for LDAP.  It would also be better to use the properties property to set the User Description rather than through invoke,

    private void createUser()
    {
     DirectoryEntry adEntry = new DirectoryEntry("LDAP://mydomain");
            DirectoryEntry userEntry = adEntry.Children.Add("CN=BobUser", "User"}
            userEntry.Properties["Description"].Add("User Description");
            userEntry.CommitChanges();
            userEntry.Invoke("SetPassword", new object[] { "12345Abcd#" });
            userEntry.CommitChanges();
    }

    Thursday, March 9, 2006 12:14 AM
  • here is the solution in code : 

      string newPassword = Membership.GeneratePassword(12, 4);
      string quotePwd;
      byte[] pwdBin;

      quotePwd = String.Format(@"""{0}""", newPassword);

      pwdBin = System.Text.Encoding.Unicode.GetBytes(quotePwd);

      UserEntry.Properties["unicodePwd"].Value = pwdBin;

      UserEntry.CommitChanges();

    ;) Mohamed Hachem


    Momo
    Wednesday, July 21, 2010 1:13 PM
  • Hi guys :)

    after three weeks of research s and headaches

    here is the solution  :

    public void SetPassword(string path, string sPassword)
            {
                try
                {
                    using (new Impersonator("AuthenticatedUserOnAD", "yourDomain", "AuthenticatedUserPassword"))
                    {

                        DirectoryEntry usr = new DirectoryEntry();
                        usr.Path = path;
                        usr.AuthenticationType = AuthenticationTypes.Secure;
                        object ret = usr.Invoke("SetPassword", sPassword);

                        usr.CommitChanges();
                        usr.Close();
                    }

                }
                catch (Exception exc)
                {
                    ErrorLoging.ErrorLog.InsertToLog(this.ErrorLogPath, "ADM","Change Password failed :"+ exc.Message, exc.StackTrace, path, "");
                }

            }

     

    here is Impersonator class :

    ---------------------------------

    namespace ADirectoryManager
    {
        #region Using directives.
        // ----------------------------------------------------------------------

        using System;
        using System.Security.Principal;
        using System.Runtime.InteropServices;
        using System.ComponentModel;

        // ----------------------------------------------------------------------
        #endregion

        /////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Impersonation of a user. Allows to execute code under another
        /// user context.
        /// Please note that the account that instantiates the Impersonator class
        /// needs to have the 'Act as part of operating system' privilege set.
        /// </summary>
        /// <remarks>   
        /// This class is based on the information in the Microsoft knowledge base
        /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
        ///
        /// Encapsulate an instance into a using-directive like e.g.:
        ///
        ///        ...
        ///        using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
        ///        {
        ///            ...
        ///            [code that executes under the new context]
        ///            ...
        ///        }
        ///        ...
        ///
        /// Please contact the author Uwe Keim (mailto:uwe.keim@zeta-software.de)
        /// for questions regarding this class.
        /// </remarks>
        public class Impersonator :
            IDisposable
        {
            #region Public methods.
            // ------------------------------------------------------------------

            /// <summary>
            /// Constructor. Starts the impersonation with the given credentials.
            /// Please note that the account that instantiates the Impersonator class
            /// needs to have the 'Act as part of operating system' privilege set.
            /// </summary>
            /// <param name="userName">The name of the user to act as.</param>
            /// <param name="domainName">The domain name of the user to act as.</param>
            /// <param name="password">The password of the user to act as.</param>
            public Impersonator(
                string userName,
                string domainName,
                string password )
            {
                ImpersonateValidUser( userName, domainName, password );
            }

            // ------------------------------------------------------------------
            #endregion

            #region IDisposable member.
            // ------------------------------------------------------------------

            public void Dispose()
            {
                UndoImpersonation();
            }

            // ------------------------------------------------------------------
            #endregion

            #region P/Invoke.
            // ------------------------------------------------------------------

            [DllImport("advapi32.dll", SetLastError=true)]
            private static extern int LogonUser(
                string lpszUserName,
                string lpszDomain,
                string lpszPassword,
                int dwLogonType,
                int dwLogonProvider,
                ref IntPtr phToken);
           
            [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
            private static extern int DuplicateToken(
                IntPtr hToken,
                int impersonationLevel,
                ref IntPtr hNewToken);

            [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
            private static extern bool RevertToSelf();

            [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
            private static extern  bool CloseHandle(
                IntPtr handle);

            private const int LOGON32_LOGON_INTERACTIVE = 2;
            private const int LOGON32_PROVIDER_DEFAULT = 0;

            // ------------------------------------------------------------------
            #endregion

            #region Private member.
            // ------------------------------------------------------------------

            /// <summary>
            /// Does the actual impersonation.
            /// </summary>
            /// <param name="userName">The name of the user to act as.</param>
            /// <param name="domainName">The domain name of the user to act as.</param>
            /// <param name="password">The password of the user to act as.</param>
            private void ImpersonateValidUser(
                string userName,
                string domain,
                string password )
            {
                WindowsIdentity tempWindowsIdentity = null;
                IntPtr token = IntPtr.Zero;
                IntPtr tokenDuplicate = IntPtr.Zero;

                try
                {
                    if ( RevertToSelf() )
                    {
                        if ( LogonUser(
                            userName,
                            domain,
                            password,
                            LOGON32_LOGON_INTERACTIVE,
                            LOGON32_PROVIDER_DEFAULT,
                            ref token ) != 0 )
                        {
                            if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 )
                            {
                                tempWindowsIdentity = new WindowsIdentity( tokenDuplicate );
                                impersonationContext = tempWindowsIdentity.Impersonate();
                            }
                            else
                            {
                                throw new Win32Exception( Marshal.GetLastWin32Error() );
                            }
                        }
                        else
                        {
                            throw new Win32Exception( Marshal.GetLastWin32Error() );
                        }
                    }
                    else
                    {
                        throw new Win32Exception( Marshal.GetLastWin32Error() );
                    }
                }
                finally
                {
                    if ( token!= IntPtr.Zero )
                    {
                        CloseHandle( token );
                    }
                    if ( tokenDuplicate!=IntPtr.Zero )
                    {
                        CloseHandle( tokenDuplicate );
                    }
                }
            }

            /// <summary>
            /// Reverts the impersonation.
            /// </summary>
            private void UndoImpersonation()
            {
                if ( impersonationContext!=null )
                {
                    impersonationContext.Undo();
                }   
            }

            private WindowsImpersonationContext impersonationContext = null;

            // ------------------------------------------------------------------
            #endregion
        }

        /////////////////////////////////////////////////////////////////////////
    }

     

    Monday, November 1, 2010 9:52 AM
  • Interesting point. I agree i sometimes wish for simplier things. It seems that somethings are more complex or not so simple to use anymore. They try to make them work better and do more things but sometimes they make things worse

    Cara Beriklan di Internet Handphone STMIK AMIKOM menuju Research University
    Tuesday, December 28, 2010 10:59 AM
  • I know this thread is old, but this is what I ended up doing to get 'around' the invoke err.  Take note, however, we are reading a large file of names to be created for each name iTrimmed.ToLower() is simply grabbing the username (which is all upper in the file being read) and converting it to lower.  These are generic accounts for testing, but we generate a lot.  It works, very well.

    string passwordProp = "new object []{" + "\"" + iTrimmed.ToLower() + "\"" + "}";
    
    user.Invoke("SetPassword", passwordProp);

    hope it helps someone....it took me a week to figure this crap out!!!!  But I still love coding

    Thursday, May 10, 2012 4:51 PM
  • don't call the directoryentry by IP adress but try to put the domain name 
    Wednesday, October 24, 2012 3:46 PM
  • Still does not work.
    Sunday, September 3, 2017 3:22 PM