1

I am trying to run my password change application from a non domain joined machine. The code works fine when run from domain joined machine. So now, I am connecting to the AD with direct LDAP connection via SSL. After changepassword method is invoked, I am getting an error:

Configuration information could not be read from the domain controller, either because the machine is unavailable, or access has been denied. (Exception from HRESULT: 0x80070547).

I am making the connection and running the application using a service account with permission to change user passwords.

string adminUser = Domain + @"\" + AdminUserName;
string adminPass = AdminUserPassword;
string ldapString = LDAPString;

DirectoryEntry de = new DirectoryEntry(ldapString, adminUser, adminPass, AuthenticationTypes.Secure);
DirectorySearcher deSearch = new DirectorySearcher(de) { SearchRoot = de, Filter = "(&(objectCategory=user)(cn=" + userName + "))" };

SearchResult result = deSearch.FindOne();

if (result != null)
{
    var adContext = new PrincipalContext(ContextType.Domain);
    currentdc = adContext.ConnectedServer;

    DirectoryEntry userEntry = result.GetDirectoryEntry();

    if (userEntry != null)
    {
        userEntry.Invoke("ChangePassword", new object[] { OldPassword, NewPassword });
    }
}
Brett Caswell
  • 1,486
  • 1
  • 13
  • 25
Sam
  • 47
  • 1
  • 6
  • *... from a non domain joined machine* ... *works fine when run from domain joined machine*. Your Domain Controller does not seem accessible outside of your domain. Your exception indicates that you are failing to connect to the DC. your issue is networking and infrastructure related.. not code implementation. – Brett Caswell Nov 08 '19 at 01:28
  • By the way you worded this question, I am a bit surprised you posed it.. did you mean to ask for something else? – Brett Caswell Nov 08 '19 at 01:38
  • With the he same connection, I can connect to the DC, pull user attribute values, just the change password is not going through. – Sam Nov 08 '19 at 03:25
  • you're sure that the exception above is thrown on `userEntry.Invoke`? – Brett Caswell Nov 09 '19 at 04:53
  • 1
    Absolutely sure. – Sam Nov 10 '19 at 00:58

1 Answers1

1

Invoking ChangePassword, calls IADsUser::ChangePassword. That documentation says it works much the same as IADsUser::SetPassword. That documentation has more information. Really, only the first method would work when you're running this from outside the domain:

First, the LDAP provider attempts to use LDAP over a 128-bit SSL connection. For LDAP SSL to operate successfully, the LDAP server must have the appropriate server authentication certificate installed and the clients running the ADSI code must trust the authority that issued those certificates. Both the server and the client must support 128-bit encryption.

I assume your LDAPString is in the format LDAP://example.com:636 (the :636 being the important part). If you can read data like that, then the SSL certificate is trusted. So that's good.

The only maybe missing piece could be 128-bit encryption? Check the certificate and see if it's maybe using less than 128-bit. Although I'd be surprised if it did.

This answer has a short snippet of code that you can use to download a certificate from any site: https://stackoverflow.com/a/22251597/1202807

Just use "https://example.com:636" as the "website".

There is also this:

In Active Directory, the caller must have the Change Password extended control access right to change the password with this method.

You should make sure that the user account you are authenticating to LDAP with does have the Change Password permission on the account you are trying to update. In our environment, Everyone has the Change Password permission (since you still need to provide the old password to do it). I think that's the default, but it's worth checking.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • Will it make any difference if I use System.DirectoryServices.Protocol instead of System.DirectoryServices? – Sam Nov 13 '19 at 18:41
  • I can't say without knowing what the actual issue is. Using [`LdapConnection`](https://learn.microsoft.com/en-us/dotnet/api/system.directoryservices.protocols.ldapdirectoryidentifier) will be strictly RFC-compliant LDAP. Whereas `DirectoryEntry` is really just a wrapper around the Windows native [`IADs` interfaces](https://learn.microsoft.com/en-us/windows/win32/adsi/using-the-iads-interfaces), which also use LDAP, but make a lot of assumptions specific to Active Directory. – Gabriel Luci Nov 13 '19 at 19:01
  • I think this is a compelling answer to a compelling question; actually, could the service itself deny write operations from non domain machines but allow read operations? – Brett Caswell Nov 15 '19 at 17:12
  • @BrettCaswell You could deny changing the password from outside the network, in a round-about way, by not setting up the SSL certificate for LDAPS. The [other two ways](https://learn.microsoft.com/en-ca/windows/win32/api/iads/nf-iads-iadsuser-setpassword#remarks) for securely transmitting the new password require you to be inside the network. But you can still read data via LDAP without it. – Gabriel Luci Nov 15 '19 at 17:33