Due to our clients authentication and network topology we have a number of Windows Servers in a DMZ without Active Directory or a Domain Controller. Corporate policy stipulates that passwords must change once a month. Our dev machines are in AD (not in the DMZ) so we run into the situation that we have to synchronise our usernames and passwords on each of the DMZ machines with our AD credentials every month. There are a lot of DMZ machines.
I want to use a simple console app to change the user passwords on all the DMZ machines for a given user. So far, I have the following code:
using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
class Program{
static void Main(){
List<string> remoteHosts = new List<string> { "RemoteHostA", "RemoteHostB", "RemoteHostC" };
remoteHosts.ForEach(host => ChangePassword(host, "username", "oldPassword", "newPassword"));
}
static void ChangePassword(string host, string username, string oldPassword, string newPassword){
using (var context = new PrincipalContext(ContextType.Machine, host, username, newPassword))
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username))
user.ChangePassword(oldPassword, newPassword);
}
}
The problem is that this only works if the password has not already changed on the dev machine where it is being run from. Because the context that is used, first has to authenticate with the dev machine in order to gain access to the network, then it has to gain access to the remote (DMZ) machine using the same context before changing the password.
How can I alter the method to use a new-password-context to gain access to the network and an old-password-context to gain access to the remote host?
Note to Title Editors: The code depends on System.DirectoryServices.AccountManagement which is an FX 3.5 assembly not 3.0.
Can you use WMI directly to achieve this? A quick search showed up this page
Note : It is a long time since I did anything with WMI, but I do remember being able to call it from a C# app, if that's how you are comfortable using it. (Check in System.Management)
Related
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?
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");
}
Background
We are transitioning to Claims-Based auth in our app (on .NET 4.5)
We currently have authentication via Asp.net membership & domain auth working correctly.
The domain portion looks like this (generalized a little):
var context = new PrincipalContext(ContextType.Domain, ADDomainName);
return context.ValidateCredentials(username, password);
Problem / Goal
Sometimes we (or some consultants we use) are on a VPN connection using machines that can see our domain servers, but that aren't members of our domain.
It would be a great help to test the app from a machine that isn't on the domain, rather than having to fire up a machine that is on the domain in order to check.
Question
Is there a way to perform domain authentication against a domain controller from a machine that isn't on the domain? I haven't been able to find any research on it thus far.
You can use LDAP authentication and specify credentials from your code:
using(var context = new PrincipalContext(ContextType.Domain, "mydomain", #"mydomain\serviceAcct", "serviceAcctPass"))
{
//Username and password for authentication.
return context.ValidateCredentials(username, password);
}
Or, run your authenticating server under runas /netonly, which lets you run with domain network credentials from a workgroup joined computer
rem if your server is standalone
runas /netonly /user:mydomain\consultantaccount C:\dev\sts\ipsts.exe
rem or you can have it in IIS Express:
runas /netonly /user:mydomain\consultantaccount "iisexpress /path:c:\dev\sts\ /port:9090 /clr:v2.0"
I will note that I have not actually checked whether /netonly will work in this context, so if you end up trying it, I'd be interested to hear if it worked.
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.
I am using the solution discussed here to authenticate users against the active directory in my ASP.NET web application. I've written a simple ADMembershipProvider class thas is used together with FormsAuthentication. Works fine when running the project locally but when deployed to a server in the network, the ValidateUser call takes really long time (approx 20s).
//Assumes using System.DirectoryServices.AccountManagement
public override bool ValidateUser(string username, string password) {
using (var context = new PrincipalContext(ContextType.Domain)) {
return context.ValidateCredentials(username, password);
}
}
I tried to add name and container parameters as documented on msdn to the PrincipalContext constructor, but these parameters doesn't seem to have any effect whatsoever.
using (var context = new PrincipalContext(ContextType.Domain, "MyDomain", "OU=MyCompany,DC=some,DC=stuff")) {
return context.ValidateCredentials(username, password);
}
We have the same problem on at least two different servers in our network. The servers are connected to the AD and running OS Windows server 2003 SP2 (IIS6)
One idea I had was that the issue might be connected to the fact that our domain has some trusts to other domains, and that they are somehow involved when validating the user. However, the users we are trying to validate exists exclusively in "our" AD.
Hit this issue and had to use ValidateCredentials(string, string, ContextOptions) method to pass in proper enum combination to access our ActiveDirectory connection in our environment.