Use Global Catalog and CheckTokenMembership to check if a caller is in an AD group

/*
 *  Active Directory has a global catalog (GC), which contains a partial replica of all objects 
 *  in the directory. It also contains partial replicas of the schema and configuration containers. 
 *  One or more domain controllers in a domain can hold a copy of the global catalog.
 * 
 *  The global catalog holds a replica of every object in Active Directory, but with only a small 
 *  number of their attributes. The attributes in the global catalog are those most frequently used 
 *  in search operations, such as a user's first and last names, login names, and so on. The global 
 *  catalog attributes also include those required to locate a full replica of the object. The 
 *  global catalog allows users to quickly find objects of interest without knowing what domain 
 *  holds them and without requiring a contiguous extended namespace in the enterprise; that is, 
 *  you can search the entire forest.
 * 
 *  The following sample code demonstrates a way to check if a caller is in a perticular security 
 *  group. It searches the global catalog to obtain the group's SID(Security Id), and then call 
 *  CheckTokenMembership to find out if the caller is in that group. It is very useful when a service 
 *  process need to check a caller's membership for authentication or authorization. 
 *   
 *  In real applications, you may need to cache the SIDs of the groups for better performance since
 *  searching the global catalog is fast, but not that fast.
 * 
 * 
 *  -- DavidM, Dalun Software, Nov.28, 2004  All rights reserved.
 * 
 *  * 
 * */
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.DirectoryServices;
using System.Security.Principal;
using System.Runtime.InteropServices;

namespace IsInGroup
{
    /// 
    /// Summary description for Class1.
    /// 
    class Class1
    {

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        static extern int CheckTokenMembership(int TokenHandle, byte[] PSID, out bool IsMember);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        static extern bool IsValidSid(byte[] PSID);

        public static string GetCallerName()
        {
            WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
            return principal.Identity.Name.Split('\\')[1];
        }

        /// 
        /// The main entry point for the application.
        /// 
        static void Main(string[] args)
        {
            string groupName = "administrators";

            //get current caller's information
            string user = GetCallerName();

            //search global catalog and get SID of the group
            Byte[] sid = null;

            DirectoryEntry entry = new DirectoryEntry("GC:");
            IEnumerator ie = entry.Children.GetEnumerator();
            ie.MoveNext();
            DirectorySearcher ds = new DirectorySearcher((DirectoryEntry)ie.Current);

            string sam = "(sAMAccountName=" + groupName + ")";
            ds.Filter = "(&(|" + sam + ")(objectClass=group))";
            using (SearchResultCollection resColl = ds.FindAll())
            {
                if (resColl.Count > 0)
                {
                    ResultPropertyCollection resultPropColl = resColl[0].Properties;
                    string name = (string)resultPropColl["name"][0];
                    string adsPath = (string)resultPropColl["adspath"][0];
                    sid = (byte[])resultPropColl["objectsid"][0];

                    if (sid == null || !IsValidSid(sid))
                    {
                        System.Console.WriteLine("Invalid SID for the group.");
                        return;
                    }
                    else
                    {
                        System.Console.WriteLine("Group found: " + name);
                        System.Console.WriteLine("Group ADS path: " + adsPath);
                    }
                }
                else
                {
                    System.Console.WriteLine("Required info was not found in the Global Catalog.");
                    return;
                }
            }

            bool bIsMember = false;
            if (CheckTokenMembership(0, sid, out bIsMember) == 0)
            {
                System.Console.WriteLine("Failed to call CheckTokenMembership.");
            }
            else
            {
                System.Console.WriteLine(user + (bIsMember ? " is a member of " : " isn't a member of ") + groupName);
            }
        }
    }
}

    

Some other samples on MSDN

Using System.DirectoryServices

See also

  • SQL: Use Dynamic SQL Query Correctly
  • SQL 2005: Use DMV and CROSS APPLY to Get Cached Plans
  • SQL 2005: Discontinued or Deprecated Features in SQL Server 2005
  • SQL 2005: Default Trace Enabled Option
  • SQL 2005: Column Level Permissions
  • SQL 2005: SQLCMD Supports Parameterized Variables and Macro Features
  • SQL 2005: DTS Has Become SSIS now
  • SQL 2005: Microsoft SQL Server 2005 JDBC Driver
  • SQL 2005: Query Notifications in ADO.Net 2.0
  • SQL 2005: Overcome SQL Index Size Limit
  • SQL 2005: DDL Triggers
  • SQL 2005: Why Should Use 64 Bit Now
  • SQL 2005: How to Rebuild The Master Database
  • SQL 2005: A Little Trick to Install SQL 2005 Onto Your Dirty DEV Machine
  • SQL 2005: New Resource Database
  • SQL 2005: Alter Index Rebuild
  • SQL 2005: XQuery Sample
  • SQL 2005: How to Move Database
  • SQL: Use COALESCE to Generate a List
  • SQL: How to Debug SQL Deadlocks
  • .Net: How to Bypass Strong Name Check
  • Agile: Lean Software Development - An Agile Toolkit
  • ORM: How to Use nHibernate 1.2 to Call Stored Procedure to Return a Dataset Without a Mapping Entity
  • AJAX: ASP.NET AJAX Tips
  • .Net: Debugging Commands
  • .Net: How to Run NUnit And Debug Your Test Fixtures Directly from VS 2005
  • .Net: How to Add Domain User to Local Group
  • .Net: Lock Value Type?
  • .Net: How to Create an Instance of a Generic Type with Parameters
  • .Net: How to Get Address of a Managed Type
  • ORM: New Features of nHibernate 1.2
  • .Net: How to Get System Error Message from HRESULT in Managed Code
  • .Net: Use Windows PowerShell Now
  • WMI: Use WMI to Run Commands on Remote Machine
  • API: GetLogicalProcessorInformation to Detect CPUs
  • .Net: How to Implement Singleton Correctly
  • .Net: There is no MTS object context (Exception from HRESULT: 0x8004E004)
  • .Net: The Net Objectives Pattern Repository
  • Web: Access Denied When ASP.Net Accesses Eventlog
  • Nant: Error Loading GUID of Project
  • AJAX: Ajax in Action
  • DTC: DtcGetTransactionManager Fails
  • .Net: Run .Net 1.1 COM+ Serviced Components Under .Net 2.0 Framework
  • .Net: Debugging Managed Code Tip
  • .Net: Assembly Binding Log Viewer (Fuslogvw.exe)
  • .Net: .Net Framework Design Guidelines
  • .Net: Use Global Catalog and CheckTokenMembership to Check AD Group Membership



  • THIS POST IS PROVIDED "AS-IS" WITH NO WARRANTIES AND CONFERS NO RIGHTS. Build time: Sun 03/30/2008 . ©2007 Dalun Software. All rights reserved. Back to Article List