Logowanie do AD z Grupami#

Po małym przeszukaniu internetu (głównieCodeProject i ExpertExchange) udało mi się w końcu zrobić logowanie do AD z wykorzystaniem grup (ale tylko tych jawnie wpisanych użytkowników, bez rozwijania grup zagnieżdżonych).

Główny kod programu:

//try autchenitcation
string[] groupsToCheck ={ "cwiczeniowcy", "Asystenci", "operatorzy", "wykladowcy" };

try
{
 //bind to ad
 DirectoryEntry de = new DirectoryEntry("LDAP://dc=pjwstk,dc=edu,dc=pl", TBLogin.Text,  TBHaslo.Text);
 DirectorySearcher mySearcher = new DirectorySearcher(de);
 mySearcher.Filter = ("(&(ObjectCategory=Person)(ObjectClass=user)(SAMAccountName=" + TBLogin.Text  + "))");
 mySearcher.PropertiesToLoad.Add("givenName");
 mySearcher.PropertiesToLoad.Add("sn");
 mySearcher.PropertiesToLoad.Add("Path");
 mySearcher.PropertiesToLoad.Add("primaryGroupId");
 mySearcher.PropertiesToLoad.Add("objectSid");
 SearchResult results = mySearcher.FindOne();
 if (null != results)
 {
  uImie = results.Properties["givenName"][0].ToString();
  uNazwisko = results.Properties["sn"][0].ToString();
  //get user groups
  ArrayList groups = new ArrayList();
  DirectoryEntry obUser = new DirectoryEntry(results.Path);
  object obGroups = obUser.Invoke("Groups");
  foreach (object ob in (IEnumerable)obGroups)
   {
    DirectoryEntry obGpEntry = new DirectoryEntry(ob);
    groups.Add(obGpEntry.Name);
   }
  //get primary group
  int primaryGroupId = (int)results.Properties["PrimaryGroupID"][0];
  byte[] userSid = results.Properties["objectSid"][0] as byte[];
  byte[] primaryGroupSid = BuildPrimaryGroupSID(userSid, primaryGroupId);
  string adsPath = String.Format("LDAP://<SID={0}>", BuildOctetString(primaryGroupSid));
  DirectoryEntry objUser = new DirectoryEntry(adsPath, TBLogin.Text, TBHaslo.Text);
  groups.Add((string)objUser.Properties["name"].Value);
  //check if member is in group
  bool isInGroup =false;
  foreach (string stc in groupsToCheck)
   if (groups.Contains(stc)) isInGroup = true;
  if (isInGroup)
   {
    //Authenticated
   }
  else
  {
   LblError.Text = "Nie masz uprawnien do wypelnienienia ankiety";
  }
 }
  else LblError.Text += "Blad Autoryzacji";
 }
catch (Exception dsce)
{
 LblError.Text = "Blad Autoryzacji";
}
// insertXML(uImie,uNazwisko);

Do tego potrzebujemy jeszcze funkcję do konwersji SIDów

private byte[] BuildPrimaryGroupSID(byte[] userSid, int primaryGroupId)
{
 byte[] rid = BitConverter.GetBytes(primaryGroupId);
 for (int i = 0; i < rid.Length; i++)
 {
  userSid.SetValue(rid[i], new long[] { userSid.Length - (rid.Length - i) });
 }
 return userSid;
}

private string BuildOctetString(byte[] bytes)
{
 StringBuilder sb = new StringBuilder();
 for (int i = 0; i < bytes.Length; i++)
 {
  sb.AppendFormat("{0}", bytes[i].ToString("X2"));
 }
 return sb.ToString();
}

I klasę, która produkuje SID

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Runtime.InteropServices;
using PSID = System.IntPtr;
using HLOCAL = System.IntPtr;
using BOOL = System.Int32;
using HANDLE = System.IntPtr;
using DWORD = System.UInt32;

/// <summary>
/// Summary description for Class1
/// </summary>
public class sid
{
 [DllImport("Advapi32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true,  CharSet = CharSet.Auto)]
 public static extern BOOL ConvertSidToStringSid(PSID Sid, out IntPtr StringSid);

 public unsafe static string UnsafeGetSidString(object sid)
 {
 string sidString = null;
 IntPtr strPtr;
 fixed (byte* psid = (byte[])sid)
  {
   IntPtr psidPtr = (IntPtr)psid;
   BOOL rc = ConvertSidToStringSid(psidPtr, out strPtr);
   Win32.CheckCall(rc);
   try
   {
    sidString = Marshal.PtrToStringAuto(strPtr);
   }
   finally
   {
    Win32.LocalFree(strPtr);
   }
  }
  return sidString;
 }
}
public class Win32
{
 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 public static extern HLOCAL LocalFree(HLOCAL hMem);
 public static void CheckCall(bool funcResult)
 {
  if (!funcResult)
  {
   ThrowLastError();
  }
  }
 public static void CheckCall(BOOL funcResult)
 {
  CheckCall(funcResult != 0);
 }
 public static void CheckCall(HANDLE funcResult)
 {
  CheckCall(!IsNullHandle(funcResult));
 }
 public static DWORD GetLastError()
 {
  return (DWORD)Marshal.GetLastWin32Error();
 }
 public static bool IsNullHandle(HANDLE ptr)
 {
  return (ptr == IntPtr.Zero);
 }
 public static void ThrowLastError()
 {
  Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 }
}

 

Oczywiście w web.config w <system.web> musimy dodać obsługę funkcji typu unsafe:

        <compilation>
            <assemblies>
             <add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
            </assemblies>
            <compilers>
                <compiler language="c#;cs;csharp" extension=".cs" compilerOptions="/unsafe" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            </compilers>
        </compilation>

Tuesday, October 17, 2006 9:33:34 AM (Central European Standard Time, UTC+01:00) #    Comments [2]  |  Trackback

 

All content © 2010, Krzysztof Pietrzak
On this page
This site
Calendar
<July 2010>
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
Archives
Sitemap
Blogroll OPML
  Tokyo by night
blog WiTa
  W-Files
blog n€x¤Ra
 .:fotoblog:.
blog Kfaza
 \\archon\blog$
blog archona
 Czasowstrzymywacz
Blog Fookyego
 Jog Pstryka
Jog Pstryka
 Mac OS X vs. Active Directory
techniczny blog kfaza

Maps
Locations of visitors to this page