如何使用System.DirectoryServices.Protocol验证用户名/密码



首先,我不能使用Active Directory,所以我不能直接使用System.DirectoryServices。这将是一台 PC 向仅支持 Novell 网络的 Novell 网络发送查询,其中仅支持 System.DirectoryServices.Protocol

我很确定我需要提供正确的搜索请求。

这是我到目前为止所拥有的:

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;
}

如何创建搜索请求来验证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;
}

来源:

  • 如何通过 LDAP + SSL 验证 Active Directory 信条?
  • 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
<小时 />

论中篇小说

DirectoryEntry 和 DirectorySearcher 都是高级类工具,是 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;
}

参考答案。

最新更新