--
My question relates to searching for well-known security principals from a C# program running as a
local user. I can’t seem to make it work.
Here is my code:
DirectoryEntry root = new DirectoryEntry("LDAP://cn=wellknown security principals,cn=configuration,dc=demoDomain,dc=loc", "domainUser", "HIDDEN");
DirectorySearcher searcher = new DirectorySearcher(root);
// Performing the search
SearchResultCollection results = searcher.FindAll();
IT works fine when running as a domain user but when running as a local user (and connecting to the domain using user a domainUser)
I get this COM exception when trying FindAll(): “The specified domain either does not exist or could not be contacted” -2147023541 (8007054B).
Related
Using these 2 examples:
http://blogs.technet.com/b/brad_rutkowski/archive/2008/04/15/c-getting-members-of-a-group-the-easy-way-with-net-3-5-discussion-groups-nested-recursive-security-groups-etc.aspx
or
Get members of Active Directory Group and check if they are enabled or disabled
I was able to get users from "Domain Users" when running the them on the Domain controller.
However, I was not able to on member machine that belong to the same domain.
I even logon to the member machine as the Domain Administrator
The errors messages:
Example 1
Unhandled Exception: System.Runtime.InteropServices.COMException: The specified domain either does not exist or could not be contacted.
Example 2
Unhandled Exception: System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. ---> System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
Can somebody please point me to an example or how to fix this problem ?
Thanks.
Accounts that are local to a workstation or server are not Active Directory accounts, even if the machine is itself a member of an Active Directory domain. Active Directory APIs generally use LDAP to connect to a domain controller (DC), which will not work for local accounts since there is no DC involved.
Assuming you are working with local users and groups, you can still use the System.DirectoryServices.AccountManagement API to get local users and groups. The DirectoryContext class provides a ContextType property, which you will set to Machine to access local users and groups.
The below code is a simple example that will list all the users on the provided workstation:
string workstationName = null; // null --> localhost
PrincipalContext cxt = new PrincipalContext(ContextType.Machine, workstationName);
foreach (var u in new PrincipalSearcher(new UserPrincipal(cxt)).FindAll())
{
var userPrincipal = u as UserPrincipal;
Console.WriteLine(u.Name);
}
I'm trying to determine the last domain connection made by a user from a remote machine, regardless of if the machine is currently connected to the domain or not.
The closest I can get is using the System.DirectoryServices.ActiveDirectory and System.DirectoryServices.AccountManagement namespaces that do something similar to this:
Domain d = Domain.GetComputerDomain();
PrincipalContext c = new PrincipalContext(ContextType.Domain, d.Name);
UserPrincipal uc = UserPrincipal.FindByIdentity(c, "johndoe");
And then using the LastLogon property of the UserPrincipal.
This works fine, as long as the machine my application is running on is connected to the domain. If it isn't, Domain.GetComputerDomain() returns null, and I'm out of luck (even if I hardcode the domain name to the PrincipalContext constructor, it throws an exception when not connected to the domain). Is there some other AD property or registry key that gets stored locally on the remote machine when it makes an AD connection to the server that I could use?
The following link describing the LSA Cache seems promising, but, to my knowledge, there is nothing regarding domain connection timestamps that gets cached.
Determine User Active Directory Groups from Local Machine off Network
I have an intranet ASP.NET MVC3 web application that is using Windows authentication with .NET Framework 4. All my code is working as far as authenticating the users. I am using Windows Authentication for the baseline authentication, and then link the Active Directory user to a user in a table in SQL Server 2008 for additional user properties specific to my application. All of that is working fine.
There is a section of the site where admins can select Active Directory users to add to the SQL user table (see above) and put in their site specific properties (IsAdmin, ShoeSize, etc.). On this screen, there is a drop down list that I populate to retrieve all Active Directory from a custom object I created that just holds the username and full name properties of the Active Directory user. Here is this code for that:
public IQueryable<ActiveDirectoryUser> ActiveDirectoryUsers
{
get
{
// get list of users in the Active Directory
DirectoryEntry dirEntry = new DirectoryEntry("WinNT://" + Environment.UserDomainName);
List<DirectoryEntry> activeDirectoryUsers = dirEntry.Children.Cast<DirectoryEntry>()
.Where(c => c.SchemaClassName == "User").ToList();
// populate a custom class I have to hold the active directory user's username and full name property values
return activeDirectoryUsers
.Where(u => !string.IsNullOrEmpty(u.Properties["FullName"].Value.ToString()))
.Select(u => new ActiveDirectoryUser()
{
NetworkId = String.Format(#"{0}\{1}", Environment.UserDomainName, u.Properties["Name"].Value),
FullName = u.Properties["FullName"].Value.ToString()
}).AsQueryable();
}
}
For some reason, this code returns no results when the web application is deployed to IIS 7. However, this works perfectly when running the site from IIS Express in Visual Studio. Any ideas of why this would be happening? I have been looking for IIS settings as the culprit, but have not found anything helpful. Do I need to change the way I am retrieving the Active Directory users? Thank you!
This issue ended up being a combination of Eric J. answer, and a change to my code for getting the Active Directory entries. I found that the DirectoryEntry method can be overloaded to take a username and password to use for the permissions (e.g. you don't have to rely on whatever account IIS is running under. Here is the code:
List<SearchResult> searchResults;
// use login account to access active directory (otherwise it will use the IIS user account, which does not have permissions)
using (DirectoryEntry root = new DirectoryEntry("LDAP://CN=Users,DC=test,DC=example,DC=com", "usernameCredential", "passwordCredential"))
using (DirectorySearcher searcher = new DirectorySearcher(root, "(&(objectCategory=person)(objectClass=user))"))
using (SearchResultCollection results = searcher.FindAll())
{
searchResults = results.Cast<SearchResult>().ToList();
}
// get the active directory users name and username
return searchResults
.Select(u => new ActiveDirectoryUser()
{
NetworkId = String.Format(#"{0}\{1}", this._domainName, u.Properties["sAMAccountName"][0]),
FullName = (string) u.Properties["cn"][0]
}).AsQueryable();
This allowed me to get the Active Directory entries, but only those are Users and person objects. Then I used LINQ to map it to my custom model.
When running in IIS Express under Visual Studio you have a much higher permission set than running in the default security context of IIS 7.
You will have to understand exactly which permissions are needed to query Active Directory in this way and ensure that the application pool your app runs in under IIS 7 has that right. Be careful to grant only the permissions needed for this operation, and make sure you review the implications of granting those rights carefully before proceeding.
How can I get a list of all windows users of the local machine with the usage of .NET (C#) ?
Here is a blog post (with code) that explains how to do it:
http://csharptuning.blogspot.com/2007/09/how-to-get-list-of-windows-user-in-c.html
The author lists the following code (quoted from the above site):
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName);
DirectoryEntry admGroup = localMachine.Children.Find("users","group");
object members = admGroup.Invoke("members", null);
foreach (object groupMember in (IEnumerable)members)
{
DirectoryEntry member = new DirectoryEntry(groupMember);
lstUsers.Items.Add(member.Name);
}
You need to add using System.DirectoryServices at the top of your code. To change machines, you would change the Environment.MachineName to be whatever machine you want to access (as long as you have permission to do so and the firewall isn't blocking you from doing so). I also modified the author's code to look at the users group instead of the administrators group.
It depends on what you are really 'after'... if you are on a windows domain (using active directory) then you can query Active Directory IF active directory is being used to limit the users who are "authorized" to use the local machine.
If your requirements are not as stringent then you can inspect the folders in the system UserProfiles where each folder except Default User and All Users represent a user profile that has logged into the local machine. caution this may include system and/or service accounts...
I'm attempting to determine whether a user is a member of a given group using System.DirectoryServices.AccountManagment.
I'm doing this inside a SharePoint WebPart in SharePoint 2007 on a 64-bit system.
Project targets .NET 3.5
Impersonation is enabled in the web.config.
The IIS Site in question is using an IIS App Pool with a domain user configured as the identity.
I am able to instantiate a PrincipalContext as such:
PrincipalContext pc = new PrincipalContext(ContextType.Domain)
Next, I try to grab a principal:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
{
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, "MYDOMAIN\somegroup");
// snip: exception thrown by line above.
}
Both the above and UserPrincipal.FindByIdentity with a user SAM throw a DirectoryServicesCOMException: "Logon failure: Unknown user name or bad password"
I've tried passing in a complete SAMAccountName to either FindByIdentity (in the form of MYDOMAIN\username) or just the username with no change in behavior. I've tried executing the code with other credentials using both the HostingEnvironment.Impersonate and SPSecurity.RunWithElevatedPrivileges approaches and also experience the same result.
I've also tried instantiating my context with the domain name in place:
Principal Context pc = new PrincipalContext(ContextType.Domain, "MYDOMAIN");
This throws a PrincipalServerDownException: "The server could not be contacted."
I'm working on a reasonably hardened server. I did not lock the system down so I am unsure exactly what has been done to it. If there are credentials I need to allocate to my pool identity's user or in the domain security policy in order for these to work, I can configure the domain accordingly. Are there any settings that would be preventing my code from running? Am I missing something in the code itself? Is this just not possible in a SharePoint web?
EDIT:
Given further testing, my code functions correctly when tested in a Console application targeting .NET 4.0. I targeted a different framework because I didn't have AccountManagement available to me in the console app when targeting .NET 3.5 for some reason.
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
using (UserPrincipal adUser = UserPrincipal.FindByIdentity(pc, "MYDOMAIN\joe.user"))
using (GroupPrincipal adGroup = GroupPrincipal.FindByIdentity(pc, "MYDOMAIN\user group"))
{
if (adUser.IsMemberOf(adGroup))
{
Console.WriteLine("User is a member!");
}
else
{
Console.WriteLine("User is NOT a member.");
}
}
What varies in my SharePoint environment that might prohibit this function from executing?
I added the account used by the IIS Application Pool to the Administrators group and this issue was resolved.