I have two functionality which I need to achieve in asp.net web application.
- Authenticate using Active Directory
- Get list of Active Directory users.
Both above work fine on client environment when I set IIS application pool to Network Service. When I change back to IIS user then only authentication works but to get the list of users stops working. I am not sure why it is happening.
Here is my code:
Authentication:
public bool AuthenticateADUser(string domain, string password, string username) { bool isValid = false; using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain)) { isValid = pc.ValidateCredentials(username, password); } return isValid; }
Get the list of Active Directory users:
using (var context = new PrincipalContext(ContextType.Domain, domain)) { if (groupName != string.Empty) { // get list of users for a group GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName); foreach (Principal principal in group.Members) { AdUsers.Add(principal); } } else // get all users regardless of group { using (var searcher = new PrincipalSearcher(new UserPrincipal(context))) { foreach (Principal principal in searcher.FindAll()) { if (principal.UserPrincipalName != null) AdUsers.Add(principal); } } //end PrincipalSearcher using } //end else } //end PrincipalContext using
Updated: I can't say which line of code because I deployed the application to client server, so can't debug it. But here is the error:
Exception information:
Exception type: DirectoryServicesCOMException
Exception message: Logon failure: unknown user name or bad password.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.PropertyValueCollection.PopulateList()
at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
at System.DirectoryServices.PropertyCollection.get_Item(String propertyName)
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInitNoContainer()
at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()
at System.DirectoryServices.AccountManagement.PrincipalContext.get_QueryCtx()
at System.DirectoryServices.AccountManagement.PrincipalSearcher.SetDefaultPageSizeForContext()
at System.DirectoryServices.AccountManagement.PrincipalSearcher..ctor(Principal queryFilter)
at WarshawGroup.OneVoice.User.bus_cUser.GetADUsers(String domain, String groupName)
at WarshawGroup.OneVoice.UI.Data.Users.Modify.Page_Load(Object sender, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Updated:
It throws an exception at
var searcher = new PrincipalSearcher(new UserPrincipal(context));
Context is PrincipalContext type...
var context = new PrincipalContext(ContextType.Domain, domain);
PrincipalContext has property called "ConnectedServer". The value for ConnectedServer is null, so it throws the exception.
If I pass user name and password along with domain in PrincipalContext, everything works.Example...
var context = new PrincipalContext(ContextType.Domain, domain,"username","pwd");
It seems like I need to impersonate the user who has permission to access a particular domain.
Is there any other way I can achieve this?
Thanks,