RabbitMQ + C# + SSL - c#

I'm trying to use C# to get RabbitMQ 3.6.2 to use SSL/TLS on Windows 7 against Erlang 18.0. I'm running into errors when I'm enabling SSL in my C# code. I have gone through the steps to set up SSL/TLS here. I've also gone through the [troubleshooting steps][2] which show turn up successful (except I couldn't do the stunnel step due to lack of knowledge of stunnel). Here's my C# code trying to connect to RabbitMQ:
var factory = new ConnectionFactory()
{
// NOTE: guest username ONLY works with HostName "localhost"!
//HostName = Environment.MachineName,
HostName = "localhost",
UserName = "guest",
Password = "guest",
};
// Without this line, RabbitMQ.log shows error: "SSL: hello: tls_handshake.erl:174:Fatal error: protocol version"
// When I add this line to go to TLS 1.2, .NET throws an exception: The remote certificate is invalid according to the validation procedure.
// https://stackoverflow.com/questions/9983265/the-remote-certificate-is-invalid-according-to-the-validation-procedure:
// Walked through this tutorial to add the client certificate as a Windows Trusted Root Certificate: http://www.sqlservermart.com/HowTo/Windows_Import_Certificate.aspx
factory.Ssl.Version = SslProtocols.Tls12;
factory.Ssl.ServerName = "localhost"; //System.Net.Dns.GetHostName();
factory.Ssl.CertPath = #"C:\OpenSSL-Win64\client\keycert.p12";
factory.Ssl.CertPassphrase = "Re$sp3cMyS3curi1ae!";
factory.Ssl.Enabled = true;
factory.Port = 5671;
// Error: "The remote certificate is invalid according to the validation procedure."
using (var connection = factory.CreateConnection())
{
}
There's a StackOverflow post regarding the "The remote certificate is invalid according to the validation procedure." exception, but the hack fix doesn't seem to take effect as the callback method suggested is never called. I think that I've added my certificate generated via OpenSSL to the Windows Trusted Root Certification Authorities certificates list for local computer. So I'm at a loss here. Any ideas on how to proceed?
Edit: Here's the final working code for anyone struggling to implement SSL on Rabbit:
var factory = new ConnectionFactory();
factory.HostName = ConfigurationManager.AppSettings["rabbitmqHostName"];
factory.AuthMechanisms = new AuthMechanismFactory[] { new ExternalMechanismFactory() };
// Note: This should NEVER be "localhost"
factory.Ssl.ServerName = ConfigurationManager.AppSettings["rabbitmqServerName"];
// Path to my .p12 file.
factory.Ssl.CertPath = ConfigurationManager.AppSettings["certificateFilePath"];
// Passphrase for the certificate file - set through OpenSSL
factory.Ssl.CertPassphrase = ConfigurationManager.AppSettings["certificatePassphrase"];
factory.Ssl.Enabled = true;
// Make sure TLS 1.2 is supported & enabled by your operating system
factory.Ssl.Version = SslProtocols.Tls12;
// This is the default RabbitMQ secure port
factory.Port = 5671;
factory.VirtualHost = "/";
// Standard RabbitMQ authentication (if not using ExternalAuthenticationFactory)
//factory.UserName = ConfigurationManager.AppSettings["rabbitmqUsername"];
//factory.Password = ConfigurationManager.AppSettings["rabbitmqPassword"];
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
// publish some messages...
}
}
Thanks,
Andy

Usual problem is mismatch between what you provide in Ssl.ServerName and host SSL certificate was issued for.
Also note that server-side SSL (encrypted connection between your client and server) and client-side authentication with certificate (you provide server with information which confirms that you have certificate it expects) are two different things. By providing Ssl.CertPath you intent to authorize at server using this certificate, which might or might not be what you want.

My problem was related to using self signed certificates. I had to add the SslOption AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch |
SslPolicyErrors.RemoteCertificateChainErrors
In the example connection factory creation code sslEnabled is true.
new ConnectionFactory()
{
Uri = uri,
ClientProvidedName = clientProvidedName,
AutomaticRecoveryEnabled = true,
Ssl = new SslOption(){
Enabled = sslEnabled,
AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNameMismatch |
SslPolicyErrors.RemoteCertificateChainErrors} ,
NetworkRecoveryInterval = TimeSpan.FromSeconds(networkRecoveryIntervalSecs)
}

It can be done as simple as this
const string RabbitMqServerHostname = "myserver.northeurope.cloudapp.azure.com";
var factory = new ConnectionFactory()
{
HostName = RabbitMqServerHostname,
UserName = "myuser",
Password = "mypassword",
// The settings below turn on SSL
Port = 5671,
Ssl = new SslOption
{
Enabled = true,
ServerName = RabbitMqServerHostname
}
};

I just went through a similar frustrating exercise with the .NET 4.5 client (v. 3.6.6) and the RabbitMQ broker/service on Windows (v. 3.6.6, Erlang 19.2).
The correct combination of RabbitMQ config file options and client settings is not intuitive and the client factory object has changed since the documentation was last updated. Now there's an SslOption class.
Are you still having problems? Perhaps I can help you.

I've resolved the problem changing only the Ssl.ServerName to the Common Name (CN) of the issued certificate, because it was different of the server which hosts the service.
factory.Ssl.ServerName = "[certificate cn]";
I had tried with python (because the provider used that language) and it worked, I suppose then that Python doesn't validate that features of the certificates (it's more insecure?).

Related

HttpClient certificate when hosted in IIS/Asp.NET Application not work

I have a strange problem.
I need to perform an SSL request using a CER client certificate, to a server that requires authentication by that certificate.
I am using the code below:
var cert = X509Certificate.CreateFromCertFile("cert.cer");
var handler = new WebRequestHandler();
handler.ClientCertificates.Add(cert);
var http_client = new HttpClient(handler);
http_client.BaseAddress = new Uri("https://service.com/");
var str_json = JsonConvert.SerializeObject(new
{
Field = "Value1",
Fiesl2 = "Value2"
});
var byteContent = new ByteArrayContent(Encoding.UTF8.GetBytes(str_json));
byteContent.Headers.Remove("Content-Type");
byteContent.Headers.Add("Content-Type", "application/json");
var res = http_client.PostAsync("ResourcePath", byteContent).Result;
res.EnsureSuccessStatusCode(); //THe error 401 ocurrs here
var res_body = res.Content.ReadAsStringAsync().Result;
This code works perfectly when I squeeze into a ConsoleApplicaiton or a WebApplication in IIS Express.
But when I squeeze exactly the same code in Local IIS or IIS Server, I get the 401-Unauthorized error. The strange thing is that using Fiddler, in this case I can not even see the request attempt.
I've already checked that path is not the problem.
The problem occours in .NET 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1 and etc..
Can anyone help me out, is it any configuration that should be performed in IIS. I've researched a lot, but I did not find that specific error.
A .cer file at client side does not contain private key, so usually it won't work if mutual SSL/TLS is required by the server. You need to get a valid certificate with private key (usually a .pfx file).

UWP app HttpClient HTTPS client certificate problems

I'm writing a UWP app in C# that is eventually destined for IoT, but right now I've only been debugging locally. I'm using Windows.Web.Http.HttpClient to connect to a self-hosted WCF REST web service that I've also written and have running as a Console app on the same machine for testing. The service requires mutual authentication with certificates, so I have a CA cert, service cert, and client cert.
My UWP code works like this:
Check app cert store for client cert and CA cert installed.
If not, install from PFX file and CER file, respectively.
Attach the Certificate to the HttpBaseProtocolFilter and add the filter to the HttpClient
Call the HttpClient.PostAsync
After I call PostAsync I get the following error: An Error Occurred in the Secure Channel Support. After plenty of searching online, and by common sense, I'm pretty sure HttpClient is barfing because of a problem establishing the mutually-authenticated SSL connection. But based on my troubleshooting I can't figure why.
To troublshoot further, I've written a plain old Console app using System.Net.Http.HttpClient, attached the client certificate to the request and everything works great. Sadly, System.Net isn't fully supported on UWP. I've also tried NOT attaching the certificate to the UWP HttpClient and the app prompts me with a UI to select an installed certificate. I select the correct cert and still get the same exception (this at least lets me know the cert is installed correctly and validating properly with the CA from the app's perspective). In additon, I hit the GET on the web service from a browser, select the client cert when prompted, and am able to download a file.
I've tried using Fiddler and, I assume because of the way it proxies traffic, it seems to work a little bit further, except my web service rejects the request as Forbidden (presumably because Fiddler is not including the correct client cert in the request). I haven't hit up Wireshark yet because it's a pain to get Wireshark to work using localhost on Windows.
My next step is to start changing the web service to not require client authentication and see if that is the problem.
Two questions: Why is Windows.Web.Http.HttClient not working in this case? And, less important, any recommendations on good HTTP monitoring tools to help me debug this further?
This MSDN post proved to have the answer. Seems like an oversight on MS part requiring a separate, meaningless call to the API beforehand. Oh well.
http://blogs.msdn.com/b/wsdevsol/archive/2015/03/26/how-to-use-a-shared-user-certificate-for-https-authentication-in-an-enterprise-application.aspx
Excerpt from the article:
However, the security subsystem requires user confirmation before allowing access to a certificates private key of a certificate stored in the shared user certificates store. To complicate matters, if a client certificate is specified in code then the lower level network functions assume the application has already taken care of this and will not prompt the user for confirmation.
If you look at the Windows Runtime classes related to certificates you won’t find any method to explicitly request access to the certificate private key, so what is the app developer to do?
The solution is to use the selected certificate to 'Sign' some small bit of data. When an application calls CryptographicEngine.SignAsync, the underlying code requests access to the private key to do the signing at which point the user is asked if they want to allow the application to access the certificate private key. Note that you must call 'Async' version of this function because the synchronous version of the function: Sign, uses an option that blocks the display of the confirmation dialog.
For example:
public static async Task<bool> VerifyCertificateKeyAccess(Certificate selectedCertificate)
{
bool VerifyResult = false; // default to access failure
CryptographicKey keyPair = await PersistedKeyProvider.OpenKeyPairFromCertificateAsync(
selectedCertificate, HashAlgorithmNames.Sha1,
CryptographicPadding.RsaPkcs1V15);
String buffer = "Data to sign";
IBuffer Data = CryptographicBuffer.ConvertStringToBinary(buffer, BinaryStringEncoding.Utf16BE);
try
{
//sign the data by using the key
IBuffer Signed = await CryptographicEngine.SignAsync(keyPair, Data);
VerifyResult = CryptographicEngine.VerifySignature(keyPair, Data, Signed);
}
catch (Exception exp)
{
System.Diagnostics.Debug.WriteLine("Verification Failed. Exception Occurred : {0}", exp.Message);
// default result is false so drop through to exit.
}
return VerifyResult;
}
You can then modify the earlier code example to call this function prior to using the client certificate in order to ensure the application has access to the certificate private key.
Add the Certificate file your Project
Add the Certificate to the Manifested file (give file path in attachment)
the Frist Service Call of in Ur Project use to ignore the certificate validation Following Code is most Suitable for Login Function.
try
{
var filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationInformationMissing);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.WrongUsage);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain);
Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient(filter);
TimeSpan span = new TimeSpan(0, 0, 60);
var cts = new CancellationTokenSource();
cts.CancelAfter(span);
var request = new Windows.Web.Http.HttpRequestMessage()
{
RequestUri = new Uri(App.URL + "/oauth/token"),
Method = Windows.Web.Http.HttpMethod.Post,
};
//request.Properties. = span;
string encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(Server_Username + ":" + Server_Password));
var values = new Dictionary<string, string>
{ { "grant_type", "password" },{ "username", Uname}, { "password", Pwd }};
var content = new HttpFormUrlEncodedContent(values);
request.Headers.Add("Authorization", "Basic " + encoded);
request.Content = content;
User root = new User();
using (Windows.Web.Http.HttpResponseMessage response = await client.SendRequestAsync(request).AsTask(cts.Token))
{
HttpStatusCode = (int)response.StatusCode;
if (HttpStatusCode == (int)HttpCode.OK)
{
using (IHttpContent content1 = response.Content)
{
var jsonString = await content1.ReadAsStringAsync();
root = JsonConvert.DeserializeObject<User>(jsonString);
App.localSettings.Values["access_token"] = root.Access_token;
App.localSettings.Values["refresh_token"] = root.Refresh_token;
App.localSettings.Values["expires_in"] = root.Expires_in;
var json = JsonConvert.SerializeObject(root.Locations);
App.localSettings.Values["LocationList"] = json;
App.localSettings.Values["LoginUser"] = Uname;
}
}
}
}
catch (Exception ex)
{
ex.ToString();
}

Error calling SSL payment gateway: "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel"

Making my first steps at implementing payment gateways.
Calling both Braintree and Beantream payment gateways from my ASP.net code behind hosted in IIS 8.5 under win 8.1 results in :
"The underlying connection was closed: Could not establish trust
relationship for the SSL/TLS secure channel"
Note that calling the same services from my middle-tier that sits on the same box works fine, so the certificate is installed properly.
Here's sample code to call the Braintree service thru their SDK:
[System.Web.Services.WebMethod]
public static CheckinDetailResponse GetViewData()
{
CheckinDetailResponse response = new CheckinDetailResponse()
{
ClientToken = string.Empty,
IsSuccessful = false,
ErrorMessage = string.Empty
};
try
{
response.ClientToken = GetPaymentToken();
response.IsSuccessful = true;
}
catch (BaseDataServicesException ex)
{
response.ErrorMessage = ex.GetLocalizedMessage(Resources.WebCommon.ResourceManager);
}
return response;
}
private static string GetPaymentToken()
{
var gateway = new BraintreeGateway
{
Environment = Braintree.Environment.SANDBOX,
MerchantId = "999",
PublicKey = "999",
PrivateKey = "999"
};
var clientToken = gateway.ClientToken.generate(null);
return JsonDcSerialization.ToJsonString(clientToken); ;
}
Is there some special setting that needs to be done in IIS in order to call SSL services from a web app?
Thanks!
Check if the SSL Certificates are installed on the machine, if you do pass them on you code, and also if the machine you're using is configured to accept the certificate issuer as trusted.
if this is a certificate issued from a third party certification authority you may need to pass the signer certificate (aka intermediate ca) along with the public key (eventually in pkcs#7 format). In the case you're using a self-signed certificate you may need to have the root imported into the mmc trusted root certification authority store.
I tend to think it's the first case as untrusted error message is usually referred to the lack of a piece in the chain of trust.
Hope this help.

Self Sign certificate on email server

I'm using a test email server to test out my code in SSL environment. I used the following command to create a self signed root and a signed certificate.
I wrote a simple test program using SmtpClient to send test email and the code is as follow:
System.Net.Mail.MailMessage mm = new System.Net.Mail.MailMessage(tFrom.Text, tTo.Text);
mm.Subject = tSubject.Text;
mm.Body = tBody.Text;
SmtpClient client = new SmtpClient(tSmtp.Text, Convert.ToInt32(tPort.Text));
client.UseDefaultCredentials = false;
if (!String.IsNullOrEmpty(tPass.Text) && !String.IsNullOrEmpty(tUser.Text))
{
client.EnableSsl = true;
client.Credentials = new NetworkCredential(tUser.Text, tPass.Text);
}
client.SendCompleted += new SendCompletedEventHandler(client_SendCompleted);
client.SendAsync(mm, null);
On my server (Smtp4Dev) I have it set to accept TLS connection
On my client machine I have the following:
Yet, whenever I send an email I keep getting the error as follow on the server log:
220 Ready to start TLS
Session ended abnormally.
System.NotSupportedException: The server mode SSL must use a certificate with the associated private key.
If I tried this without SSL then I can receive my email fine. I tried to add the certificate under Personal and Trusted Root Certification but same error still occur. I am very new to SSL so I hope you can point me in the right direction.
Look at implementing the ServerCertificateValidationCallback delegate. Try something like this before you use SmtpClient:
System.Net.ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
Returning true and thus accepting all certificates is only a good idea in a dev environment, but you can expand on the delegate implementation to check for other properties and not just blindly return true for everything.

Novell LDAP C# - Novell.Directory.Ldap - Has anybody made it work?

I'm trying to use the library released by Novell (Novell.Directory.Ldap). Version 2.1.10.
What I've done so far:
I tested the connection with an application (LdapBrowser) and it's working, so its not a communication problem.
It's compiled in Mono, but I'm working with Visual Studio. So created a project with the sources. I also included a reference to Mono.Security, because the project depended on it.
I commented a call (freeWriteSemaphore(semId); ) in the error catching part of the connection, because it was throwing more exceptions. I checked what that call did, and its just a error tracing mechanism.
I followed the basics steps provided in the documentation by Novell (http://www.novell.com/coolsolutions/feature/11204.html).
// Creating an LdapConnection instance
LdapConnection ldapConn= new LdapConnection();
ldapConn.SecureSocketLayer = ldapPort == 636;
//Connect function will create a socket connection to the server
ldapConn.Connect(ldapHost,ldapPort);
//Bind function will Bind the user object Credentials to the Server
ldapConn.Bind(userDN,userPasswd);
Right now it's crashing at the Bind() function. I get the error 91.
So, has someone ever used this library and seen it work? If so, what did you do to make it work, is there some special configuration needed? Is there a way to make it work in .NET environment without Mono (I can have references to Mono dlls, but I don't want it to be installed on the server)?
(UPDATE)
The connection is on port 636, thus using SSL. I checked with WireShark the communication and compared with what I get from LDAP Browser. I've seen that the step where the SSL certicate is communicated, is not done by the LDAP library. So, what is the best way to make it do what its supposed to?
(UPDATE) I checked the documentation and it's indicating that it doesn't support SSL. http://www.novell.com/coolsolutions/feature/11204.html
Authenticate to the LDAP server with
LdapConnection.Bind(). We support only
cleartext authentication. SSL/TLS
support is yet to be added.
But the documentation date from 2004, and since then, many updates have been made. And there is a parameter in the library to define if the connection uses SSL. So now I'm confused.
(UPDATE) Found a more up-to-date documentation : http://developer.novell.com/documentation//ldapcsharp/index.html?page=/documentation//ldapcsharp/cnet/data/bqwa5p0.html. The way the SSL connection is made, is by registering the certificate on the server. The problem is that what I'm doing is not bound to a specific Novell server, so the certificate must be obtained dynamically.
I came looking for a solution to a similar problem. My bind command would fail as well while using the same code from Novell's website. The solution that worked for me was adding a dynamic Certificate Validation Call back. You can read about it here.
// Creating an LdapConnection instance
LdapConnection ldapConn = new LdapConnection();
ldapConn.SecureSocketLayer = true;
ldapConn.UserDefinedServerCertValidationDelegate += new
CertificateValidationCallback(MySSLHandler);
//Connect function will create a socket connection to the server
ldapConn.Connect(ldapHost, ldapPort);
//Bind function will Bind the user object Credentials to the Server
ldapConn.Bind(userDN, userPasswd);
// Searches in the Marketing container and return all child entries just below this
//container i.e. Single level search
LdapSearchResults lsc = ldapConn.Search("ou=users,o=uga",
LdapConnection.SCOPE_SUB,
"objectClass=*",
null,
false);
while (lsc.hasMore())
{
LdapEntry nextEntry = null;
try
{
nextEntry = lsc.next();
}
catch (LdapException e)
{
Console.WriteLine("Error: " + e.LdapErrorMessage);
// Exception is thrown, go for next entry
continue;
}
Console.WriteLine("\n" + nextEntry.DN);
LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
System.Collections.IEnumerator ienum = attributeSet.GetEnumerator();
while (ienum.MoveNext())
{
LdapAttribute attribute = (LdapAttribute)ienum.Current;
string attributeName = attribute.Name;
string attributeVal = attribute.StringValue;
Console.WriteLine(attributeName + "value:" + attributeVal);
}
}
ldapConn.Disconnect();
Console.ReadKey();
}
public static bool MySSLHandler(Syscert.X509Certificate certificate,
int[] certificateErrors)
{
X509Store store = null;
X509Stores stores = X509StoreManager.CurrentUser;
//string input;
store = stores.TrustedRoot;
X509Certificate x509 = null;
X509CertificateCollection coll = new X509CertificateCollection();
byte[] data = certificate.GetRawCertData();
if (data != null)
x509 = new X509Certificate(data);
return true;
}
I finally found a way to make this work.
First, theses posts helped me get on the right track : http://directoryprogramming.net/forums/thread/788.aspx
Second, I got a compiled dll of the Novell LDAP Library and used the Mono.Security.Dll.
The solution:
I added this function to the code
// This is the Callback handler - after "Binding" this is called
public bool MySSLHandler(Syscert.X509Certificate certificate, int[] certificateErrors)
{
X509Store store = null;
X509Stores stores = X509StoreManager.LocalMachine;
store = stores.TrustedRoot;
//Import the details of the certificate from the server.
X509Certificate x509 = null;
X509CertificateCollection coll = new X509CertificateCollection();
byte[] data = certificate.GetRawCertData();
if (data != null)
x509 = new X509Certificate(data);
//List the details of the Server
//if (bindCount == 1)
//{
Response.Write("<b><u>CERTIFICATE DETAILS:</b></u> <br>");
Response.Write(" Self Signed = " + x509.IsSelfSigned + " X.509 version=" + x509.Version + "<br>");
Response.Write(" Serial Number: " + CryptoConvert.ToHex(x509.SerialNumber) + "<br>");
Response.Write(" Issuer Name: " + x509.IssuerName.ToString() + "<br>");
Response.Write(" Subject Name: " + x509.SubjectName.ToString() + "<br>");
Response.Write(" Valid From: " + x509.ValidFrom.ToString() + "<br>");
Response.Write(" Valid Until: " + x509.ValidUntil.ToString() + "<br>");
Response.Write(" Unique Hash: " + CryptoConvert.ToHex(x509.Hash).ToString() + "<br>");
// }
bHowToProceed = true;
if (bHowToProceed == true)
{
//Add the certificate to the store. This is \Documents and Settings\program data\.mono. . .
if (x509 != null)
coll.Add(x509);
store.Import(x509);
if (bindCount == 1)
removeFlag = true;
}
if (bHowToProceed == false)
{
//Remove the certificate added from the store.
if (removeFlag == true && bindCount > 1)
{
foreach (X509Certificate xt509 in store.Certificates)
{
if (CryptoConvert.ToHex(xt509.Hash) == CryptoConvert.ToHex(x509.Hash))
{
store.Remove(x509);
}
}
}
Response.Write("SSL Bind Failed.");
}
return bHowToProceed;
}
And i used it in the binding process
// Create Connection
LdapConnection conn = new LdapConnection();
conn.SecureSocketLayer = true;
Response.Write("Connecting to:" + ldapHost);
conn.UserDefinedServerCertValidationDelegate += new
CertificateValidationCallback(MySSLHandler);
if (bHowToProceed == false)
conn.Disconnect();
if (bHowToProceed == true)
{
conn.Connect(ldapHost, ldapPort);
conn.Bind(loginDN, password);
Response.Write(" SSL Bind Successfull ");
conn.Disconnect();
}
quit = false;
The key elements are using the SSL Handler to dynamically obtain the Certificate, and using X509StoreManager.LocalMachine so that when the website is running its able to save and fetch the certificates.
The UserDefinedServerCertValidationDelegate is obsolete, so if it is an issue with invalid ssl certificates, you can skip the certificatevalidaion this way:
LdapConnectionOptions options = new LdapConnectionOptions()
.ConfigureRemoteCertificateValidationCallback(new CertCallback((a, b, c, d) => true))
.UseSsl();
LdapConnection connection = new LdapConnection(options);
connection.Connect(...);
You should however review if ignoring the certificate is a secure solution for your application.
91 is "cannot connect". Try to put the server in "ldap://x.x.x.x" format, check that userDN is set properly (with domain etc).
I am often using WireShark to see what is going on at the network level (it is aware of LDAP protocol).
I work on Forefront Identity Manager integration. So the code I write always comes from a few calling clients. This may not be appropriate if you are trying to package an application for use "anywhere".
I just wanted to update this thread with a simple solution for Novell servers which have the default TLS/SSL "confidentiality required" option enabled.
1) Make sure you get the SSL certificates off the Novell server you are binding too and enroll those into the trusted store on the executing client / server. There are normally two 1 for the IP and for the hostname dependent on which you will call (DNS preferable)
2) Import the following / add references
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
3) Here is a snippet. Make sure you choose the AuthenticationTypes.SecureSocketsLayer which is key.
// serverAddress = Server IP or DNS (Match SSL certificate)
// ObjectDN = The DN of the user you are binding to
// userName = Account which will be used to make the bind
// password = password of the user which will make the bind
// value = The value you wish to add to the attribute
// Connect to the user in LDAP
DirectoryEntry entry = new DirectoryEntry("LDAP://" + serverAddress + "/" + ObjectDN + ""
, userName
, password
, AuthenticationTypes.SecureSocketsLayer);
// Write the Updated attribute
entry.Properties["attribute"].Value = value;
// Read back the updated Attribute into a label
label.Text = entry.Properties["attribute"].Value.ToString();
I think I may have already offered this answer to someone else in a different question.
[OtherQuestion on LDAP][1]
Two issues I think: 1) What kind of bind are you trying to do? SSL? Clear text? Anonymous?
2) How is it configured on the eDirectory side for LDAP binds?
The tool LDAP Browser, are you referring to the one at this link?
Free LDAP Browser
On the eDirectory side, they can require TLS for all LDAP communication, and they can disallow Anonymous binds.
Can you ask the folks at the other end to enable LDAP tracing (Using DStrace with the +LDAP option enabled, some links for how to use Dstrace on Novell eDirectory look at: Different types of Dstrace Capturing and understand DS Trace for Identity Manager.)
That usually will show an error message that will enlighten you.
My guess is either Require TLS is enabled, and you might not be doing a successful SSL bind.
If so, try to connect on port 636, with SSL enabled, and a fully qualified DN for the user you are trying to login as.
If you are trying with SSL enabled, and you are not getting a pop up box about accepting the tree CA's trusted root certficate, then perhaps the CA or the SSL certificate taht the eDirectory server is user has expired or is broken. (There are any number of causes for this that can be common, and take but a moment to fix).
Usually in Dstrace you will see an error about the SSL certificate if there is a problem. An example from a Novell Identity Manager perspective of an expired certificate is in this article: Certificate Expired As well as some details on how to fix the certificates.
Next possibility is that the DN you are specifying is not quite correct.
Let me know if you need more help.
Following my previous post - if you have to use secure connection, try to use ldaps:// as a prefix to server address.
If there is no SSL/TLS support, you can try this - guidelines and .NET wrapper for OpenLDAP library.
One important point - there are settings for TLS security level in OpenLDAP, so if your LDAP server has self-signed certificate you either have to import it on a client side or set TLS to not check the signing authority *that is less secure of course).
I had gone through this scenario, for me Novell LDAP service running in Kubernetes container. I tried adding CA certificate to the Mono trust store, which will add the file inside "/usr/share/.mono/certs/Trust" in linux container. But nothing did work, still Novell connect not successful for LDAP 636 port.
Finally I made it work in below way:
LdapConnection Connection = new LdapConnection();
Connection.SecureSocketLayer = true;
Connection.UserDefinedServerCertValidationDelegate += new
Novell.Directory.Ldap.RemoteCertificateValidationCallback(LdapSSLHandler);
public bool LdapSSLHandler(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == sslPolicyErrors.None)
{
return true; //Is valid
}
if (certificate.GetCertHashString() == "YOUR CERTIFICATE HASH KEY") // Thumbprint value of the certificate
{
return true;
}
return false;
}

Categories