Este tópico mostra como interagir com o Active Directory do Windows através dos Comandos C# do Formulário Dinâmico.
Banco de Dados
Para iniciar, vamos criar uma tabela para gravar os usuários do AD em nosso banco de dados:
CREATE TABLE adusers
(
username VARCHAR(60) NOT NULL,
commonname VARCHAR(255),
displayname VARCHAR(255),
email VARCHAR(100),
CONSTRAINT pk_adusers_usrname PRIMARY KEY (username)
);
Obtendo Usuários
A rotina baixo pode ser chamada em qualquer procedimento do Formulário Dinâmico.
Para isso, clique no botão direito do mouse sobre o procedimento, vá até o menu Ação → Executar Comando C#
O código C# abaixo usa a biblioteca System.DirectoryServices do .NET Framework para acessar as informações do AD. Como essa biblioteca não está referenciada no projeto, ela é chamada via Reflection, usando o método LoadAssembly
do SDK do Latromi para carregar a DLL e o método Activator.CreateInstance(...)
do .NET para instanciar as classes DirectoryEntry
e DirectorySearcher
.
Os campos que serão gravados são:
- Nome de Usuário
- Nome Comum
- Nome de Exibição
O código faz primeiro um UPDATE
. Se nenhum registro foi afetado, então faz um INSERT
.
using System.Reflection;
using System.Collections;
using LATROMI.Extensions;
using System.Data;
// Informar os dados do usuário para autenticar no AD e realizar as operações.
// Preferencialmente um administrador.
string adUser = "usuario_administrador";
string adUserPassword = "senha_do_usuario";
string adUserDomain = "dominio";
// Fully qualified domain name ou FQDN é o nome de domínio que especifica a posição do nó na hierarquia do Domain Name System (DNS).
// Um FQDN é estruturado da seguinte forma: "host.3rd-level-domain.2nd-level-domain.top-level-domain". O número de níveis em um FQDN não é fixo
string adFQDN = "dominio.com.br";
string adUserAndDomain = string.Concat(adUserDomain, @"\", adUser);
string ldapAddress = "LDAP://" + adFQDN;
// Validações
if (string.IsNullOrEmpty(adUser)) throw new InvalidOperationException("Nome de usuário não informado.");
if (string.IsNullOrEmpty(adUserPassword)) throw new InvalidOperationException("Senha de usuário não informada.");
if (string.IsNullOrEmpty(adUserDomain)) throw new InvalidOperationException("Domínio de usuário não informado.");
if (string.IsNullOrEmpty(adFQDN)) throw new InvalidOperationException("FQDN não informado.");
var directoryServicesAssembly = LoadAssembly("System.DirectoryServices.dll");
var directoryEntryType = directoryServicesAssembly.GetType("System.DirectoryServices.DirectoryEntry");
var directorySearchType = directoryServicesAssembly.GetType("System.DirectoryServices.DirectorySearcher");
dynamic directoryEntry = Activator.CreateInstance(directoryEntryType, ldapAddress, adUserAndDomain, adUserPassword);
//Carrega o objeto nativo do AD para forçar a autenticação.
var obj = directoryEntry.NativeObject;
dynamic search = Activator.CreateInstance(directorySearchType, directoryEntry);
search.Filter = "(&(objectClass=user)(objectCategory=person))";
search.PageSize = 100;
var properties = (IList)search.PropertiesToLoad;
// Seleciona as propriedades que serão carregadas
//
properties.Add("cn"); //Common Name
properties.Add("samaccountname");
properties.Add("usergroup");
properties.Add("displayname");//first name
properties.Add("userPrincipalName");
properties.Add("memberOf"); // groups
properties.Add("userAccountControl");
//
// Informações referentes às funções do usuário.
properties.Add("title");
properties.Add("department");
properties.Add("company");
properties.Add("manager");
//
// Informações referente aos contatos do usuário.
properties.Add("telephoneNumber");
properties.Add("mail");
//
// Informações referentes ao endereço do usuário.
properties.Add("streetAddress");
properties.Add("l"); // City
properties.Add("st"); // State
properties.Add("postalCode");
properties.Add("co"); //Country
var searchResultCollection = search.FindAll();
if (searchResultCollection != null)
{
// Abre a conexão
using (var connection = Database.CreateConnection("Teste AD"))
{
// Abre a Conexão
connection.Open();
foreach(object searchResult in searchResultCollection)
{
dynamic resultObj = searchResult;
// Obtém os dados
string username = (string)resultObj.Properties["samaccountname"][0];
string commonName = (string)resultObj.Properties["cn"][0];
// Display Name e Email podem não estar presentes no AD,
// portanto é importante verificar se existe para evitar erros
string displayName = resultObj.Properties.Contains("displayname") == true
? (string)resultObj.Properties["displayname"][0]
: null;
//
string email = resultObj.Properties.Contains("mail") == true
? (string)resultObj.Properties["mail"][0]
: null;
// Salva no banco de dados
var commandParameters = new Dictionary<string, object>
{
["@username"] = username.ToUpper(),
["@commonname"] = commonName,
["@displayname"] = displayName ?? Convert.DBNull,
["@email"] = email ?? Convert.DBNull
};
int affectedRows = connection.ExecuteNonQuery(
"UPDATE adusers SET "+
" commonname = @commonname " +
" , displayname = @displayname " +
" , email = @email " +
" WHERE username = @username", commandParameters);
// Se nenhuma linha foi afetada pelo UPDATE,
// então faz o INSERT do usuario
if (affectedRows <= 0)
{
connection.ExecuteNonQuery(
"INSERT INTO adusers (username, commonname, displayname, email) " +
"VALUES (@username, @commonname, @displayname, @email)", commandParameters);
}
}
}
}
Obtendo um usuário Específico
Para listar todos os usuários, o filtro usando na classe DirectorySearcher
é este:
search.Filter = "(&(objectClass=user)(objectCategory=person))";
Para obter os dados de um usuário específico, sem precisar percorrer todos os outros usuários, basta substituir o filtro por:
search.Filter = "(SAMAccountName=" + "nome_de_usuario" + ")";