I have a PrincipalContext that uses SSL. This works fine when using a method like Context.ValidateCredentials(). But when I need to find a user using UserPrincipal.FindByIdentity() I get the following error:
System.Runtime.InteropServices.COMException: The server is unwilling to process the request.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_SchemaEntry()
at System.DirectoryServices.AccountManagement.ADStoreCtx.IsContainer(DirectoryEntry de)
at System.DirectoryServices.AccountManagement.ADStoreCtx..ctor(DirectoryEntry ctxBase, Boolean ownCtxBase, String username, String password, ContextOptions options)
at System.DirectoryServices.AccountManagement.PrincipalContext.CreateContextFromDirectoryEntry(DirectoryEntry entry)
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()
--- End of inner exception stack trace ---
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()
at System.DirectoryServices.AccountManagement.PrincipalContext.get_QueryCtx()
at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate)
at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, String identityValue)
at System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, String identityValue)
My method:
public List<string> GetUserInfo(string user) {
var list = new List<string>();
using (var context = new PrincipalContext(ContextType.Domain, "xxxx.xxxx.xxxx:636", "DC=xxxx,DC=xxxx,DC=xxxx", ContextOptions.SimpleBind | ContextOptions.Sealing | ContextOptions.SecureSocketLayer)) {
var uP = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, user);
//Do stuff with uP
return list;
}
But this is working fine:
public bool ValidateCredentials(string username, string password) {
using (var context = new PrincipalContext(ContextType.Domain, "xxxx.xxxx.xxxx:636", "DC=xxxx,DC=xxxx,DC=xxxx", ContextOptions.SimpleBind | ContextOptions.Sealing | ContextOptions.SecureSocketLayer)) {
return context.ValidateCredentials(username, password);
}
}
How come I cant work with UserPrincipal using the Context with SSL? If I remove SSL it works fine..
I changed my ContextOptions to Negotiate and SSL. Then it worked
Unfortunately there are not enough code examples that show how to configure PrincipalContext or DirectoryEntry to use LDAPS (SSL Active Directory). I have found these solutions for this issue:
Configure PrincipalContext to use LDAPS:
var path = "test.domainName.local:636";
ContextOptions options = ContextOptions.Negotiate | ContextOptions.SecureSocketLayer;
using (var context = new PrincipalContext(ContextType.Domain, path, "DC=xyz,DC=local", options))
{
pr("Name: " + context.Name);
pr("ConnectedServer: " + context.ConnectedServer);
pr("Container: " + context.Container);
pr("UserName: " + context.UserName);
}
Configure DirectoryEntry to use LDAPS:
string path = "LDAP://test.domainName.local:636";
var dic = new DirectoryEntry(path);
pr("Name: " + dic.Name);
pr("Path: " + dic.Path);
pr("AuthenticationType: " + dic.AuthenticationType);
pr("SchemaClassName: " + dic.SchemaClassName);
pr("Username: " + dic.Username);
Related
I am trying to connect to another domain using from my C# code but I get an error.
Here is my code:
doLog("Going For establishing Connection");
var username = "cn=Directory Manager";
var password = "somepassword";
using (var context = new PrincipalContext(ContextType.Domain, "LDAP://10.10.10.132:2232", username, password))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
doLog("In the principal searcher");
foreach (var result in searcher.FindAll())
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
doLog("Looping result:" + de.Properties["givenName"].Value);
Console.WriteLine("First Name: " + de.Properties["givenName"].Value);
}
}
}
It is working in java but from .net it always throw an error on this line
using (var context = new PrincipalContext(ContextType.Domain, "LDAP://10.10.10.132:2232", username, password))
This is the error I get:
I am using DirectorySearcher to get AD groups from LDAP. The below code works when I fetch the property "cn" from DirectoryEntry and it throws an exception when "sAMAccountName" is selected. The property does exist as you can see that I search based on sAMAccountName.
Exception is
"Exception Details: System.Runtime.InteropServices.COMException:
Unknown error (0x8000500c)"
[COMException (0x8000500c): Unknown error (0x8000500c)]
System.DirectoryServices.PropertyValueCollection.PopulateList()
+519959 System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry
entry, String propertyName) +119
System.DirectoryServices.PropertyCollection.get_Item(String
propertyName) +162
ASP._Page_app_tools_active_directory_cshtml.SearchADGroups(List1 Fields, String DomainName) in d:\inetpub\wwwroot\app\tools\active_directory.cshtml:371 ASP._Page_app_tools_active_directory_cshtml.Execute() in d:\inetpub\wwwroot\app\tools\active_directory.cshtml:154 System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +252 System.Web.WebPages.WebPage.ExecutePageHierarchy(IEnumerable1
executors) +99 System.Web.WebPages.WebPage.ExecutePageHierarchy()
+182 System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext
pageContext, TextWriter writer, WebPageRenderingBase startPage) +107
System.Web.WebPages.WebPageHttpHandler.ProcessRequestInternal(HttpContextBase
httpContext) +142
List<ADGroup> Groups = new List<ADGroup>();
using (DirectoryEntry dEntry = new DirectoryEntry("LDAP://" + DomainName))
{
using (DirectorySearcher gSearch = new DirectorySearcher())
{
gSearch.SearchRoot = dEntry;
if(GroupName != "")
{
gSearch.Filter = String.Format("(&(objectClass=group)(samaccountname=*{0}*))", GroupName);
gSearch.SearchScope = SearchScope.Subtree;
gSearch.PropertiesToLoad.Add("sAMAccountName");
SearchResultCollection group_results = gSearch.FindAll();
foreach (SearchResult group_result in group_results)
{
if(group_result != null)
{
DirectoryEntry group_entry = group_result.GetDirectoryEntry();
group_entry.Properties["cn"].Value.ToString()
group_entry.Properties["sAMAccountName"].Value.ToString()
}
}
}
}
}
I expect the value for sAMAccountName
I am trying to connect to the online test LDAP server specified here using System.DirectoryServices.AccountManagement like this:
try
{
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "ldap.forumsys.com:389", "dc=example,dc=com", "cn=read-only-admin,dc=example,dc=com", "password"))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(ctx )))
{
foreach (var result in searcher.FindAll().Take(usersCount))
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
}
}
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
But it throws the following exception:
Object reference not set to an instance of an object.
Could you please tell what is wrong with my code and how to be able to connect to that LDAP server?
PS: I am able to connect to that server using Apache Directory Studio
Stack Trace :
at System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)
at System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval()
at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, ContextOptions options, String userName, String password)
at System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, String userName, String password)
at ConsoleApp1.Program.GetGroups(String userName) in C:\Users\Simple Code\source\repos\ConsoleApp1\ConsoleApp1\Program.cs:line 48
As said here, the problem could be that you try to connect to an Apache Directory Studio with the class PrincipalContext that not supports this OpenLDAP,
so one way to go is using the DirectoryEntry class
Using DirectoryEntry it works for me as following:
using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://ldap.forumsys.com:389/dc=example,dc=com", "", "", AuthenticationTypes.None)))
{
searcher.Filter = "((objectClass=person))";
searcher.PropertiesToLoad.Add("mail");//email
searcher.PropertiesToLoad.Add("givenName");//first name
searcher.PropertiesToLoad.Add("sn"); //last name
searcher.PropertiesToLoad.Add("telephoneNumber");
searcher.PropertiesToLoad.Add("description");
searcher.PropertiesToLoad.Add("memberOf"); // groups
var activeDirectoryStaffs = searcher.FindAll();
if (activeDirectoryStaffs != null)
{
for (int i = 0; i < activeDirectoryStaffs.Count; i++)
{
SearchResult result = activeDirectoryStaffs[i];
var Email = result.Properties.Contains("mail") ? (string)result.Properties["mail"][0]:null;
var Mobile = result.Properties.Contains("telephoneNumber") ? (string)result.Properties["telephoneNumber"][0] : null;
var FirstName = result.Properties.Contains("givenName") ? (string)result.Properties["givenName"][0] : null;
var LastName = result.Properties.Contains("sn") ? (string)result.Properties["sn"][0] : null;
var Description = result.Properties.Contains("description") ? (string)result.Properties["description"][0] : null;
}
}
}
I have the following code which is called inside of an ASP.NET application:
public DomainUserInfo GetDomainUserInfoByName(string domain, string firstName, string lastName)
{
string[] domainArray = domain.Split(',');
foreach (string d in domainArray)
{
var principalContext = new PrincipalContext(ContextType.Domain, d);
var userPrincipal = new UserPrincipal(principalContext) {GivenName = firstName, Surname = lastName};
using (var searcher = new PrincipalSearcher(userPrincipal))
{
userPrincipal = (UserPrincipal) searcher.FindOne();
}
if (userPrincipal != null)
{
var domainUserInfo = new DomainUserInfo
{
FirstName = userPrincipal.GivenName,
LastName = userPrincipal.Surname,
Email = userPrincipal.EmailAddress,
LanID = userPrincipal.SamAccountName,
Extension = userPrincipal.VoiceTelephoneNumber,
DomainName = d,
NTAccountName = userPrincipal.Sid.Translate(typeof (NTAccount)).ToString()
};
return domainUserInfo;
}
}
return null;
}
It works when deployed on some servers but not on others, where it throws the exception:
[COMException (0x80005000): Unknown error (0x80005000)]
System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) +386081
System.DirectoryServices.DirectoryEntry.Bind() +36
System.DirectoryServices.DirectoryEntry.get_AdsObject() +31
System.DirectoryServices.PropertyValueCollection.PopulateList() +21
System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName) +49
System.DirectoryServices.PropertyCollection.get_Item(String propertyName) +135
System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInitNoContainer() +288
System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit() +37
System.DirectoryServices.AccountManagement.PrincipalContext.Initialize() +118
System.DirectoryServices.AccountManagement.PrincipalContext.ContextForType(Type t) +34
System.DirectoryServices.AccountManagement.Principal.GetStoreCtxToUse() +37
System.DirectoryServices.AccountManagement.UserPrincipal.set_GivenName(String value) +17
Mfc.Inv.RM.Framework.ActiveDirectory.ActiveDirectoryManager.GetDomainUserInfoByName(String domain, String firstName, String lastName) +167
It looks like this is occurring on the line:
var userPrincipal = new UserPrincipal(principalContext) {GivenName = firstName, Surname = lastName};
when trying to set the GivenName property of the UserPrincipal object.
I'm totally stuck as to what could be causing this, especially since it works on some servers and not others. I already tried writing a console application that calls the same code it works on all of the servers, so I am guessing it has to be something to do with IIS.
here is what I am doing and if you were to hover over userFind or do a QuickWatch on it you will see the following information. also notice the IdentityType.SamAccountName that I am passing
var pc = new PrincipalContext(ContextType.Domain, domainName, null, null);
var userFind = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, username);
I am trying to create a new AD-User with this code:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "Domain", "ou=some_ou, dc=Mydomain");
UserPrincipal user = new UserPrincipal(ctx, account, passwd, true);
user.GivenName = Givenname;
user.Surname = Surname;
user.DisplayName = Displayname;
user.UserPrincipalName = account + "#Domain";
user.Save();
The User is created without error. But I also have to set properties like Address etc, so the code continues with:
string distname = user.DistinguishedName;
DirectoryEntry duser = new DirectoryEntry(distname);
try
{
duser.Properties["company"].Value = "Company";
}
catch (Exception e)
{
}
Now I am getting
Error: System.Exception._COMPlusExceptionCode -532459699
The string distname shows the correct distinguished name.
I am not 100% sure what is causing your problem but one thing that may make things easier on you and may clear up some errors due to you improperly using both DirectoryServices and DirectoryServices.AccountManagement at the same time is creating a new class that includes the company attribute.
Its actually not that hard to do.
[DirectoryObjectClass("user")]
[DirectoryRdnPrefix("CN")]
public class UserPrincipalEx : UserPrincipal
{
public UserPrincipalEx(PrincipalContext context) : base(context) { }
public UserPrincipalEx(PrincipalContext context, string samAccountName, string password, bool enabled)
: base(context, samAccountName, password, enabled)
{
}
[DirectoryProperty("company")]
public string Company
{
get
{
if (ExtensionGet("company").Length != 1)
return null;
return (string)ExtensionGet("company")[0];
}
set { this.ExtensionSet("company", value); }
}
}
You can then just modify your code to
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "Domain", "ou=some_ou, dc=Mydomain");
UserPrincipalEx user = new UserPrincipalEx(ctx, account, passwd, true);
user.GivenName = Givenname;
user.Surname = Surname;
user.DisplayName = Displayname;
user.UserPrincipalName = account + "#Domain";
user.Company = "Company";
user.Save();
My hunch is you are having some kind of interaction with the two methods of interfacing with active directory, if you switch to a single interface your problem may just go away.
For DirectoryEntry, you have to specify the protocol (LDAP, GC, WinNT, ...). So you would have to do:
DirectoryEntry duser = new DirectoryEntry("LDAP://" + distname);
Note that the protocol is case sensitive, LDAP has to be all caps.
I see you are using credentials in the UserPrincipal,
Did you forgot to use them when creating your DirectoryEntry?
Also, you need to add "LDAP://" before you server name
Try something like :
DirectoryEntry duser = new DirectoryEntry("LDAP://" + distname);
duser.Username = account;
duser.Password = passwd;
duser.AuthenticationType = AuthenticationTypes.Secure;