Active Directory Sync
- .NET
По долгу службы пришлось разбираться с Active Directory. Пришлось почитать, поэкспериментировать с классами, но всё в результате заработало превосходно.
В первую очередь хотелось бы описать немного Directory Synchronization объект, который появился в .net framework 2.0. О нём, и о других преимуществах 2го framework вы сможете почитать на сайте microsoft (http://msdn.microsoft.com/en-us/magazine/cc188700.aspx ). Лично мне статья помогла разобраться, хотя я обилия информации в сети на предмет dyrSync нет.
Для синхронизации я использую Web-Service, действия происходят следующим образом:
1. Веб сервис получает LDAP путь к запросу.
2. GetSyncData возвращает AD cookie:
Приходится использовать Домен в качестве точки входа, потому как DirSynch работает с корневым элементом дерева. Фильтр может быть в виде: OU=myOU или что-либо в этом роде. В моём случае я достаточно просто обошел эту особенность: создал иерархическую структуру, из которой можно выбрать и LDAP путь до домена, и LDAP путь до данного объекта. Фильтр же – через имя объекта, который нужно синхронизировать.
3. Обратная синхронизация + сверка
Здесь поступайте на своё усмотрение, либо получите bool (есть разница – нет разницы), либо получите дельту в полном объеме.
(Dictionary<string, object> не сериализируется стандартными методами в XML, попробуйте использовать свои массивы с keyvaluepair, либо перепишите сериализацию).
4. Для того, чтобы сохранить всю историю изменений записи, создайте еще одну таблицу, добавьте к ней поле-идентификатор и поставьте триггер на INSERT / UPDATE:
Таким образом получите неплохую историю о каждой из записей, которые синхронизируете. Хотя это – не единственный способ.
спасибо за внимание
з.ы. не судите строго. прежде не блоггил( first experience
В первую очередь хотелось бы описать немного Directory Synchronization объект, который появился в .net framework 2.0. О нём, и о других преимуществах 2го framework вы сможете почитать на сайте microsoft (http://msdn.microsoft.com/en-us/magazine/cc188700.aspx ). Лично мне статья помогла разобраться, хотя я обилия информации в сети на предмет dyrSync нет.
Для синхронизации я использую Web-Service, действия происходят следующим образом:
1. Веб сервис получает LDAP путь к запросу.
[WebMethod]
public void Synchronize (string DomainPath, string Filter, string EntryPath)
{
DirectoryEntry de = new DirectoryEntry (DomainPath);
using (SqlConnection conn = new SqlConnection(Globals.ConnectionString))
{
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = «INSERT INTO SyncTable (Snapshot, OU) VALUES (@Snapshot, @OU, @ExchangeServer)»;
command.Parameters.AddWithValue("@Snapshot", GetSyncData(de, filter));
command.Parameters.AddWithValue(" @OU", EntryPath);
command.ExecuteNonQuery();
conn.Close();
}
}
2. GetSyncData возвращает AD cookie:
public byte[] DirectorySync (DirectoryEntry DomainDE, string Filter)
{
ADInit.Init();
try
{
using (DirectorySearcher srch = new DirectorySearcher(DomainDE, Filter))
{
srch.SearchScope = SearchScope.Base;
srch.DirectorySynchronization = new DirectorySynchronization();
foreach (SearchResult se in srch.FindAll())
{
}
MemoryStream ms = new MemoryStream();
BinaryFormatter bFormat = new BinaryFormatter();
bFormat.Serialize(ms, srch.DirectorySynchronization.GetDirectorySynchronizationCookie());
ms.Close();
return ms.GetBuffer();
}
}
catch (Exception Ex)
{
throw Ex;
}
}
Приходится использовать Домен в качестве точки входа, потому как DirSynch работает с корневым элементом дерева. Фильтр может быть в виде: OU=myOU или что-либо в этом роде. В моём случае я достаточно просто обошел эту особенность: создал иерархическую структуру, из которой можно выбрать и LDAP путь до домена, и LDAP путь до данного объекта. Фильтр же – через имя объекта, который нужно синхронизировать.
3. Обратная синхронизация + сверка
[WebMethod]
public bool GetRegionEntry (string Domain, string Filter, string EntryPath)
{
DirectoryEntry de = new DirectoryEntry (Domain);
RegionInfo _regionInfo = regionEntry.GetEntry();
using (SqlConnection conn = new SqlConnection(Globals.ConnectionString))
{
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = «SELECT * FROM SyncTable WHERE OU= @OU»;
command.Parameters.AddWithValue(" @OU", EntryPath);
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
return regionEntry.GetSyncDelta(de, Filter, (byte[])reader[«Snapshot»]);
}
else
{
throw new Exception (“Can’t read Sync Cookie from Database!”);
}
conn.Close();
}
return _regionInfo;
}
Здесь поступайте на своё усмотрение, либо получите bool (есть разница – нет разницы), либо получите дельту в полном объеме.
///public Dictionary<string, object> GetSyncDelta (DirectoryEntry DomainDE, string Filter, byte[] _cookie)
public bool GetSyncDelta (DirectoryEntry DomainDE, string Filter, byte[] _cookie)
{
Dictionary<string, object> _delta = new Dictionary<string, object>();
BinaryFormatter bf = new BinaryFormatter();
byte[] cookie = (byte[]) bf.Deserialize(new MemoryStream(_cookie));
DirectorySynchronization dirSync = new DirectorySynchronization(cookie);
DirectorySearcher srch = new DirectorySearcher(DomainDE, Filter);
srch.DirectorySynchronization = dirSync;
foreach(SearchResult sr in srch.FindAll())
{
foreach (string attrName in sr.Properties.PropertyNames)
{
_delta.Add( attrName, sr.Properties[attrName]);
}
return true;
}
return false;
//return _delta;
}
(Dictionary<string, object> не сериализируется стандартными методами в XML, попробуйте использовать свои массивы с keyvaluepair, либо перепишите сериализацию).
4. Для того, чтобы сохранить всю историю изменений записи, создайте еще одну таблицу, добавьте к ней поле-идентификатор и поставьте триггер на INSERT / UPDATE:
ALTER TRIGGER [SyncTableTrg]
ON [dbo].[SyncTable]
AFTER INSERT, UPDATE
AS
BEGIN
INSERT INTO SyncTableLog (OU, Snapshot)
SELECT OU, Snapshot FROM inserted
END
Таким образом получите неплохую историю о каждой из записей, которые синхронизируете. Хотя это – не единственный способ.
спасибо за внимание
з.ы. не судите строго. прежде не блоггил( first experience