I have a virtual machine with Active Directory that I want to connect to using .NET, I've already connected to an ubuntu machine running OpenLDAP but when connecting to AD it's not working smoothly.
The code I'm attempting to connect with is as follows:
var directoryEntry =
new DirectoryEntry("LDAP://192.168.1.1", #"EXAMPLE\Administrator", "Abc1234");
try
{
var test = directoryEntry.NativeObject;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
Watching the locals window the variable directoryEntry's Guid, name etc says "Function evaluation timed out".
Then when it arrives at the try block it simply says "The server is not operational".
I've also tried this code, and it fails at the "ldap.bind" telling me that "the ldap-server is unavailable".
using (var ldap = new LdapConnection("192.168.1.1:389"))
{
ldap.AuthType = AuthType.Basic;
ldap.SessionOptions.ProtocolVersion = 3;
ldap.Bind(new NetworkCredential(#"EXAMPLE\Administrator", "Abc1234"));
}
I know the server is up and running, I know that they have a connection (machines can ping each other) but I can't figure out why it isn't working. Can any of you see if there are any flaws in the code? (and yes I've googled all of the errors and various questions about connecting to AD before asking this question but none of the solutions have worked).
If you domain name is 'example.com' and let say you have an organization unit (OU) called 'users'. This works perfectly fine for me.
However the machine where this code runs, is added to the AD domain and it runs with an AD user account. If you do not have a machine added to the same domain which you are querying, you may try "Run as" option (Shift + Right Click) to launch the program or visual studio.
public static List<string> GetAllUsers()
{
List<string> users = new List<string>();
using (DirectoryEntry de = new DirectoryEntry("LDAP://OU=Users,DC=example,DC=local"))
{
using (DirectorySearcher ds = new DirectorySearcher(de))
{
ds.Filter = "objectClass=user";
SearchResultCollection src = ds.FindAll();
foreach (SearchResult sr in src)
{
using (DirectoryEntry user = new DirectoryEntry(sr.Path))
{
users.Add(new string(user.Properties["sAMAccountName"][0].ToString()));
}
}
}
}
return users;
}
I tested your code (with changed domain / password...) in my own Active Directory test environment, it works. If I use a wrong password intentionally for testing purpose, I get "invalid credentials". Fine.
"The server is not operational" will be returned if LDAP is completely unavailable. So it seems that e.g. port 389 is not reachable.
Firewall ?
LDAP SSL (port 636) ??
If you do not have a machine added to the same domain which you are querying, you may try "Run as" option (Shift + Right Click) to launch the program or visual studio.
Yes, this was my first idea too as I saw this question. However, it seems that you will get another error in this case.
What I suggest: install WireShark, the network analyzer and check what is sent over the wire (assuming your AD is running on another machine).
WireShark helped me more than often to diagnose errors with AD, login, SMB or other protocols.
PS:
The answer from Ravi M Patel is a nice example of searching, I almost do the same in my own code.
Problem solved. I had two network adapters and adapter 1 had dhcp and the static ip I was attempting to connect was running on adapter 2. I simply gave adapter 1 the static adress and was able to connect that way, seemingly the code connects via adapter 1 per default. And Thanks for all the answers guys :)
Related
I have a client which uses Okta LDAP Interface facility. We have a LDAP v3 tool which connects with AD, Open LDAP other LDAP v3 supported servers.
We want to integrate Okta LDAP Interface into our tool as it is LDAPv3 Compatible. Our Code is based on .NET framework + C Sharp.
We are facing some issues/challenges while connecting with Okta LDAP Interface.
We use System.DirectoryServices by Microsoft library provided by microsoft currently. But facing issues with LDAP Interface.
For StartTLS/389
I get the error :
Unwilling to perform. LDAP Error Code 53
More: A secure connection cannot be established. To admin: This service requires TLS. LDAP
For SSL/636
Error: The server is not operational.
Links:
https://learn.microsoft.com/en-us/dotnet/api/system.directoryservices?view=netframework-4.8
https://learn.microsoft.com/en-us/dotnet/api/system.directoryservices.directoryentry?view=netframework-4.8
https://ldapwiki.com/wiki/LDAP_UNWILLING_TO_PERFORM
var oktaLDAPPath = "LDAP://dev-506668.ldap.oktapreview.com:636/ou=users,dc=dev-506668,dc=oktapreview,dc=com";
var un = "uid=*******,dc=dev-506668,dc=oktapreview,dc=com";
var pass = "*******";
var filter = "((objectClass=*))";
try
{
using (var userDirectoryEntry = new DirectoryEntry(oktaLDAPPath, un, pass,AuthenticationTypes.SecureSocketsLayer))
{
using (var directorySearcher = new DirectorySearcher(userDirectoryEntry, filter) { PageSize = 100 })
{
directorySearcher.FindOne();
}
}
}
catch (DirectoryServicesCOMException dex)
{
}
catch (Exception ex)
{
}
Thanks
Update: So I did some testing for myself. I see what's going on.
If you do a DNS lookup on dev-506668.ldap.oktapreview.com, it gives you a CNAME result to op1-ldapi-fb96b0a1937080bd.elb.us-east-1.amazonaws.com.
A browser will use the IP address of the CNAME, but still make the request with the host name that you originally gave it. However, for some reason, when starting an LDAP connection, Windows is using the CNAME to iniatate the connection.
In other words, Windows is changing the request to LDAP://op1-ldapi-fb96b0a1937080bd.elb.us-east-1.amazonaws.com:636. But then it receives the SSL certificate which has the name *.ldap.oktapreview.com and it panics because that doesn't match the name it used to make the request (op1-ldapi-fb96b0a1937080bd.elb.us-east-1.amazonaws.com).
I verified all of this using Wireshark, monitoring traffic on port 636. The SSL Client Hello is using op1-ldapi-fb96b0a1937080bd.elb.us-east-1.amazonaws.com instead of dev-506668.ldap.oktapreview.com.
I don't know of a way to make it not do that. DirectoryEntry has no way to override how it verifies the SSL certificate either. LdapConnection does, which you can see here, but it might be a little harder to work with. I've never used it. (you probably should do some verification of your own and no just return true like that example does).
This might be something you can share with Okta Support anyway.
Original answer:
It sounds like your computer does not trust the SSL certificate that is used on the server. To verify this, I use Chrome. You have to start Chrome like this:
chrome.exe --explicitly-allowed-ports=636
Then you can put this in the address bar:
https://dev-506668.ldap.oktapreview.com:636
If the certificate is not trusted, you will get a big error saying so. You can click the 'Advanced' button to see the reason Chrome gives for it not being trusted. But Chrome will also let you inspect the certificate by clicking on "Not secure" in the address bar to the left of the address, then click 'Certificate'.
There a couple reasons it might not be trusted:
The fully-qualified domain name you are using (dev-506668.ldap.oktapreview.com) doesn't match what is on the certificate. If that's the case, you might be able to just change the domain name you use to match the certificate.
The certificate is not issued by a trusted authority. It could be a self-signed certificate. If this is the case, then you should see an "Install Certificate" button when you view the certificate, which you can use to explicitly trust the certificate. See here for screenshots, starting on step 3. This will only apply to the current computer.
I recently ran into this issue and was pointed to the following solution:
Add the following registry value then restart the server and see if it fixes the issue.
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LDAP\UseHostnameAsAlias
DWORD, set the value to 1
See https://support.microsoft.com/en-us/topic/an-error-occurs-when-you-try-to-establish-ssl-connections-to-the-nodes-by-using-the-alias-name-from-an-ldaps-client-computer-that-is-running-windows-7-or-windows-server-2008-r2-49b6ee93-2c68-a892-8133-612d208dd1b1 for more details.
I am working on a solution to use Active Directory to authenticate our applications, we are using LDAP protocol, we have several domain controllers that all sync together.
I have built out an application that works with Active Directory authentication using our internal domain controller which is on the same network I run the application, as soon as I point to the Domain Controller hosted on Amazon (separate network) I get an error response saying the server can not be contacted. When I open command prompt and ping the server using its domain name I can get a reply.
The AWS AD server is new and was spun up just a few weeks ago for this project, I can't tell if this is an issue with the AD setup on that machine or if I have to modify my code to access AD on a separate network. Here is the function I use to authenticate against AD - again this works on the domain controller hosted on the same network I'm executing but as soon as I update the config to use the AWS DC it fails. Sys admins are looking into the server to make sure everything is OK, but I'm expecting that they will say everything is configured correctly.
public bool IsAuthenticated(string username, string pwd)
{
var domainAndUsername = _domain + #"\" + username;
var entry = new DirectoryEntry(_ldapPath, domainAndUsername, pwd);
_username = username;
try
{
//Bind to the native AdsObject to force authentication.
var unused = entry.NativeObject;
var search = new DirectorySearcher(entry) {Filter = "(SAMAccountName=" + username + ")"};
search.PropertiesToLoad.Add("cn");
var result = search.FindOne();
if (result == null) return false;
//Update the new path to the user in the directory.
_ldapPath = result.Path;
_filterAttribute = (string) result.Properties["cn"][0];
}
catch (Exception ex)
{
// Exception Handling
// throw
}
return true;
}
When I open command prompt and ping the server using its domain name I
can get a reply.
Ping is not a good test. Just because ping works, doesn't mean that anything else will or will not work.
A better test is using the telnet client. It's a quick test that opens a TCP connection on whatever port you specify. That will tell you if there are any firewalls in the way preventing the connection.
It uses port 389 by default, so try that. From the command prompt:
telnet domain.com 389
A blank screen means the connection succeeded. If it fails, it will say so.
Here are the ports that Active Directory uses. You can specify a different port if you want to.
389: LDAP - single domain only (the default if you don't specify anything)
3268: Global Catalog - your whole forest
636: LDAP over SSL
3269: Global Catalog over SSL
I'm trying to get the groups for a user from an ADAM server using:
PrincipalContext yourDomain = new PrincipalContext(ContextType.ApplicationDirectory,
principalContextName,
principalContextContainer,
ContextOptions.ServerBind | ContextOptions.SimpleBind,
principalContextUserName,
principalContextPassword);
UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain,
IdentityType.UserPrincipalName,
userName);
PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
And I keep getting the "server is not operational" error.
I finaly understood my problem but I dont know how to fix it.
The thing is that, the two ADAM servers are behind a firewall and an NLB, they both reply by the name of adam.company.local and the nslookup of that name, reply's 100.10.130.1
I can even ping the 100.10.130.1 and the name adam.company.local so the problem wasn't networking, but it is!
With WireShark I found out that at some point the server returns his own name and my calls start trying to call that name. Of course then the firewall blocks them and the exception occurs.
To confirm this, I made 2 lines on the hosts file, with both server names to 100.10.130.1 and the problem was gone, I could retrieve all the groups with ease.
Why is that? why does de connection change to a machine I cant get to?
The final question is how do I prevent it because on the publication machine I cant create these lines on the hosts file?
I'm using WMI inside c# to get a list of users currently "logged in" to a machine:
ManagementScope ms = new ManagementScope(ManagementPath.DefaultPath);
var q = new SelectQuery("Win32_LoggedOnUser");
using (var query = new ManagementObjectSearcher(ms, q)) {
using (var results = query.Get()) {
foreach (var r in results) {
using (var o = new ManagementObject(r["Dependent"].ToString())) {
var logonType = o["LogonType"];
if (logonType == "2") {
// Interactive user is logged in, retrieve the name
using (var userObj = new ManagementObject(r["Antecedent"].ToString())) {
name = userObj["Name"].ToString();
}
}
...
This works great, but it seems that in some cases even after the user logs out, WMI still reports it as being logged in. One particular case is when that user accesses a network share during the session.
Is there anyway around this? Perhaps a way to test a session to see if it was created as a share or if it's active?
Any tips would be greatly appreciated.
Even though the user has logged off, because you accessed another computer's files remotely, the connection remains open for a period of time.
https://superuser.com/questions/173535/what-are-close-wait-and-time-wait-states
Look under Run > cmd > netstat -a. You should see a connection called microsoft-ds after you have established a connection through Windows Explorer to another computer. This is the service that Microsoft uses for file transfers, among other things. If you see a TIME_WAIT or CLOSE_WAIT, the connection is still open even if window you used to access the files is closed.
You can check this programmatically by using "handle.exe", a tool provided by Microsoft that is a part of Sysinternals, that will be able to provide information on which part of the hive is still active. This should include Registry Keys, ports, the works.
http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx
WMI may be reporting that the user is still logged in because a port or connection has not been closed that was initiated by that user. This type of thing has caused us a few headaches, so we use handle.exe to dump anything keeping the hive open for a user and then systematically kill/close all of it before we do any profile maintenance (as an automation).
Of course, rebooting the computer always works. =)
I'm currently writing some software in C# which needs to connect to an AD server and get some user details. When I connect using the code below it works against most AD servers that I connect to but there are a couple where it fails with an error of "Logon failure: unknown user name or bad password.". The server name / credentials I'm using are definately correct as I've tested them with an LDAP Browser and the AD server is using standard security (port 389 etc). Can anyone offer any advice?
Cheers
Tim
DirectoryEntry d = new DirectoryEntry("LDAP://" + domain, admin_username, admin_password);
try
{
object x = d.NativeObject;
}
catch
{
throw;
}
I've had similar issues programming .net / AD in the past. One thing I found useful is using an LDAP viewer to see if I can connect to certain servers, etc. In this way, I can at least determine if it is a .NET error (perhaps my code), a credential error, etc.
I use the free/lite version of Softerra's LDAP viewer (http://www.ldapbrowser.com/download.htm) although I'm sure there are many others to choose from out there. If you try the one listed here, make sure to download the 'LDAP browser' and not 'LDAP Administrator'. The browser is the free one.
Try connecting to the same LDAP path you're having trouble with in code, using a LDAP browser/viewer. This will at least as step one determine if it is a .NET/code issue or not. If you can't connect via the browser, it can be helpful to play around with the connection options, such as port, domain (FQDN), etc.
Hope this might help narrow things down.
Active Directory allows at least three different logon name styles:
LDAP - i.e. LDAP DN. For example: cn=JohnS, ou=Users, dc=example, dc=com
NTLM. For example: EXAMPLE\JohnS
Kerberos principal name: For example: johns#example.com
However, you cannot login with just JohnS like you do with Windows box. It's a very common mistake.