简体   繁体   English

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

[英]How would I validate a Username/Password using System.DirectoryServices.Protocol?

First, I cannot use Active Directory , so I cannot use System.DirectoryServices directly. 首先,我不能使用Active Directory ,所以我不能直接使用System.DirectoryServices This will be a PC sending a query to a Novell network where only System.DirectoryServices.Protocol is supported. 这将是一台PC向Novell网络发送查询,其中仅支持System.DirectoryServices.Protocol

I am pretty sure that I am down to needing to provide the proper SearchRequest. 我很确定我需要提供正确的SearchRequest。

This is what I have so far: 这是我到目前为止:

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

How do I create a SearchRequest to validate a user / pwd combination? 如何创建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
};

Let me show you my very best attempt to achieve this validation, maybe it will works for you. 让我告诉你我最好的尝试来实现这个验证,也许它会对你有用。

In my context this doesn't work because my admin user can't read attribute "userPassword" and I can't figure why. 在我的上下文中这不起作用,因为我的管理员用户无法读取属性“userPassword”,我无法弄清楚原因。 I guess is some permission not assigned. 我猜是没有分配一些许可。

Anyway this is the code, hope it helps: 无论如何这是代码,希望它有所帮助:

        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.");
        }

On Windows 在Windows上

You can append ContextOptions.Negotiate parameter for ValidateCredentials (Username and Password). 您可以为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;
}

Sources: 资料来源:


On Novell 在Novell上

DirectoryEntry and DirectorySearcher are both high level class tools that are wrappers for Active Directory. DirectoryEntryDirectorySearcher都是高级类工具,它们是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;
}

Referred to the answer . 提到了答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM