Auth as administrator - c#

I've done an application that basically goes through all active users on a network via DirectoryEntry, where I'm able to get each computers Username (login id), this is done by DE.UserName (DirectoryEntry).
Alright, so far so good, now with my problem; whenever I try to fetch it's password it's throwing an exception saying I need to have admin rights in order to get the password of each connected pc.
I am not the owner of the network, so I'm wondering if there's any way to auth as an admin or change your group to Administrator, or in any way bypass this so I can access it's password?
Code:
DirectoryEntry computers = new DirectoryEntry("WinNT://JBVAS");//The domain
IEnumerator enumerator = computers.Children.GetEnumerator();
while(enumerator.MoveNext())
{
DirectoryEntry entry = enumerator.Current as DirectoryEntry;
Console.WriteLine("Username: {0}{1}Password: {2}",
entry.Username, Environment.NewLine, entry.Password);
}

You could use impersonation to make your code (temporary) run under a higher privileged user.
I wrote an easy-to-use impersonation class some years back, you can find it over at CodeProject.com.
An example could be:
using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
// code that executes under the new context
}
Put your Active Directory code that needs administrator permissions inside the using block.

Related

How to keep my application "authenticated" with an AD account? c#

I am pretty new to C#
I have been using Powershell scripts to code things like Unlocking an AD user or Enabling/Disabling an account. however, I do this with a different account, so I will log in with the admin account (Get-Credential) and storing it as '$cred' for example.
I am currently trying to do a similar thing in C# and I have found how to effectively "Authenticate"
But I am not sure how to store that Authentication, or have my app Authenticated to do things with it like Disable or Unlock an AD Account.
I have this:
public bool ADauthenticate(string username, string password)
{
bool result = false;
using (DirectoryEntry _entry = new DirectoryEntry())
{
_entry.Username = username;
_entry.Password = password;
DirectorySearcher _searcher = new DirectorySearcher(_entry);
_searcher.Filter = "(objectclass=user)";
try
{
SearchResult _sr = _searcher.FindOne();
string _name = _sr.Properties["displayname"][0].ToString();
MessageBox.Show("authenticated!");
result = true;
this.Close();
}
catch
{
MessageBox.Show("Incorrect credentials");
this.ADUsername.Text = "";
this.ADPwd.Text = "";
}
}
return result; //true = user Authenticated.
}
Which just tells me that the account is correct of course, but doesn't keep my application "authenticated", any ideas?
It's not accurate to say that your "application" was authenticated. All that was authenticated is a single network connection to your domain controller. As soon as _entry is destroyed, you lose that authentication.
If you want everything to happen using those credentials, then you have several options, ranging from easy (for you) to more difficult:
Have your users run your application under the credentials they need. Then you don't need to bother getting their username and password or setting the username and password on the DirectoryEntry object. Users can do this by:
Using Shift + right-click on the application icon and click "Run as a different user", or
Create a shortcut to: runas.exe /user:DOMAIN\username "yourapplication.exe". This will open a command window asking for the password, then start your application under those credentials.
You still ask for the username and password, but restart your application under those credentials using Process.Start().
Keep the username and password variables alive for the life of the application and pass them to every DirectoryEntry object you create in your application.
Options 1 and 2 require the computer that you're running this from is joined to the same or trusted domain as the domain you are connecting to. But since I see you're not specifying the domain name, I'm guessing that's the case.
You can do this a lot easier by using the System.DirectoryServices.AccountManagement assembly and namespace.
Add a reference to the System.DirectoryServices.AccountManagement assembly to your project, and then use this code to validate username/password against AD:
using System.DirectoryServices.AccountManagement;
// create the principal context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YourDomain"))
{
bool accountValidated = ctx.ValidateCredentials(userName, password);
// do whatever you want to do with this information
}

Not able to Set Password and Enable Account using C# and admin User

Using WPF & C#, I can set all the attributes in Active Directory, but can't do the following :
1) Can't Set User Password
2) Can't Enable User
However, I can do the same thing manually!
Approach Tried:
1.
DirectoryEntry directoryEntry=
directoryEntry.Invoke("SetPassword", new object[] {myPass#x6712}); // To set password
directoryEntry.Properties["userAcountControl"].Value=0x0200; //To Enable User
2.
DirectoryEntry uEntry = new DirectoryEntry(userDn);
uEntry.Invoke("SetPassword", new object[] { password });
uEntry.Properties["LockOutTime"].Value = 0; //unlock account
3.
using (var context = new PrincipalContext( ContextType.Domain ))
{
using (var user = UserPrincipal.FindByIdentity( context, IdentityType.SamAccountName, userName ))
{
user.SetPassword( "newpassword" );
// or
user.ChangePassword( "oldPassword", "newpassword" );
user.Save();
}
}
ERROR ON PASSWORD SET: Exception has been thrown by the target invocation.
ERROR ON ENABLE USER: Access is denied.
NOTE: I'm using a Domain Admin User.
The program gives the exception in these above lines.
Please, Advice! Thanks in Advance !!
Maybe this is just a mistake in your question, but the code you show in your first example wouldn't compile because the password is not in quotes. It should be:
directoryEntry.Invoke("SetPassword", new object[] {"myPass#x6712"});
That code invokes IADsUser.SetPassword. The 'Remarks' in the documentation point to some prerequisites for it to work, namely, that it must be a secure connection. So it may have failed in setting up a secure connection. It would usually try Kerberos to do that, so something might have gone wrong there.
You can try specifically connecting via LDAPS (LDAP over SSL) by pointing it at port 636 (new DirectoryEntry("LDAP://example.com:636/CN=whatever,DC=example,DC=com")), but that requires that you trust the certificate that is served up. Sometimes it's a self-signed cert, so you would need to add the cert to the trusted certs on whichever computer you run this from.
Or, the account you are running it with does not have the 'Reset Password' permission on the account.
For enabling, the userAccountControl attribute is a bit flag, so you don't want to set it to 2, mostly because 2 (or more accurately, the second bit) means that it's disabled. So you want to unset the second bit. You would do that like this:
directoryEntry.Properties["userAcountControl"].Value =
(int) directoryEntry.Properties["userAcountControl"].Value & ~2;
Most of the time that will result in a value of 512 (NORMAL_ACCOUNT), but not necessarily. The account could have other bits set that you don't want to inadvertently unset.
You also need to call .CommitChanges() for the changes to userAcountControl to take effect:
directoryEntry.CommitChanges();

How to programmatically access this Active Directory as LocalService?

Trying to access the local ActiveDirectory from my Windows Service.
I was going to try using the LocalService to access it, it works when I run it inside Visual Studio as Administrator, but failed when I run it as an actual Service.
Do I need to provide the SecurityIdentifier to DirectoryEntry somehow? But it only takes username and password and not SecurityIdentifier...
var fqhn = System.Net.Dns.GetHostEntry(Environment.MachineName).HostName;
using (DirectoryEntry root = new DirectoryEntry(string.Format("LDAP://{0}/RootDSE", fqhn)))
{
string ctx = root.Properties["configurationNamingContext"].Value.ToString();
string path = string.Format("LDAP://{0}/CN=Microsoft Exchange,CN=Services,{1}",
fqhn, ctx);
var blah = new DirectoryEntry(path);
}
It gives me
System.DirectoryServices.DirectoryServicesCOMException (0x80072030): There is no such object on the server., I've tried running the service in both LocalService or NetworkService.
Actually, it looks like I was using the wrong address to access the ActiveDirectory. On my local machine, I was using:
System.Net.Dns.GetHostEntry(Environment.MachineName).HostName;
But I should be using the domain instead:
Environment.UserDomainName
So I kind of made a fallback approach in case the domain is not there...
string domain = Environment.UserDomainName;
if (String.IsNullOrEmpty(domain))
domain = System.Net.Dns.GetHostEntry(Environment.MachineName).HostName;
Now connecting to the LDAP works:
new DirectoryEntry(string.Format("LDAP://{0}/RootDSE", domain)
And just to confirm what #Harry Johnston said in the other reply, using NetworkService worked! (I reverted back to LocalService just to be sure and it failed on me)

Adding an AD User to a Machine Local group via AccountManagement

I wanted to implement adding an AD user to a local machine group via User and GroupPrincipals, and I thought it would work nice and easy. Unfortunately, I continue to get a General Access Denied error. It's possible I just don't understand the proper authentication happening, but I assumed I had the proper access set up. Here is a code snippet of what is being called:
var ctx = new PrincipalContext(ContextType.Machine,
Environment.MachineName,
ConfigurationManager.AppSettings["MyUser"],
ConfigurationManager.AppSettings["MyPW"]);
var grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, "LocalGrp");
var adUser = ADService.GetUserByDomainUserName(vModel.ContactId);
var adCtx = new PrincipalContext(ContextType.Domain,
"myDomain.com",
ConfigurationManager.AppSettings["MyUser"],
ConfigurationManager.AppSettings["MyPW"])
;
var user = UserPrincipal.FindByIdentity(adCtx,
IdentityType.Guid,
adUser.UserGuid.ToString());
if (grp != null &&
user != null)
{
if(!user.IsMemberOf(grp))
{
grp.Members.Add(user);
grp.Save();
}
}
The user is found, the group is found, but when I add and reach the grp.Save() step, I am treated with a General Access Denied exception. with the ctx being opened via the "MyUser" and "MyPW", I thought that would allow group manipulation on the machine since that account is part of the machine local administrators group. Can I not mix machine/domain contexts in this manner, or is there an authentication problem I am just missing?
Did you run Visual Studio in Admin mode. Even though your login has admin rights, your program needs to elevate itself to use those rights if you didn't start it elevated.
See:
http://chrisforbesblogs.net/2010/02/26/run-visual-studio-2010-as-administrator-by-default/
Relevant Google search

Get groups from Active Directory using C#

I am having issues getting the groups from Active Directory via System.DirectoryServices
Originally I started my application on a computer that was registered on the domain, but as it was a live domain I did not want to do any writes to AD what so ever, so I set up a machine with Windows XP as the host operating system, and installed windows server 2003 on a VM.
I've added another Ethernet port in the machine and set up a switch, the 1 Ethernet port is dedicated to the VM and the other port is used for the host.
After configuring the IP addresses to get them communicating I transferred my application onto the host machine and fired it up, but I was getting an DirectoryServicesCOMException.
With the message that the user name and password was invalid :( just to check that it was not active directory I created a 3rd virtual machine and installed Windows XP, which i added to the domain with the credentials tested in the APP, works a treat.
So I thought it must be because the machine where the application is running is not part of the domain.
Heres the block of code that was causing the issue:
public CredentialValidation(String Domain, String Username, String Password, Boolean Secure)
{
//Validate the Domain!
try
{
PrincipalContext Context = new PrincipalContext(ContextType.Domain, Domain); //Throws Exception
_IsValidDomain = true;
//Test the user login
_IsValidLogin = Context.ValidateCredentials(Username, Password);
//Check the Group Admin is within this user
//******HERE
var Results = UserPrincipal.FindByIdentity(Context, Username).GetGroups(Context);
foreach(Principal Result in Results)
{
if (Result.SamAccountName == "Domain Admins")
{
_IsAdminGroup = true;
break;
}
}
Results.Dispose();
Context.Dispose();
}
catch (PrincipalServerDownException)
{
_IsValidDomain = false;
}
}
The information in the login dialogue is being entered like so:
Domain: test.internal
Username: testaccount
Password: Password01
Hope someone can shed some light in this error.
Update:
After checking the Security Logs on the server i can see that my log in attempts was successful, but this is down to:
_IsValidLogin = Context.ValidateCredentials(Username, Password);
The line after where im checking the groups is causing the error, so the main issue is that the lines of code below are not working correctly from a machine thats not joined to the network:
var Results = UserPrincipal.FindByIdentity(Context, Username).GetGroups(Context);
According to your code snippet, you're failing when you attempt to create the PrincipalContext, before calling ValidateCredentials. At that point the thread running your code is still working under either a local identity (if you're in a web process) or the identity you signed onto your machine with (for a windows process). Either of these won't exist on the test.internal domain.
You might want to try the overload of PrincipalContext that includes the username and password in the constructor. See http://msdn.microsoft.com/en-us/library/bb341016.aspx
I used to do quite a bit of user management via C# .NET. I just dug up some methods you can try.
The following two methods will get a DirectoryEntry object for a given SAM account name. It takes a DirectoryEntry that is the root of the OU you want to start searching for the account at.
The other will give you a list of distinguished names of the groups the user is a member of. You can then use those DN's to search AD and get a DirectoryEntry object.
public List<string> GetMemberOf(DirectoryEntry de)
{
List<string> memberof = new List<string>();
foreach (object oMember in de.Properties["memberOf"])
{
memberof.Add(oMember.ToString());
}
return memberof;
}
public DirectoryEntry GetObjectBySAM(string sam, DirectoryEntry root)
{
using (DirectorySearcher searcher = new DirectorySearcher(root, string.Format("(sAMAccountName={0})", sam)))
{
SearchResult sr = searcher.FindOne();
if (!(sr == null)) return sr.GetDirectoryEntry();
else
return null;
}
}

Categories