我如何使用 System.DirectoryServices.Protocol 验证 Username/Password?
How would I validate a Username/Password using System.DirectoryServices.Protocol?
首先,我不能使用Active Directory,所以我不能直接使用System.DirectoryServices
。这将是一台 PC 向仅支持 System.DirectoryServices.Protocol
的 Novell 网络发送查询。
我很确定我需要提供正确的 SearchRequest。
这是我目前拥有的:
private static String _certificatePath;
private static String _server;
private static SearchResponse Query(String user, String pwd, out String error)
{
SearchResponse result = null;
error = String.Empty;
if (File.Exists(_certificatePath))
{
var identifier = new LdapDirectoryIdentifier(_server, false, false);
try
{
using (var connection = new LdapConnection(identifier))
{
connection.SessionOptions.ProtocolVersion = 3;
var cert = new X509Certificate();
cert.Import(_certificatePath, null, X509KeyStorageFlags.DefaultKeySet);
connection.ClientCertificates.Add(cert);
connection.AuthType = AuthType.External;
connection.AutoBind = false;
var request = new SearchRequest()
{
DistinguishedName = user, //Find this person
Filter = "(objectClass=*)", //The type of entry we are looking for
Scope = System.DirectoryServices.Protocols.SearchScope.Subtree, //We want all entries below this ou
};
result = (SearchResponse)connection.SendRequest(request); //Run the query and get results
}
} catch (Exception err)
{
error = String.Format("SDSP::Query {0}: {1}", err.GetType(), err.Message);
}
}
else
{
error = "The system cannot find the Cryptography Certificate at the path specified in the Application Configuration file.";
}
return result;
}
如何创建 SearchRequest 来验证 user
/ pwd
组合?
var request = new SearchRequest()
{
DistinguishedName = user, //Find this person
Filter = "(objectClass=*)", //The type of entry we are looking for
Scope = System.DirectoryServices.Protocols.SearchScope.Subtree, //We want all entries below this ou
};
让我向您展示我为实现此验证所做的最佳尝试,也许它对您有用。
在我的上下文中,这不起作用,因为我的管理员用户无法读取属性 "userPassword",我也不知道为什么。我想是没有分配某些权限。
无论如何,这是代码,希望对您有所帮助:
var server = "<SERVER:PORT>";
var adminUser = "<USERNAME>";
var adminPass = "<PASSWORD>";
using (var ldap = new LdapConnection(server))
{
ldap.SessionOptions.ProtocolVersion = 3;
// To simplify this example I'm not validating certificate. Your code is fine.
ldap.SessionOptions.VerifyServerCertificate += (connection, certificate) => true;
ldap.SessionOptions.SecureSocketLayer = true;
ldap.AuthType = AuthType.Basic;
ldap.Bind(new System.Net.NetworkCredential($"cn={adminUser},o=<ORGANIZATION>", adminPass));
// Now I will search to find user's DN.
// If you know exact DN, then you don't need to search, go to compare request directly.
var search = new SearchRequest
{
//Here goes base DN node to start searching. Node closest to entry improves performance.
// Best base DN is one level above.
DistinguishedName = "<BASEDN>", //i.e.: ou=users,o=google
Filter = "uid=<USERNAME>",
Scope = SearchScope.OneLevel
};
// Adding null to attributes collection, makes attributes list empty in the response.
// This improves performance because we don't need any info of the entry.
search.Attributes.Add(null);
var results = (SearchResponse)ldap.SendRequest(search);
if (results.Entries.Count == 0)
throw new Exception("User not found");
// Because I'm searching "uid" can't exists more than one entry.
var entry = results.Entries[0];
// Here I use DN from entry found.
var compare = new CompareRequest(entry.DistinguishedName, new DirectoryAttribute("userPassword", "<PASSWORD>"));
var response = (CompareResponse)ldap.SendRequest(compare);
if (response.ResultCode != ResultCode.CompareTrue)
throw new Exception("User and/or Password incorrect.");
}
在 Windows
您可以为 ValidateCredentials
(用户名和密码)附加 ContextOptions.Negotiate
参数。
const int ldapErrorInvalidCredentials = 0x31;
const string server = "sd.example.com:636";
const string domain = "sd.example.com";
try
{
using (var ldapConnection = new LdapConnection(server))
{
var networkCredential = new NetworkCredential(_username, _password, domain);
ldapConnection.SessionOptions.SecureSocketLayer = true;
ldapConnection.AuthType = AuthType.Negotiate;
ldapConnection.Bind(networkCredential);
}
// If the bind succeeds, the credentials are valid
return true;
}
catch (LdapException ldapException)
{
// Invalid credentials throw an exception with a specific error code
if (ldapException.ErrorCode.Equals(ldapErrorInvalidCredentials))
{
return false;
}
throw;
}
来源:
- How do I validate Active Directory creds over LDAP + SSL?
- https://msdn.microsoft.com/en-us/library/bb300969(v=vs.110).aspx
- https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.contextoptions(v=vs.110).aspx
在 Novell 上
DirectoryEntry and DirectorySearcher 都是高级 class 工具,是 Active Directory 的包装器。
//use the users credentials for the query
DirectoryEntry root = new DirectoryEntry(
"LDAP://dc=domain,dc=com",
loginUser,
loginPassword
);
//query for the username provided
DirectorySearcher searcher = new DirectorySearcher(
root,
"(sAMAccountName=" + loginUser + ")"
);
//a success means the password was right
bool success = false;
try {
searcher.FindOne();
success = true;
}
catch {
success = false;
}
简称answer。
首先,我不能使用Active Directory,所以我不能直接使用System.DirectoryServices
。这将是一台 PC 向仅支持 System.DirectoryServices.Protocol
的 Novell 网络发送查询。
我很确定我需要提供正确的 SearchRequest。
这是我目前拥有的:
private static String _certificatePath;
private static String _server;
private static SearchResponse Query(String user, String pwd, out String error)
{
SearchResponse result = null;
error = String.Empty;
if (File.Exists(_certificatePath))
{
var identifier = new LdapDirectoryIdentifier(_server, false, false);
try
{
using (var connection = new LdapConnection(identifier))
{
connection.SessionOptions.ProtocolVersion = 3;
var cert = new X509Certificate();
cert.Import(_certificatePath, null, X509KeyStorageFlags.DefaultKeySet);
connection.ClientCertificates.Add(cert);
connection.AuthType = AuthType.External;
connection.AutoBind = false;
var request = new SearchRequest()
{
DistinguishedName = user, //Find this person
Filter = "(objectClass=*)", //The type of entry we are looking for
Scope = System.DirectoryServices.Protocols.SearchScope.Subtree, //We want all entries below this ou
};
result = (SearchResponse)connection.SendRequest(request); //Run the query and get results
}
} catch (Exception err)
{
error = String.Format("SDSP::Query {0}: {1}", err.GetType(), err.Message);
}
}
else
{
error = "The system cannot find the Cryptography Certificate at the path specified in the Application Configuration file.";
}
return result;
}
如何创建 SearchRequest 来验证 user
/ pwd
组合?
var request = new SearchRequest()
{
DistinguishedName = user, //Find this person
Filter = "(objectClass=*)", //The type of entry we are looking for
Scope = System.DirectoryServices.Protocols.SearchScope.Subtree, //We want all entries below this ou
};
让我向您展示我为实现此验证所做的最佳尝试,也许它对您有用。
在我的上下文中,这不起作用,因为我的管理员用户无法读取属性 "userPassword",我也不知道为什么。我想是没有分配某些权限。
无论如何,这是代码,希望对您有所帮助:
var server = "<SERVER:PORT>";
var adminUser = "<USERNAME>";
var adminPass = "<PASSWORD>";
using (var ldap = new LdapConnection(server))
{
ldap.SessionOptions.ProtocolVersion = 3;
// To simplify this example I'm not validating certificate. Your code is fine.
ldap.SessionOptions.VerifyServerCertificate += (connection, certificate) => true;
ldap.SessionOptions.SecureSocketLayer = true;
ldap.AuthType = AuthType.Basic;
ldap.Bind(new System.Net.NetworkCredential($"cn={adminUser},o=<ORGANIZATION>", adminPass));
// Now I will search to find user's DN.
// If you know exact DN, then you don't need to search, go to compare request directly.
var search = new SearchRequest
{
//Here goes base DN node to start searching. Node closest to entry improves performance.
// Best base DN is one level above.
DistinguishedName = "<BASEDN>", //i.e.: ou=users,o=google
Filter = "uid=<USERNAME>",
Scope = SearchScope.OneLevel
};
// Adding null to attributes collection, makes attributes list empty in the response.
// This improves performance because we don't need any info of the entry.
search.Attributes.Add(null);
var results = (SearchResponse)ldap.SendRequest(search);
if (results.Entries.Count == 0)
throw new Exception("User not found");
// Because I'm searching "uid" can't exists more than one entry.
var entry = results.Entries[0];
// Here I use DN from entry found.
var compare = new CompareRequest(entry.DistinguishedName, new DirectoryAttribute("userPassword", "<PASSWORD>"));
var response = (CompareResponse)ldap.SendRequest(compare);
if (response.ResultCode != ResultCode.CompareTrue)
throw new Exception("User and/or Password incorrect.");
}
在 Windows
您可以为 ValidateCredentials
(用户名和密码)附加 ContextOptions.Negotiate
参数。
const int ldapErrorInvalidCredentials = 0x31;
const string server = "sd.example.com:636";
const string domain = "sd.example.com";
try
{
using (var ldapConnection = new LdapConnection(server))
{
var networkCredential = new NetworkCredential(_username, _password, domain);
ldapConnection.SessionOptions.SecureSocketLayer = true;
ldapConnection.AuthType = AuthType.Negotiate;
ldapConnection.Bind(networkCredential);
}
// If the bind succeeds, the credentials are valid
return true;
}
catch (LdapException ldapException)
{
// Invalid credentials throw an exception with a specific error code
if (ldapException.ErrorCode.Equals(ldapErrorInvalidCredentials))
{
return false;
}
throw;
}
来源:
- How do I validate Active Directory creds over LDAP + SSL?
- https://msdn.microsoft.com/en-us/library/bb300969(v=vs.110).aspx
- https://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.contextoptions(v=vs.110).aspx
在 Novell 上
DirectoryEntry and DirectorySearcher 都是高级 class 工具,是 Active Directory 的包装器。
//use the users credentials for the query
DirectoryEntry root = new DirectoryEntry(
"LDAP://dc=domain,dc=com",
loginUser,
loginPassword
);
//query for the username provided
DirectorySearcher searcher = new DirectorySearcher(
root,
"(sAMAccountName=" + loginUser + ")"
);
//a success means the password was right
bool success = false;
try {
searcher.FindOne();
success = true;
}
catch {
success = false;
}
简称answer。