I hope somebody could help me to solve my problem.
There is some domain, and some shared directory in that domain. User has domain username and password, to get access to that shared directory, but his computer is not in domain most of time. I mean, when he need to connect to that directory he is typing network path (for example "\\fileserver"), than windows asks for username and password, and after writing it he will get the access until restart windows or logout.
So my question is, how can i get domain user name that user uses to connect to network, by using C# code?
I tryed to use CredentialCache.GetCredential, but i think it works only if user connect to shared directory by using NetworkCredentials in C# program. If connection already was before C# program started, it will be empty.
I also tryed Environment.UserName, but since computer is not in domain, it returns only local user name, that different from domain username.
Sorry for my bad english, i hope you could understand my explanation.
Have you took a look at the nugget package CredentialManagement ?
I used it already, but couldn't roam credential saved with enterprise persistence
using CredentialManagement;
using (CredentialSet credentials = new CredentialSet())
{
Debug.Print(credentials.Count.ToString() + " credential(s) found.");
foreach (Credential credential in credentials)
{
Debug.Print(credential.Target); //This is domain/IP of the saved credential.
Debug.Print(credential.Type.ToString());
Debug.Print(credential.Username);
Debug.Print(credential.PersistanceType.ToString());
Debug.Print(credential.Description);
Debug.Print(credential.LastWriteTime.ToString());
}
Debug.Print("End");
}
Related
Ive written a program to manage our Active Directory in c# - windows forms.
I'm stuck at the following point:
For managing the Active Directory and Commiting Changes, you have to run the program as administrator.
I want to include a login button to verify as admin and be able to commit changes without starting the .exe directly as admin.
Something like:
group.Properties["member"].Add(distinguishedName);
group.CommitChanges();
If this is not possible I was thinking it could maybe be possible to restart the program when the user has typed in his credentials and putting in the admin-credentials directly into the username and password field as parameters.
Is that possible? If not, do you have other suggestions?
Your program does not need to run as admin. You just need to connect to Active Directory using credentials that have permissions to update that group. By default, it will use the credentials that the program is running with. So it sounds like whichever credentials you are using to run as admin also has permissions to update that group.
If it helps you, you can use alternate credentials for connecting to AD by using the constructor for DirectoryEntry that accepts credentials. For example:
var group = new DirectoryEntry($"LDAP://{groupDn}", "username", "password");
group.Properties["member"].Add(distinguishedName);
group.CommitChanges();
I want to write a function in a windows service application to remove a given computer name from Active Directory.
The Windows service is running on a machine which is domain-joined to the DC. Currently I have logged in to this machine with domain admin account.
The Windows service is running under the security context of "NT AUTHORITY/SYSTEM" and this should not be changed, as there shouldn't be any user interaction after installing the application, meaning that admin shouldn't enter their credentials in services.
When I run the application with my newly added code to delete the computer account, it doesn't work. However, when I change the logon info on the Windows Service and update that with domain admin credentials, it's able to successfully remove the computer account from AD.
Below is [a shortened version of] the function used to delete computer accounts.
Is there any way I can modify the code to be able to remove Computer Accounts using the same security context (NT AUTHORITY/SYSTEM)?
private void DeleteComputerAccount(string CompName, DirectoryEntry DirEntry)
{
try
{
//Delete computer account
DirectorySearcher search = new DirectorySearcher(DirEntry, "(name=" + CompName + ")");
SearchResult res = search.FindOne();
res.GetDirectoryEntry().DeleteTree();
}
catch (Exception)
{
Throw();
}
}
Where DeleteComputerAccount is called:
DirectoryEntry dirEntry = new DirectoryEntry("LDAP://domain.contoso.com");
string compName = "MyWorkstation01";
DeleteComputerAccount(compName, dirEntry);
When a service runs as local system, it will access the network (and thus AD) in the security context of the host's computer account. You can delegate the computer account (or better, a group which the computer is a member of) the ability to delete objects from AD. This link has accurate advice on how to complete that task - http://sigkillit.com/2013/06/12/delegate-adddelete-computer-objects-in-ad/
While not what you asked, a couple other things stand out to me:
You're not filtering your search very well. You might get something other than what you want back. I'd suggest a filter like this instead: (&(objectClass=computer)(sAMAccountName=<PCName>$))
Local system is a lot of access. Could you run this as network service instead?
Since Microsoft release the two following patches, my C# code just stopped working and always sends back an error message (The system cannot contact a domain controller to service the authentication request. Please try again later.) when trying to change the password.
https://support.microsoft.com/en-us/kb/3167679
https://support.microsoft.com/en-us/kb/3177108
private void ChangePassword(string username, string oldPassword, string newPassword)
{
string machineName = Environment.MachineName;
string contextUser = String.Format(#"{0}\{1}", machineName, username);
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine, machineName, null, ContextOptions.Negotiate, contextUser, oldPassword))
using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username))
{
user.ChangePassword(oldPassword, newPassword);
}
}
If the submitted credential is not valid, i get a specific error message saying bad username or password so the submitted credential is valid.
I tried many scenarios and they all fail:
Use the user/password of the user i want to change its password for the PrincipalContext.
Use a different user/password for the PrincipalContext.
User a local admin user/password for the PrincipalContext.
None works.
Read a lot about this "new behavior" and i can't seem to find a way to change a valid, not locked, not disabled local user.
Those posts are similar to mine and it seems like some people got a workaround but only for Active Directory and not local user accounts.
C# Active Directory Invoke “ChangePassword” cannot contact domain
Changing Active Directory user passwords in c#/asp.net after MS patch KB3167679
c# Change AD password Directoryservices
Can anyone tell me what's wrong with my code and explain me why it broke since the patches please?
If you just want to change the password for a local user you should be able to use NetUserChangePassword.
That still works for me. At least for the local machine (use the name of that as the domain name parameter).
Microsoft has updated this article: https://support.microsoft.com/en-us/kb/3177108 . Here they have given us problems created by the original "fixes" as well as some tips for working with Kerberos and self-service password reset.
As of October 11, 2016 Microsoft re-released the patches associated with https://technet.microsoft.com/en-us/library/security/ms16-101.aspx to resolve issues caused by the original updates (which you can read in https://support.microsoft.com/en-us/kb/3177108 including the fact that you could no longer change passwords on local accounts-- see "known issue #3").
So in short you should be able to change local passwords now with the latest updates (October 11, 2016).
i have active directory configured and i have added two user x and y and my domain is DOMAIN. And i have created an application where i these two can login with their username DOMAIN/X and DOMAIN/Y. But Here's the scenario i will add the intended user details into the database like their username and password and I want to show a login button without username and password fields who were within my LAN and i should be able to get the PC name and then i will verify it across username which i have saved in Db and get the username and password to validate him. So basically is there any way to get the Computer name from where the user tried to access the application within my LAN
you can use this piece of code to get the pc name
System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();
but if you will be saving the name of the pc as just the name it might end up having more then one name of the same.
if its just for each computer you want to register I would suggest going for MAC address
not sure exactly how its done but maybe this link will help you
MAC Address
I've created a small application which attempts to authenticate a user based on their username and password. This application works correctly when run on the same domain which Active Directory resides on.
I must now extend the application to also work on domains which are "closed" in terms of security and permissions. In other words, is there a way to run the application based on an administrator account, or an account which has the necessary permissions to access the Active Directory?
This is the code I have used to authenticate a user:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, server + ":" + port))
{
if (pc.ValidateCredentials(username, password))
{
valid = true;
}
else
{
valid = false;
}
}
The above code works perfectly, however I would like to modify it so that it can communicate with the Active Directory database in an authenticated manner.
I have read numerous documentation and resources, but have not found anything. The closes I found was an article mentioning that IIS has to be set up and configured in a specific manner. However, my application is a simple C# application, and IIS is not being used.
If I understand the question properly, you want to execute ValidateCredentials using a different user than the current process' user.
I may be missing something, but have you tried modifying your code this way?
using (PrincipalContext pc =
new PrincipalContext(ContextType.Domain,
server + ":" + port,
specialAccountUsername,
specialAccountPassword))
{
return pc.ValidateCredentials(username, password);
}
It simply uses a constructor that takes the special account you are using for accessing the domain.