11.09.2013

Ищем пользователя в AD из MS SQL

Пока не забыл, запишу здесь. Каждый раз с этим вопросом какая-то непонятная возня происходит.

Задача

Есть корпоративное программное обеспечение (далее - ПО), в котором необходимо сделать аутентификацию пользователей по их логину (Windows Authentication).
Пользователям необходимо назначать персонализированные права.
Пользователям необходимо рассылать e-mail в процессе эксплуатации ПО.

Идея

В базе данных MS SQL создать таблицу со списком пользователей.
Данные о пользователях (account, e-mail, должность, подразделение) подтянуть из корпоративной Active Directory.

Реализация

Запускаем консоль MS SQL (на примере MS SQL 2000)

Подключение ADSI

EXEC master.dbo.sp_addlinkedserver @server = N'ADSI' , @srvproduct=N'Active Directory Service Interfaces' , @provider=N'ADSDSOObject' , @datasrc=N'adsdatasource'

Настройка аутентификации для ADSI

EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'ADSI' ,@useself=N'False' ,@locallogin=NULL ,@rmtuser=N'username' ,@rmtpassword='password'

В качестве username/password используется учетная запись корпоративного пользователя, имеющего право работать с доменом.
Прилинкованный ADSI выглядит следующим образом:
Кстати, прежде чем экспериментировать в консоли, можно запустить замечательную бесплатную программу LDAP Admin
В программе все те же настройки, что и на

Тестовое подключение

Возвращаемся в консоль:

SELECT * FROM OPENQUERY(ADSI,'SELECT cn,sAMAccountName FROM ''LDAP://domainname:port/DC=dc''')

Вот тут все должно заработать
Порт обычно 386 или 3268
DC можно узнать, выбрав в программе LDAP Admin "Fetch DNs" при подключении.
Если не заработало, дальше двигаться смысла нет. Нужно добиваться, что бы заработало.

Настройка запроса

Вытащим список пользователей, совпадающих по началу имени

SELECT * FROM OPENQUERY(ADSI,'SELECT userPrincipalName, cn,title,name,mail,company,department,displayName FROM ''LDAP://domainname:port/DC=dc'' WHERE cn =''Иванов И*'' AND objectClass=''person'' AND objectClass<>''computer''')

Если получилось, совсем замечательно. К сожалению, MS SQL не даст выполнить запрос просто так, если имя пользователя передавать параметрически, так что через exec и добавить немного кавычек:

declare @name nvarchar(150)
set @name='Иванов И*'
exec ('SELECT * FROM OPENQUERY(ADSI,''SELECT userPrincipalName, cn,title,name,mail,company,department,displayName FROM ''''LDAP://domainname:port/DC=dc'''' WHERE cn ='''''+@name+''''' AND objectClass=''''person'''' AND objectClass<>''''computer'''' '')')

Ну и маленькая хитрость.
Если  результат exec вытащить не удается, то можно вернуть результат запроса во временную таблицу внутри exec:

exec ('insert into temp_table (userPrincipalName, cn,title,name,mail,company,department,displayName) SELECT userPrincipalName, cn,title,name,mail,company,department,displayName FROM OPENQUERY(ADSI,...

Теперь Иванова можно найти в AD, если он есть и сразу вытащить его account и e-mail, ну и еще чего записано, что бы жить легче стало.

Всё, вроде ничего не забыл?...