Connecting to LDAP with PHP Successfully, but cannot connect with C# - c#

I am connecting successfully to the LDAP with PHP, tried a whole lot of things but when I try with C# am always getting either "Server is not operational" or "The LDAP server in unavailable".
Here is the PHP code:
<?php
function login($username='user', $password='pass') {
if (empty($username) || empty($password)) {
throw new BadCredentialsException('Invalid username or password.');
}
if (($ldap = #ldap_connect($url = 'ldap://ds.xyz-example.com', $port = 636)) === false) {
echo('Error connecting LDAP server with url %s on port %d.');
}
if (!#ldap_bind($ldap, sprintf($dn='uid=%s,ou=People,dc=xyz-example,dc=com', $username), $password)) {
$error = ldap_errno($ldap);
if ($error === 0x31) {
echo('Invalid username or password.');
} else {
echo('error during authentication with LDAP.');
}
}
return true;
}
login(); // call the function
?>
This is working perfect but I need it with C#. How can I do this with C# using the port and the dn and the user and pass?
Here is what I tried with C# but with an error "Server is not operational"
string ldapPath = "LDAP://ds.xyz-example.com:636/UID=user,OU=People,DC=xyz-example,DC=com";
string user = "user";
string password = "pass";
DirectoryEntry deSSL = new DirectoryEntry(ldapPath, user, password, AuthenticationTypes.SecureSocketsLayer);
try
{
user = deSSL.Properties["uid"][0].ToString(); //if this works, we bound successfully
Response.Output.Write("Success... {0} has bound", user);
}
catch (Exception ex)
{
Response.Output.Write("Bind Failure: {0}", ex.Message);
}
Thanks in advance!

Could it be your library doesn't implement LDAP but rather a weird non-standard Microsoft version of LDAP called ActiveDirectory, which only works when the server is an actual ActiveDirectory Server and doesn't quite work as easily when you use non-microsoft servers, such as OpenLDAP?
Could it be?

Related

Can't connect to Gmail with IMAPX using c#

I'm following an example from IMAPX but it will not connect to GMAIL.
IMAP is enabled for the account and I've triple checked the username and password but it won't connect:
var server = ConfigurationManager.AppSettings["server"];
var login = Decrypt(ConfigurationManager.AppSettings["user"]);
var password = Decrypt(ConfigurationManager.AppSettings["pass"]);
//create the IMAP CLient
var client = new ImapClient(server, true);
//connect to the server
if (!client.Connect())
{
Console.WriteLine("Error: Failed to connect");
return;
}
//login to the server
if (!client.Login(login, password))
{
Console.WriteLine("Error: Invalid login");
return;
}
Anyone have any idea how to use this library to connect to gmail? I have tried variations of "use SSL" and "verify certificate", but no mater what I try the login always fails.
Google by default does not allow "less secure" apps from account access unless the account is setup to allow it.
References:
https://support.google.com/accounts/answer/6010255?hl=en
https://security.stackexchange.com/questions/66025/what-are-the-dangers-of-allowing-less-secure-apps-to-access-my-google-account

C# Active Directory Invoke "ChangePassword" cannot contact domain

I have the following code as part of a web application for my Active Directory users to be able to update their passwords (for active directory and gmail at the same time). I am using C# with System.DirectoryServices.AccountManagement.
This code worked until yesterday
try
{
State.log.WriteLine("Connecting LDAP.");
string ldapPath = "LDAP://192.168.76.3";
DirectoryEntry directionEntry = new DirectoryEntry(ldapPath, domainName + "\\" + userName, currentPassword);
if (directionEntry != null)
{
DirectorySearcher search = new DirectorySearcher(directionEntry);
State.log.WriteLine("LDAP Connected, searching directory for SAMAccountName");
search.Filter = "(SAMAccountName=" + userName + ")";
SearchResult result = search.FindOne();
if (result != null)
{
State.log.WriteLine("Getting User Entry.");
DirectoryEntry userEntry = result.GetDirectoryEntry();
if (userEntry != null)
{
State.log.WriteLine("Setting Password");
if (force)
{
userEntry.Invoke("SetPassword", new[] { newPassword });
}
else
{
userEntry.Invoke("ChangePassword", new object[] { currentPassword, newPassword });
}
userEntry.CommitChanges();
State.log.WriteLine("Changes Committed to ActiveDirectory.");
}
else
{
State.log.WriteLine("Could not get user Entry...");
}
}
else
{
State.log.WriteLine("Search returned no results.");
}
}
else
{
State.log.WriteLine("Could not connect to LDAP with given username and passwd");
}
}
Since yesterday, this code makes it to the line:
userEntry.Invoke("ChangePassword", new object[] { currentPassword, newPassword });
and then throws the following exception:
[8:37:00 AM] : Password Requirements Met.
[8:37:00 AM] : Connecting LDAP.
[8:37:00 AM] : LDAP Connected, searching directory for SAMAccountName
[8:37:01 AM] : Getting User Entry.
[8:37:01 AM] : Setting Password
[8:37:01 AM] : Failed to reset Windows Password for jason.
Exception has been thrown by the target of an invocation.
The system cannot contact a domain controller to service the authentication request. Please try again later. (Exception from HRESULT: 0x800704F1)
The "force" option using "SetPassword" still works just fine, but the "ChangePassword" method which can be invoked by non-administrator users does not.
Change userPrincipal.ChangePassword("Old pass", "New Pass"); to userPrincipal.SetPassword(model.NewPassword);
I found a work-around and forgot to post it. What I did was use the code above to authenticate the user and then just call my "ForceChangePassword" method:
public static void ForceChangeADPassword(String username, String newPassword)
{
String DN = "";
try
{
DN = GetObjectDistinguishedName(objectClass.user, returnType.distinguishedName, username, DOMAIN_CONTROLLER_IP);
}
catch(Exception e)
{
throw new PasswordException(String.Format("Could not find AD User {0}", username), e);
}
if(DN.Equals(""))
throw new PasswordException(String.Format("Could not find AD User {0}", username));
DirectoryEntry userEntry = new DirectoryEntry(DN.Replace("LDAP://", LdapRootPath), "accounts", AcctPwd);
userEntry.Invoke("SetPassword", new object[] { newPassword });
userEntry.Properties["LockOutTime"].Value = 0;
userEntry.CommitChanges();
userEntry.Close();
}
Earlier this month Microsoft released a security patch, resolving some vulnerabilities in the area of password change. Specifically, the update blocked fallback to NTLM authentication after a failed Kerberos authentication when changing a password.
You might want to read more about the update here.
Microsoft has updated this article: https://support.microsoft.com/en-us/kb/3177108 . Here they have given us problems created by the original "fixes" as well as some tips for working with Kerberos and self-service password reset.
As of October 11, 2016 Microsoft re-released the patches associated with https://technet.microsoft.com/en-us/library/security/ms16-101.aspx to resolve issues caused by the original updates (which you can read in https://support.microsoft.com/en-us/kb/3177108 including the fact that you could no longer change passwords on local accounts).

Failed to connect Salesforce via c#

I am trying to connect Salesforce api via C#. I have reset the security token and added it to the my password then i tried to connect. But login is failed. What am i doing wrong ? Any help would be appriciated.
Login function:
public void sForceLogin(String userName, String password)
{
try
{
currentLoginResult = sForce.login(userName, password);
}
catch (System.Web.Services.Protocols.SoapException ex)
{
Console.WriteLine("An exception has been catched:" + ex.Message);
}
}
Main:
SForceTest sft = new SForceTest();
sft.sForceLogin("example#example.com", "password+securitytoken");
You can use following code to login into salesforce.
using (SforceService service = new SforceService())
{
LoginResult loginResult =
service.login(username, String.Concat(password, securityToken));
this.SessionID = loginResult.sessionId;
this.ServerUrl = loginResult.serverUrl;
}
Salesforce login api requires username, password and the security token.

Using StartTLS with LDAP from System.DirectoryServices

I'm trying to connect to an LDAP server which requires StartTLS, but having no luck - whenever I use either the SessionOptions.StartTransportLayerSecurity(..) or set SessionOptions.SecureSocketLayer to true, I get exceptions.
Here's the code I'm using:
using (var connection = new LdapConnection(new LdapDirectoryIdentifier(config.LdapServer, config.Port, false, false)))
{
connection.SessionOptions.ProtocolVersion = 3;
connection.Credential = new NetworkCredential(config.BindDN, config.BindPassword);
connection.SessionOptions.VerifyServerCertificate += (conn, cert) => {return true;};
connection.AuthType = AuthType.Basic;
//connection.SessionOptions.SecureSocketLayer = true;
connection.SessionOptions.StartTransportLayerSecurity(null); // throws here, same if done after bind.
connection.Bind();
... do stuff with connection
}
The resulting exception is "TlsOperationException: An unspecified error occurred", which happens when invoking the StartTransportLayerSecurity method.
I've tested the code against both and OpenLDAP server and Active Directory, but neither works.
Does anyone know how to get StartTLS working with System.DirectoryServices?
There used to be a fair amount of subtle LDAP stack incompatibilities in the wild, which could still apply to the potentially legacy scenario your customer might be using.
The following are the most commonly encountered issues regarding incompatibilities between OpenLDAP and Microsoft's LDAP stack (I'll amend and/or replace these links once more info is available):
The OpenLDAP StartTLS issues (ITS#3037) (summarized in On getting OpenLDAP and Windows LDAP to interop) have triggered a respective hotfix:
You cannot send Start TLS requests from a computer that is running Windows Server 2003 or Windows XP or Windows Vista to a server that is running OpenLDAP Software
An extended operation that is sent to an LDAP server by API over the LDAP service causes a protocol error
Obviously, updating either OpenLDAP and/or Windows (ideally both of course) should remedy these issues, if they turn out to be the culprit here.
Good luck!
Please read this topic:
Binding over a TLS/SSL Encrypted Connection
Example 19. Binding to an ADAM instance on secure port 50001 using Basic authentication and SSL/TLS
string hostNameAndSSLPort = "sea-dc-02.fabrikam.com:50001";
string userName = "cn=User1,cn=AdamUsers,cn=ap1,dc=fabrikam,dc=com";
string password = "adamPassword01!";
// establish a connection
LdapConnection connection = new LdapConnection(hostNameAndSSLPort);
// create an LdapSessionOptions object to configure session
// settings on the connection.
LdapSessionOptions options = connection.SessionOptions;
options.ProtocolVersion = 3;
options.SecureSocketLayer = true;
connection.AuthType = AuthType.Basic;
NetworkCredential credential =
new NetworkCredential(userName, password);
connection.Credential = credential;
try
{
connection.Bind();
Console.WriteLine("\nUser account {0} validated using " +
"ssl.", userName);
if (options.SecureSocketLayer == true)
{
Console.WriteLine("SSL for encryption is enabled\nSSL information:\n" +
"\tcipher strength: {0}\n" +
"\texchange strength: {1}\n" +
"\tprotocol: {2}\n" +
"\thash strength: {3}\n" +
"\talgorithm: {4}\n",
options.SslInformation.CipherStrength,
options.SslInformation.ExchangeStrength,
options.SslInformation.Protocol,
options.SslInformation.HashStrength,
options.SslInformation.AlgorithmIdentifier);
}
}
catch (LdapException e)
{
Console.WriteLine("\nCredential validation for User " +
"account {0} using ssl failed\n" +
"LdapException: {1}", userName, e.Message);
}
catch (DirectoryOperationException e)
{
Console.WriteLine("\nCredential validation for User " +
"account {0} using ssl failed\n" +
"DirectoryOperationException: {1}", userName, e.Message);
}
And the next example show "How to use TLS to authenticate and perform a task"
string hostOrDomainName = "fabrikam.com";
string userName = "user1";
string password = "password1";
// establish a connection to the directory
LdapConnection connection = new LdapConnection(hostOrDomainName);
NetworkCredential credential =
new NetworkCredential(userName, password, domainName);
connection.Credential = credential;
connection.AuthType = AuthType.Basic;
LdapSessionOptions options = connection.SessionOptions;
options.ProtocolVersion = 3;
try
{
options.StartTransportLayerSecurity(null);
Console.WriteLine("TLS started.\n");
}
catch (Exception e)
{
Console.WriteLine("Start TLS failed with {0}",
e.Message);
return;
}
try
{
connection.Bind();
Console.WriteLine("Bind succeeded using basic " +
"authentication and SSL.\n");
Console.WriteLine("Complete another task over " +
"this SSL connection");
TestTask(hostName);
}
catch (LdapException e)
{
Console.WriteLine(e.Message);
}
try
{
options.StopTransportLayerSecurity();
Console.WriteLine("Stop TLS succeeded\n");
}
catch (Exception e)
{
Console.WriteLine("Stop TLS failed with {0}", e.Message);
}
Console.WriteLine("Switching to negotiate auth type");
connection.AuthType = AuthType.Negotiate;
Console.WriteLine("\nRe-binding to the directory");
connection.Bind();
// complete some action over this non-SSL connection
// note, because Negotiate was used, the bind request
// is secure.
// run a task using this new binding
TestTask(hostName);
After a bit more work on this issue I found that I was running up against a couple of issues:
There was a bug in the code where the port number was being incorrectly changed to the SSL port (636) when connecting to AD in our test suite (doh!).
The OpenLDAP test server (that was a replica of our customers) was using openldap-2.4.18 - which has known issues with StartTLS.
After applying a patch to OpenLDAP (as discussed here - http://www.openldap.org/lists/openldap-bugs/200405/msg00096.html) we were able to fix #2 - at which point we started getting a different error "A local error occurred".
Though originally we had this code:
connection.SessionOptions.VerifyServerCertificate
+= (conn, cert) => {return true;};
We had removed it while testing, and because the OpenLDAP server was using a self-signed cert, that was not in a trusted store. Re-introducing that callback resolved this issue, though we now make it a configurable option i.e. "Verify Server Certificate Y/N" so customers need to opt into skipping the check (mostly for our QA team to use).
Thanks Steffen for pointing me in the direction of OpenLDAP versions which lead me to this solution.

Check email credentials existence

There are dozen of questions asking is smtp server working like Testing SMTP server is running via C# and Can I test SmtpClient before calling client.Send()? and they do they work of checking by sending commands to smtp servers. They never use any credentials for testing purposes. So I'm wondering is there a way to check are these login and password valid on this smtp-server without sending a mail?
My big concern when I was working on this issue is to find a solution where I do not have to send email to check if the credentials are valid or not. So after trying a bunch of the solutions offered online, I came up with my own acceptable one to test email credentials :
I use MailKit to help me out.
public static bool ValidateCredentials(string username, string password, string server, int port, bool certificationValidation)
{
try
{
using (var client = new MailKit.Net.Smtp.SmtpClient())
{
try
{
client.ServerCertificateValidationCallback = (s, c, h, e) => certificationValidation;
client.Connect(server, port, false);
client.Authenticate(username, password);
client.Disconnect(true);
return true;
}
catch (Exception ex)
{
Console.WriteLine(string.Format("ValidateCredentials Exception: {0}", ex.Message));
}
}
}
catch (System.Exception ex)
{
Console.WriteLine(string.Format("ValidateCredentials Exception: {0}", ex.Message));
}
return false;
}
SMTP doesn't allow you login without sending an email.
have a look at the below:
How to validate smtp credentials before sending mail?

Categories