使用服务帐户的Active Directory身份验证

时间:2014-12-22 18:05:05

标签: c# web-services active-directory

我正在使用Web Services来针对Active Directory对用户进行身份验证。我目前的解决方案是有效的,但是,我正在尝试采用不同的方法。

我有一个Active Directory(生产),它位于防火墙后面。我还在Active Directory中安装了DMZ。他们之间有单向关系。 DMZ信任生产和生产并不关心DMZ

我想要完成的是通过DMZ Active Directory对每个人进行身份验证。目前,根据用户名,我知道要对哪个AD服务器进行身份验证。

例如,我的生产Active Directory(假设域 domain.local )和我的DMZ Active目录(假设域 domain.public )。在对任何AD服务器进行身份验证之前,我会检查其中一个服务器中是否存在提供的用户名。然后,我检查用户是否处于活动状态,然后才进行身份验证。 (我在第一个函数中遇到问题。它永远不会达到第二个或第三个函数。)

更新:添加所有内容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.DirectoryServices;
using System.Security.Principal;
using System.DirectoryServices.AccountManagement;

namespace ActiveDirectory
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class Service1 : IService1
{
    #region Does User Exist in AD

    public string local = string.Empty;
    public string ldappath = string.Empty;
    public string userNameToUse = string.Empty;
    public string domain = string.Empty;

    public bool DoesUserExist(string userName)
    {
        string _userName = userName;

        bool exist = true;

        using (var domainContext = new PrincipalContext(ContextType.Domain, domain))
        {
            using (var foundUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userNameToUse))
            {
                if (foundUser == null)
                {
                    exist = false;
                }
                else
                {
                    return exist;
                }
            }
        }
        return exist;
    }

    #endregion

    #region Check if User Active
    public bool isActive (string userName)
    {
        string _userNameToBeSearched = userNameToUse;
        string _username = string.Empty;
        string _pwd = string.Empty;

        if (local == "YES")
        {
             _username = "xx";
             _pwd = "xx";
            ldappath = "LDAP://xxx/DC=xx, DC=local";
        }
        else
        {
             _username = "xx";
             _pwd = "xx";
             ldappath = "LDAP://xxx/DC=xx, DC=public";
        }

        bool isActive = true;

        try
        {
            DirectoryEntry entry = new DirectoryEntry(ldappath, _username, _pwd);
            DirectorySearcher search = new DirectorySearcher(entry);
            entry.AuthenticationType = AuthenticationTypes.Secure;
            search.SearchRoot = entry;
            search.Filter = "(SAMAccountName=" + _userNameToBeSearched + ")";

            SearchResult results = search.FindOne();

            if (results.ToString() != "")
            {
                int flags = Convert.ToInt32(results.Properties["userAccountControl"][0].ToString());

                //CHECK IF THE ACCOUNT IS DISABLED
                if (flags == 66050)
                {
                    isActive = false;
                }
            }
        }
        catch (DirectoryServicesCOMException ex)
        {
            ex.ToString();
        }
        return isActive;
    }

    #endregion

    #region Is user authenticated
    public string isAuthenticated (string userName, string pwd)
    {
        string _userName, _pwd, message;
        _userName = userName;
        _pwd = pwd;

        char[] splitchar = { '@' };

        string[] strSplit = _userName.Split(splitchar);

        string z = strSplit[0];

        if (strSplit.Length == 2)
        {
            domain = "x.public";
            userNameToUse = z.ToString();
            local = "NO";
        }
        else
        {
            domain = "x.local";
            userNameToUse = z.ToString();
            local = "YES";
        }

        if (DoesUserExist (userNameToUse) == true)
        {
            if (isActive(userNameToUse) == true)
            {
                try
                {
                    DirectoryEntry entry = new DirectoryEntry(ldappath, userNameToUse, _pwd);
                    object nativeObject = entry.NativeObject;
                    var GUIDID = "";

                    using (var domainContext = new PrincipalContext(ContextType.Domain, domain))
                    {
                        using (var user = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userNameToUse))
                        {
                            if (user != null)
                            {
                                GUIDID = user.Guid.ToString();
                            }
                        }
                        message = "Successfully authenticated:" + GUIDID;
                    }
                }
                catch (DirectoryServicesCOMException)
                {
                    message = "Invalid password.";
                }
            }
            else
            {
                message = "Account is disabled";
            }
        }
        else
        {
            message = "There's an issue with your account.";
        }
        return message;      
    }

    #endregion
}
}

如果DMZ AD中存在用户名,则返回true,否则返回false。但是,将会有用户只存在于生产AD中,但在DMZ中不会有任何条目。从那以后,我建立了一种信任,我应该能够做到这一点:

username@domain.local用于生产和username@domain.public但是,即使我指定完全用户名,如果DMZ AD中不存在条目,它将返回null,尽管它存在于生产AD中。

有关如何使用具有生产AD完全权限的webservices帐户DMZ AD通过{{1}}验证所有人的任何建议吗?

注意如果需要我可以提供剩下的代码...... *

由于

2 个答案:

答案 0 :(得分:0)

PrincipalContext中域的价值是多少?如果您还没有,那么您需要为正在查找用户当前代码的用户使用正确的域名。 PrincipalContext不支持在林中的域之间进行搜索。

以下是使用DirectorySearcher执行此操作的example

答案 1 :(得分:0)

代码有几个问题,我只讨论主要问题。

  1. 在方法DoesUserExist中,您使用服务帐户(没有凭据传递给PrincipalContext)来查询这两个域。但是在方法isActive中,您拥有不同域的不同凭据。所以我们有2个域的3个凭证......

    至少对两种方法使用一致的方法。

  2. 对于单向信任(例如A信托B),B中的帐户应该能够访问域A和B.

    可能您只需将受信任域中的帐户用作服务帐户即可。然后使用服务帐户(null到用户名和密码)来执行所有AD访问。因此,您甚至不需要在代码中输入密码。

  3. isActive中," 66050"来自?
    66060是10202十六进制,表示(1)用户,(2)禁用,(3)不会过期密码。

    要检查帐户是否已启用,请仅检查ACCOUNTDISABLE位(0x0002)。启用时应为0。

  4. 您已在DoesUserExist中获得UserPrincipal。只需查看UserPrincipal.Enabled

  5. 即可启用

    我需要在日常工作中进行代码审查。现在我也在Stack Overflow上做了... :))