Problem with C# calling ActiveDirectory's SetPassword function - c#

I create a new user successfully, and then I try to set their initial password using the following code:
newUser.AuthenticationType = AuthenticationTypes.Secure;
newUser.Invoke("SetPassword", new object[] { "somepassword" });
newUser.Properties["LockOutTime"].Value = 0; //unlock account
When it (eventually) returns, I get the following exception
System.IO.FileNotFoundException: The network path was not found
If I inspect the 'newUser' object, it has a Path attribute which looks fine to me.
I don't think my instance of AD is available over SSL though, I can only connect to it over port 389. Is that something to do with it?
Any help appreciated, I'm new to AD and struggling...
Thanks

As suggested here, you might have more success with the new and improved System.DirectoryServices.AccountManagement namespace.
// establish context for local machine
PrincipalContext ctx = new PrincipalContext(ContextType.Machine);
// find the account
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "YourUser");
// set the password to a new value
user.SetPassword("new-top-secret-password");
user.Save();
marc_s provides more detail in the OP.

Related

Connect to Active Directory using LdapConnection class on remote server

I have a problem: I need to connect from a remote server to Active Directory, but the code has to be using the LdapConnection class. I need this because that way I can only test change notifiers when some event happen (such as user is deactivated or he changed group, data etc). OS on the remote server is Windows Server 2012.
I managed to do this from local using DirectoryServices with the following code:
String ldapPath = "LDAP://XRMSERVER02.a24xrmdomain.info";
directoryEntry = new DirectoryEntry(ldapPath, #"A24XRMDOMAIN\username", "pass");
//// Search AD to see if the user already exists.
DirectorySearcher search = new DirectorySearcher(directoryEntry);
search.Filter = "(&(objectClass=user))";
SearchResult result = search.FindOne();
This is okay and connection works but now I need to connect using the LdapConnection class.
I tried something like this on many ways but none of that helped me:
LdapConnection connection = new LdapConnection(XRMSERVER02.a24xrmdomain.info);
var credentials = new NetworkCredential(#"A24XRMDOMAIN\username", "pass");
connection.Credential = credentials;
connection.Bind();
It says that credentials are invalid but that is not true.
Explanations:
XRMSERVER02 - Domain controller
a24xrmdomain.info - Domain
A24XRMDOMAIN - Domain used for logging
Thanks for your help.
Even though I solved my problem I want to share with other developers what I achieved so far. Problem that I encountered was that I had remote server with OS Windows server 2012 and Active directory on it. I needed to connect on him via my local machine(Windows 10).
As I stated in my question it is possible to do that via DirectoryServices with the following code:
String ldapPath = "LDAP://(DomainController).a24xrmdomain.info";
directoryEntry = new DirectoryEntry(ldapPath, #"DOMAIN\username","pass");
//// Test search on AD to see if connection works.
DirectorySearcher search = new DirectorySearcher(directoryEntry);
search.Filter = "(&(objectClass=user))";
SearchResult result = search.FindOne();
This is one of the solutions, but since my task was to get notification and to identify when ever some object has changed in Active Directory, I needed connection to Active Directory on Remote server via LDAP class. Code for getting notifiers is taken from:
- Registering change notification with Active Directory using C#
I succeeded to connect with LDAP class via next code:
String ldapPath2 = "(DomainController).a24xrmdomain.info";
LdapConnection connection = new LdapConnection(ldapPath2);
var credentials = new NetworkCredential(#"username", "pass");
connection.Credential = credentials;
connection.Bind();
Want to mention that no IP address of remote server is needed, just Domain Controller that is used on him, and that Domain used for logging is unnecessary.
Happy coding
Try using NetworkCredential constructor with 3 parameters: username, password and domain. Specify domain separately from user name

Unable to validate credentials using LDAP

I am new to LDAP and wanted to connect to a LDAP server using .Net to validate the user credentials. The following code returns an error:
The LDAP server is unavailable
But the validation works fine in Java code. Kindly let me know where I have gone wrong.
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "LDAP://192.168.65.201:389/DC=be,DC=ndl,DC=CompanyName,DC=com"))
{
bool a= pc.ValidateCredentials("myname#CompanyName.com","password");
}
First of all - PrincipalContext only works against Active Directory, not against any other LDAP server.
Secondly: you're specifying invalid parameters for the constructor. Check out the MSDN docs on what constructors are available for PrincipalContext.
You can define just a ContextType parameter, in which case the PrincipalContext is constructed against the current domain you're connected to:
var ctx = new PrincipalContext(ContextType.Domain);
Or you can use a constructor with a second string parameter which signifies the domain name of your domain (only the domain name - NOT a complete LDAP path!):
var ctx = new PrincipalContext(ContextType.Domain, "CompanyName.com");
Then you're connected to that specific domain, at the root level.
Or thirdly, you can specify a third parameter which defines the container in that domain to connect to:
var ctx = new PrincipalContext(ContextType.Domain, "CompanyName.com",
"CN=Users,DC=be,DC=ndl,DC=CompanyName,DC=com");
So you'll need to find the appropriate constructor and supply the correct parameters to get this to work - if you're using Active Directory.

Need to reset and expire a password in Active Directory within a PrincipalContext

I was trying to use the following code to set an Active Directory's user password:
using (var context = new PrincipalContext( ContextType.Domain ))
{
using (var user = UserPrincipal.FindByIdentity( context, IdentityType.SamAccountName, userName ))
{
user.SetPassword( "newpassword" );
user.ExpirePasswordNow();
}
}
The code pulled the user information with no problem, but I got an Access Denied when trying to reset the password. I then realized that the above code provided no security context within which to do the operation. How to put that in? MSDN gives the full constructor for PrincipalContext as:
public PrincipalContext(
ContextType contextType,
string name,
string container,
string userName,
string password
)
and all the examples I could find made it clear that the first string was the server name, and username and password were clear enough, too, but what was the "container". The description in MSDN was as clear as mud:
"The container on the store to use as the root of the context. All
queries are performed under this root, and all inserts are performed
into this container."
I tried using an arbitrary string like "ABCD" but that was no good. I tried a number of things to no good result.
How to fix this?
Finally dug up an answer in this StackOverflow question:
Active Directory Services: PrincipalContext -- What is the DN of a "container" object?
Leave the thing at null. Wow, what a concept. I tried it and to my great surprise it actually worked. Here's my final working code:
using (var context = new PrincipalContext(ContextType.Domain, "xxxdcoly302.xxx.xx.lcl", null, #"XXX\admin-acct", "Beautifu!"))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, userAccountID))
{
user.SetPassword("Pa$$word1");
user.ExpirePasswordNow();
}
}
Note that I first tried to include "LDAP://" as part of the server name above ("xxxdcoly302.xxx.xx.lcl"). This did not work! It told me "The server could not be contacted." I found another StackOverflow answer that said leave that LDAP prefix off. So I did and it worked.

Cant find users or groups with System.DirectoryServices.AccountManagement

I'm trying to integrate a system with Active Directory using the System.DirectoryServices.AccountManagement stuff. Our IT people have setup an AD box and my dev box is not part of this (or any) domain.
So far, I have 3 lines of code as a test:
var pc = new PrincipalContext(ContextType.Domain, "machine", "CN=Administrator,CN=Users,DC=domain,DC=com", "Password");
var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, "Administrator");
var gp = GroupPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, "Admins");
Creating the PrincipalContext works as listed above, but if I try to use the domain name instead of the server name then I get an error : The server could not be contacted. So, I left this on the machine name.
When getting the user or group, I get an error : A local error has occurred.
For the user, I also tried this with the same result:
var user = UserPrincipal.FindByIdentity(pc, IdentityType.DistinguishedName, "cn=Administrator,ou=users,dc=domain,dc=com");
So, overall, I'm confused :(
Does anyone have any suggestions?
As a side note, I'd like to kick the programmer who thought that 'a local error has occurred' would be a useful error message!
Cheers
PS: I can use the SysInternals AD Explorer just fine from my machine and I can see the dn's I'm trying to use.
PPS: If I use machine.domain.com for the name when creating the PrincipalContext, it also fails to connect.
So this is one of those things that makes perfect sense AFTER you hack through to the solution. The problem was the Context was trying to use a Negotiated security context which is not configured. When I used SimpleBind it works just fine:
var pc = new PrincipalContext(ContextType.Domain, "machine", "DC=domain,DC=com", ContextOptions.SimpleBind, "CN=Administrator,CN=Users,DC=domain,DC=com", "Password");
Cheers
PS: A more useful error message would have saved me a days head scratching!
To do the search using the credentials of the current user, specify the domain as such:
new PrincipalContext(ContextType.Domain, "xyz.mycorp.com:3268", "DC=mycorp,DC=com");
From
When do I need a Domain Name and a Domain Container to create a PrincipalContext?

Active Directory, enumerating user's groups, COM exception

while enumerating current user's groups through AD .NET API I sometimes get
COMException: Unknown error (0x80005000)
Here's my code :
var userName = Environment.UserName;
var context = new PrincipalContext(ContextType.Domain);
var user = UserPrincipal.FindByIdentity(context, userName);
foreach (var userGroup in user.GetGroups())
{
Console.WriteLine(userGroup.Name);
}
What's the problem? I thought every user can retrieve list of HIS groups?It seems to be strange behavior, sometimes It can be reproduced like this : when running on 'userA' PC, It crashes, but it is enumerating OTHER 'userB' groups successfully (under 'userA')!
Try using
var context = new PrincipalContext(ContextType.Domain, "yourcompany.com", "DC=yourcompany,DC=com", ContextOptions.Negotiate);
With the ContextOption set to Negotioate the client is authenticated by using either Kerberos or NTLM so even if the user name and password are not provided the account management API binds to the object by using the security context of the calling thread.
I had the same problem, I solved it by supplying the domain name when creating the PrincipalContext:
var domain = new PrincipalContext(ContextType.Domain, Environment.UserDomainName);
var user = UserPrincipal.FindByIdentity(domain, Environment.UserName);
0x80005000 = E_ADS_BAD_PATHNAME so you supply an invalid adspath somewhere, maybe you must add LDAP:// prefix or opposit are doing this twice? Set a breakpoint and inspect value...
EDIT:
AdsPath should be a value like "LDAP://CN=Administator,CN=Users,DC=contoso,DC=com", you seem to have a misformed path.

Categories

Resources