Asp.net Active Directory LDAP:尝试过滤到组级别

时间:2014-02-27 15:30:56

标签: asp.net c#-4.0 active-directory ldap

我使用c#在asp.net中创建了一个登录页面,但是我很难尝试只允许某个组访问。现在我正在访问所有人,但我似乎无法过滤我需要的组,因此只有那些人可以访问我的应用程序。

任何帮助都会很棒,所以我可以将此应用程序授权给Active Directory中的那个组。

以下是我用来传递群组的课程:

public class LdapAuthentication
{
    private string _path;
    private string _filterAttribute;

    public LdapAuthentication(string path)
    {
        _path = path;
    }

    public bool IsAuthenticated(string domain, string username, string pwd)
    {
      string domainAndUsername = domain + @"\" + username;
      DirectoryEntry entry = new DirectoryEntry( _path, domainAndUsername, pwd);

      try
      { 
        // Bind to the native AdsObject to force authentication.
        Object obj = entry.NativeObject;
        DirectorySearcher search = new DirectorySearcher(entry);
        search.Filter = "(SAMAccountName=" + username + ")";
        search.PropertiesToLoad.Add("cn");
        SearchResult result = search.FindOne();
        if(null == result)
        {
          return false;
        }
        // Update the new path to the user in the directory
        _path = result.Path;
        _filterAttribute = (String)result.Properties["cn"][0];
      }
      catch (Exception ex)
      {
        throw new Exception("Error authenticating user. " + ex.Message);
      }
      return true;
    }

    public string GetGroups()
    {
        DirectorySearcher search = new DirectorySearcher(_path);
        search.Filter = "(cn=" + _filterAttribute + ")";
        search.PropertiesToLoad.Add("memberOf");
        StringBuilder groupNames = new StringBuilder();
        try
        {
            SearchResult result = search.FindOne();
            int propertyCount = result.Properties["memberOf"].Count;
            String dn;
            int equalsIndex, commaIndex;

            for (int propertyCounter = 0; propertyCounter < propertyCount;
                 propertyCounter++)
            {
                dn = (String)result.Properties["memberOf"][propertyCounter];

                equalsIndex = dn.IndexOf("=", 1);
                commaIndex = dn.IndexOf(",", 1);
                if (-1 == equalsIndex)
                {
                    return null;
                }
                groupNames.Append(dn.Substring((equalsIndex + 1),
                                  (commaIndex - equalsIndex) - 1));
                groupNames.Append("|");
            }
        }
        catch (Exception ex)
        {
            throw new Exception("Error obtaining group names. " +
              ex.Message);
        }
        return groupNames.ToString();
    }

    public bool isMember( String groupname )
    {
        DirectorySearcher search = new DirectorySearcher(_path);
        search.Filter = "(cn=" + _filterAttribute + ")";
        search.PropertiesToLoad.Add("memberOf");
        try
        {
            SearchResult result = search.FindOne();
            int propertyCount = result.Properties["memberOf"].Count;

            for (int propertyCounter = 0; propertyCounter < propertyCount;
                    propertyCounter++)
            {
                String dn = (String)result.Properties["memberOf"][propertyCounter];
                // The comma in the regex is important to prevent accidental matches
                if ( Regex.IsMatch( dn, @"cn="+groupname+",.*", RegexOptions.IgnoreCase))
                    return true;
            }
        }
        catch (Exception ex)
        { 
            // Some logging here probably
        }
        return false;
    }
}

它必须在Get groups功能中,但我不知道如何通过我正在寻找的组。如果有人可以提供帮助,那将非常感激。提前谢谢。

这是我的按钮点击事件:

    protected void btnLogin_Click(object sender, EventArgs e)
    {
        // Path to you LDAP directory server.
        // Contact your network administrator to obtain a valid path.
        string adPath = "LDAP://domain.com";
        LdapAuthentication adAuth = new LdapAuthentication(adPath);
        String myGroupName = "Some_Group";

        try
        {
            if (true == adAuth.IsAuthenticated(txtDomainName.Text, txtLoginID.Text, txtPassword.Text))
            {
                if( adAuth.isMember( myGroupName ) )
                  {
                      // User is authenticated and a member of the group. 
                      // Create your auth ticket, cookie, and whatnot
                      // Retrieve the user's groups
                        string groups = adAuth.GetGroups();
                        // Create the authetication ticket
                        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,  // version
                                                          txtLoginID.Text,
                                                          DateTime.Now,
                                                          DateTime.Now.AddMinutes(60),
                                                          false, groups);
                        // Now encrypt the ticket.
                        string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
                        // Create a cookie and add the encrypted ticket to the 
                        // cookie as data.
                        HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);

                        // Add the cookie to the outgoing cookies collection.
                        Response.Cookies.Add(authCookie);

                        // Redirect the user to the originally requested page
                        //Response.Redirect(FormsAuthentication.GetRedirectUrl(txtLoginID.Text, false));

                        Response.Redirect("LookupEdit.aspx");   
                  }
                  else
                  {
                      lblError.Text = "Authorization failed. You are not a member of the "+myGroupName+" group";
                  }
                }
                else
                {
                  lblError.Text = "Authentication did not succeed. Check user name and password.";
                }
              }
              catch(Exception ex)
              {
                lblError.Text = "Error authenticating. " + ex.Message;
              }
    }

3 个答案:

答案 0 :(得分:0)

我也遇到了这个问题。我使用与进行AD身份验证几乎相同的类。我使用不同的方式连接到AD,但有一些奇怪的问题。在我更改为此代码之前,我实现了角色提供程序,并且我仍然使用该角色提供程序来拒绝和授予访问权限。这就是我基本上做到的。 Follow this link因为它可以帮助您设置角色。

我唯一改变的是“GetRolesForUser”和..

public override string[] GetRolesForUser(string username)
{
    var allRoles = new List();
    var ctx = new PrincipalContext(ContextType.Domain);
    UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
    if (user != null)
    {
       var groups = user.GetGroups();
       allRoles.AddRange(groups.Select(x => x.Name));
    }

    return allRoles.ToArray();
}

这样,您可以在web.config中拒绝并授予组。

我这样做..

<location path="TestPage.aspx">
    <system.web>
      <authorization>
        <allow roles="SoftwareDevelopers" />
        <deny users="*" />
      </authorization>
    </system.web>
 </location>

所以我拒绝所有人访问除了AD组SoftwareDevelopers之外的TestPage.aspx。

我希望这会有所帮助。 编辑:如果您使用注释中的链接来执行此活动目录,获取该组的一种方法是使用登录时创建的身份验证票证。

        if (Request.Cookies["ADAuthCookie"] != null)
        {
            HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);

            string cookiePath = ticket.CookiePath;
            DateTime expiration = ticket.Expiration;
            bool expired = ticket.Expired;
            bool isPersistent = ticket.IsPersistent;
            DateTime issueDate = ticket.IssueDate;
            string name = ticket.Name;
            string userData = ticket.UserData;
            int version = ticket.Version;
            System.Diagnostics.Debug.WriteLine(cookiePath);
            System.Diagnostics.Debug.WriteLine(expiration);
            System.Diagnostics.Debug.WriteLine(expired);
            System.Diagnostics.Debug.WriteLine(isPersistent);
            System.Diagnostics.Debug.WriteLine(issueDate);
            System.Diagnostics.Debug.WriteLine(name);
            System.Diagnostics.Debug.WriteLine(userData);
            System.Diagnostics.Debug.WriteLine(version);

            if (userData.Contains("SoftwareDevelopers"))
            {
                lblMessage.Text = "You're a software developer.";
            }

        }

您必须解密故障单才能读取信息。我已经提供了如何将它写入控制台,以便您可以看到它是如何工作的。如果您愿意,上面提供的if语句是一种限制/显示页面部分的方法。

但是,我发现这个答案中关于如何设置ADRoleProvider的链接可能是你最好的选择。

答案 1 :(得分:0)

您想检查用户是否是正确群组的成员,对吗? 为什么不创建一个接受组名并返回布尔值的函数,如下所示:

public boolean isMember( String username, String groupname )
    {
        DirectorySearcher search = new DirectorySearcher(_path);
        search.Filter = "(cn=" + username + ")";
        search.PropertiesToLoad.Add("memberOf");
        try
        {
            SearchResult result = search.FindOne();
            int propertyCount = result.Properties["memberOf"].Count;

            for (int propertyCounter = 0; propertyCounter < propertyCount;
                 propertyCounter++)
            {
                String dn = (String)result.Properties["memberOf"][propertyCounter];
                // The comma in the regex is important to prevent accidental matches
                if ( Regex.IsMatch( dn, @"cn="+groupname+",.*", RegexOptions.IgnoreCase)
                  return true;
            }
        }
        catch (Exception ex)
        { // Some logging here probably
        }
        return false;
    }

最好的方法是让LDAP通过在搜索中指定组名来进行成员资格迭代。但是,这需要groupname为完整的群组 DN (例如cn=mygroup,ou=groups,dc=xxx,dc=xxx),因此这可能不适合您:

public boolean isMember( String username, String groupdn )
    {
        DirectorySearcher search = new DirectorySearcher(_path);
        // Escaping the input strings is advisable from a security standpoint!
        search.Filter = "(&(cn=" + username + ")(memberOf=" + groupdn + "))";
        search.PropertiesToLoad.Add("cn");
        try
        {
            SearchResult result = search.FindOne();
            // The LDAP server has done the matching for us
            if ( result != null )
               return true;
        }
        catch (Exception ex)
        { // Some logging here probably
        }
        return false;
    }
祝你好运!

答案 2 :(得分:0)

好的,在你的评论之后,这是你应该做的:

在LdapAuthentication类中创建一个isMember(String)函数:

public boolean isMember( String groupname )
{
    DirectorySearcher search = new DirectorySearcher(_path);
    search.Filter = "(cn=" + _filterAttribute + ")";
    search.PropertiesToLoad.Add("memberOf");
    try
    {
        SearchResult result = search.FindOne();
        int propertyCount = result.Properties["memberOf"].Count;

        for (int propertyCounter = 0; propertyCounter < propertyCount;
             propertyCounter++)
        {
            String dn = (String)result.Properties["memberOf"][propertyCounter];
            // The comma in the regex is important to prevent accidental matches
            if ( Regex.IsMatch( dn, @"cn="+groupname+",.*", RegexOptions.IgnoreCase)
              return true;
        }
    }
    catch (Exception ex)
    { // Some logging here probably
    }
    return false;
}

接下来,将其添加为btnlogin_Click代码:

<script runat=server>
void btnlogin_Click(Object sender, EventArgs e)
{
  String adPath = "LDAP://your.domain.com"; //Enter your domain name here
  LdapAuthentication adAuth = new LdapAuthentication(adPath);
  String myGroupName = "auth-group-name"; //Enter your group's name (cn) here
  try
  {
    if(true == adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text))
    {
      if( adAuth.isMember( myGroupName ) )
      {
          // User is authenticated and a member of the group. 
          // Create your auth ticket, cookie, and whatnot
      }
      else
      {
          errorLabel.Text = "Authorization failed. You are not a member of the "+myGroupName+" group";
      }
    }
    else
    {
      errorLabel.Text = "Authentication did not succeed. Check user name and password.";
    }
  }
  catch(Exception ex)
  {
    errorLabel.Text = "Error authenticating. " + ex.Message;
  }
}
</script>

这应该可以帮到你。显然,您应该在isMember()检查后创建一些代码,以创建一个允许其他页面检查用户的身份验证状态的安全cookie。

祝你好运。