I have two domains(DomainA and DomainB) each in their own AD forests and I have established a forest trust between them,. I am now trying to connect and bind to DomainA and query DomainA for certain attributes of a DomainB user, which is basically a cross domain query.
I am using DirectoryServices.Protocols.LdapConnection and I have set the port to be 636(SSL port) and set the Referral Chasing to ReferralChasingOption.All in C# code. Yet, when the code executes to search the response, I see this error message -
"A referral was returned by the server"
private static LdapConnection getLdapsConnection()
{
LdapConnection connection;
LdapDirectoryIdentifier identifier;
NetworkCredential credential;
try
{
credential = getAdminCredential();
identifier = new LdapDirectoryIdentifier("DomainA.local", 636);
connection = new LdapConnection(identifier, credential)
{
AuthType = AuthType.Basic,
SessionOptions =
{
ProtocolVersion = 3,
SecureSocketLayer = true,
VerifyServerCertificate = new VerifyServerCertificateCallback(true)
}
};
connection.SessionOptions.ReferralChasing = ReferralChasingOptions.All;
return connection;
}
catch (Exception exc)
{
return null;
}
}
public static SearchResponse retrieveUserAttributes(string userName(DomainB_User), List<string> attributesToReturn, LdapConnection connObj)
{
try
{
String filter = "(&(objectCategory=person)(sAMAccountName=" + userName + "))";
String target = "CN=userName,CN=Users,DC=DomainB,DC=local";
SearchRequest searchRequest = new SearchRequest(target, filter, System.DirectoryServices.Protocols.SearchScope.Subtree, attributesToReturn.ToArray());
SearchResponse response = (SearchResponse)connObj.SendRequest(searchRequest);
return response;
}
catch (Exception exc)
{
return null;
}
}
Not sure why the referral error is seen even though referral chasing option is set.
Note:
The same code works perfectly fine for LDAP over 389, this is an issue only for LDAP over ssl for cross domain
Related
I am unable to connect to Active Directory with TLS 1.2 using the DirectoryService class. I am able to connect using TLS 1.2 via LDP on Windows, Open Source LDAPAdmin on Windows and LdapConnection in a .Net 4.7.2 console application. I have verified the TLS 1.2 connections using WireShark. Here is some sample code:
static void Main(string[] args)
{
LdapConnection conn = new LdapConnection("server.domain.com:636");
var op = conn.SessionOptions;
op.ProtocolVersion = 3;
op.SecureSocketLayer = true;
op.VerifyServerCertificate = (ldapConnection, serverCertificate) =>
{
return true;
};
conn.AuthType = AuthType.Negotiate;
var cred = new NetworkCredential("user#domain.com", "password");
conn.Credential = cred;
conn.Bind(cred);
Console.WriteLine("LdapConnection Success");
// Is not TLS 1.2
var de = new DirectoryEntry("LDAP://server.domain.com", "user#domain.com", "password", AuthenticationTypes.Secure);
try
{
foreach (var child in de.Children)
{
Console.WriteLine(child);
}
Console.WriteLine($"{de.Path} Success");
}
catch (Exception ex)
{
Console.WriteLine($"{de.Path} {ex.Message}");
}
//Does not work
de = new DirectoryEntry("LDAP://server.domain.com:636", "user#domain.com", "password");
try
{
foreach (var child in de.Children)
{
Console.WriteLine(child);
}
Console.WriteLine($"{de.Path} Success");
}
catch (Exception ex)
{
Console.WriteLine($"{de.Path} {ex.Message}");
}
//Does not work
de = new DirectoryEntry("LDAP://server.domain.com", "user#domain.com", "password", AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure);
try
{
foreach (var child in de.Children)
{
Console.WriteLine(child);
}
Console.WriteLine($"{de.Path} Success");
}
catch (Exception ex)
{
Console.WriteLine($"{de.Path} {ex.Message}");
}
//Does not work
de = new DirectoryEntry("LDAP://server.domain.com:636", "user#domain.com", "password", AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure);
try
{
foreach (var child in de.Children)
{
Console.WriteLine(child);
}
Console.WriteLine($"{de.Path} Success");
}
catch (Exception ex)
{
Console.WriteLine($"{de.Path} {ex.Message}");
}
Console.ReadKey();
}
Any Idea's how to connect through the DirectoryService class? I have seem many questions about this topic in StackOverflow which is why I included all of the other answers I read about in the sample code.
The correct way to connect via LDAPS with DirectoryEntry is:
e = new DirectoryEntry("LDAP://server.domain.com:636", "user#domain.com", "password");
You don't need to specify AuthenticationTypes.SecureSocketsLayer, since that's the only possible way to connect on port 636, but it also doesn't hurt anything if you do.
My guess is that you have a problem with the certificate. Probably one of two reasons:
The domain name on the certificate does not match the domain name you are using to connect. For example, if you are connecting using the domain name server.domain.com, then the certificate must be issued to (or have a Subject Alternative Name for) server.domain.com. If the domain on the certificate is just domain.com, or just server, then it does not match and it will fail.
The certificate is not issued by an authority that the client computer trusts. It could be self-signed, for example.
It works with LdapConnection because you have this:
op.VerifyServerCertificate = (ldapConnection, serverCertificate) =>
{
return true;
};
That's your custom code for validating the certificate, which always returns true. So any issue with the cert will be ignored. DirectoryEntry does not give you a way to do that.
You can use the PowerShell code in this answer to download the certificate (make sure to change the domain name) and inspect it. Windows will flag an issue with it (if there is one) when you double-click the .cer file.
I'm trying to connect to AWS Cognito from a .net Framework project.
I can sign up succesfully but when I need to sign in, throws me an error: "User pool {userPool} client does not exist".
This is my code:
private async Task<bool> CheckPasswordAsync(string userName, string password)
{
try
{
var authReq = new AdminInitiateAuthRequest
{
UserPoolId = ConfigurationManager.AppSettings["USERPOOL_ID"],
ClientId = ConfigurationManager.AppSettings["CLIENT_ID"],
AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH,
};
authReq.AuthParameters.Add("USERNAME", userName);
authReq.AuthParameters.Add("PASSWORD", password);
AdminInitiateAuthResponse authResp = await _client.AdminInitiateAuthAsync(authReq);
var auts = authResp;
return true;
}
catch(Exception ex)
{
var exc = ex.Message;
return false;
}
}
I don't know if I need to ad more information to the method.
The user pool exists and is the same that I have in appSettings.
Any idea about what's wrong?
Thanks in advance.
I am following this tutorial http://wiki.developerforce.com/page/Integrating_Force.com_with_Microsoft_.NET
However, I am getting this error:
LOGIN_MUST_USE_SECURITY_TOKEN: Invalid username, password, security
token; or user locked out. Are you at a new location? When accessing
Salesforce--either via a desktop client or the API--from outside of
your company’s trusted networks, you must add a security token to your
password to log in. To receive a new security token, log in to
salesforce.com at http://login.salesforce.com and click Setup | My
Personal Information | Reset Security Token.
This is my code in my Console App:
static void Main(string[] args)
{
string userName;
string password;
userName = "me#myWebsite.com";
password = "myPassword";
SforceService SfdcBinding = null;
LoginResult CurrentLoginResult = null;
SfdcBinding = new SforceService();
try
{
CurrentLoginResult = SfdcBinding.login(userName, password);
}
catch (System.Web.Services.Protocols.SoapException e)
{
// This is likley to be caused by bad username or password
SfdcBinding = null;
throw (e);
}
catch (Exception e)
{
// This is something else, probably comminication
SfdcBinding = null;
throw (e);
}
}
The error states I need a security token, but the documentation never seems to mention it and I'm not sure how to get one.
What I had to do (which was not in the documentation) is go to here:
https://na15.salesforce.com/_ui/system/security/ResetApiTokenConfirm?retURL=%2Fui%2Fsetup%2FSetup%3Fsetupid%3DPersonalInfo&setupid=ResetApiToken
And, reset my token. Then, append it to the end of my password like:
If your password = "mypassword"
And your security token = "XXXXXXXXXX"
You must enter "mypasswordXXXXXXXXXX" in place of your password
Ref. http://docs.servicerocket.com/pages/viewpage.action?pageId=83099770
With a SOAP API like this you need to authenticate to the service first by providing the username and password. Their response should return an authorization token that will be valid for a period of time. Then in your subsequent communications you pass this token to the API so that it knows who you are.
Get the authorization token:
SforceService SfdcBinding = null;
LoginResult CurrentLoginResult = null;
SfdcBinding = new SforceService();
try
{
CurrentLoginResult = SfdcBinding.login(userName, password);
}
catch (System.Web.Services.Protocols.SoapException e)
{
// This is likely to be caused by bad username or password
SfdcBinding = null;
throw (e);
}
catch (Exception e)
{
// This is something else, probably communication
SfdcBinding = null;
throw (e);
}
Setup the session:
//Change the binding to the new endpoint
SfdcBinding.Url = CurrentLoginResult.serverUrl;
//Create a new session header object and set the session id to that returned by the login
SfdcBinding.SessionHeaderValue = new SessionHeader();
SfdcBinding.SessionHeaderValue.sessionId = CurrentLoginResult.sessionId;
Perform your query:
QueryResult queryResult = null;
String SOQL = "select FirstName, LastName, Phone from Lead where email = 'john.smith#salesforce.com'";
queryResult = SfdcBinding.query(SOQL);
Creating a web service which talks to Active Directory to verify users and determine which groups they belong to.
I started out with the verification process, and got this working:
public bool AuthenticateAdUser(string username, string password)
{
//in the real code, these come from config
string domain = "TestDomain";
string server = 666.666.666.666;
string authType = "Basic";
string useSsl = "false";
AuthType atype = (AuthType)Enum.Parse(typeof(AuthType), authType);
using (var ldapConnection = new LdapConnection(server))
{
var networkCredential = new NetworkCredential(username, password, domain);
ldapConnection.SessionOptions.SecureSocketLayer = Convert.ToBoolean(useSsl);
ldapConnection.AutoBind = false;
ldapConnection.AuthType = atype;
ldapConnection.Bind(networkCredential);
}
// If the bind succeeds, the credentials are valid
return true;
}
However, I'm not clear on how I can use that LdapConnection object to work with groups. The documentation and examples suggest you use PrinicpalContext for that purpose. So I tried this.
string domain = "TestDomain";
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain))
{
using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(pc, username).GetGroups(pc))
{
src.ToList().ForEach(sr => result.Add(sr.SamAccountName));
}
}
This fails, claiming it can't contact the Active Directory server. Using a DNS style name ("TestDomain.local") doesn't seem to help.
This does at least spin up a network principal:
string server = "666.666.666.666";
using (PrincipalContext pc = new PrincipalContext(ContextType.Machine, server))
{
using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(pc, username).GetGroups(pc))
{
src.ToList().ForEach(sr => result.Add(sr.SamAccountName));
}
}
But when you try and do anything with it, it fails with "Network path not found".
Any ideas on why the Principal won't work, or how I can use the LdapConnection to query groups?
I'd like check the the login and the password match with the AD info. I tried with this piece of coode but I get an exception on FindOne (bad username or password .. but they are correct). I know there is the PrincipalContext solution but I need to be able to set the server (Production, Dev, ...)
Thanks,
var Ad = new DirectoryEntry("LDAP://server1.domain.com", username, password);
var AdSearcher = new DirectorySearcher(Ad);
AdSearcher.Filter = String.Format("(anr={0})", username);
AdSearcher.PropertiesToLoad.Add("sAMAccountName");
AdSearcher.PropertiesToLoad.Add("displayName");
var AdSearcherResults = AdSearcher.FindOne();
var userFullName = AdSearcherResults.Properties["displayName"][0].ToString();
var userUid = AdSearcherResults.Properties["sAMAccountName"][0].ToString();
if (Membership.ValidateUser(username, userUid))
return true;
return false;
Update1 I tried this too :
using (var context = new PrincipalContext(ContextType.Domain, "server1.domain.com"))
{
var isValid = context.ValidateCredentials(username, password);
}
My computer is not connected on the domain but should be work I think.
My code for ActiveDirectory Auth.
public DirectoryEntry connDirectory(string usr, string pwd)
{
string ip = iniMan.IniRead("LDAP", "adres");
DirectoryEntry oDE;
oDE = new DirectoryEntry(ip, usr, pwd, AuthenticationTypes.Secure);
return oDE;
}
public bool AD_Login(string kullanici_adi, string sifre)
{
try
{
DirectoryEntry entLogin = connDirectory(kullanici_adi, sifre);
object loginObj = entLogin.NativeObject;
return true;
}
catch (Exception ex)
{
return false;
}
}
void TestMetod(){
if(AD_Login("ozan","ozan"){
//ok
}
}