29 Janeiro 2016

Obter Utilizadores e Grupos da Active Directory numa solução de SQL Server Integration Services

Em projetos de desenvolvimento de Business Intelligence existe, normalmente, a necessidade de configurar segurança nos acessos aos dados por parte de utilizadores e/ou grupos. Um exemplo é a restrição de membros em dimensões nos cubos em Analysis Services. Nestes casos, uma solução possível passa por definir e carregar uma tabela para mapeamento entre utilizadores e os membros de dimensões a restringir.

Num dos nossos projetos, foi necessário carregar os grupos e respetivos utilizadores diretamente da Active Directory. Assim, os grupos deveriam estar localizados numa diretoria da AD previamente definida.

O objetivo era implementar um dtsx que extraísse esta informação da AD e que a carregasse numa tabela temporária para posteriormente ser tratada nos restantes processos do Datawarehouse. Na maioria dos casos, quando queremos transferir dados de uma base de dados relacional ou ficheiro, usamos o componente de Data Flow Task. Neste caso vamos dispensar esse componente e usar um Script Task.

Através deste componente é possível implementar código em C# com base no namespace AccountManagement da Framework .Net (3.5 ou superior). Este namespace permite pesquisar e manusear utilizadores e grupos na AD de forma mais simples do que o namespace DirectoryServices já existente em versões mais antigas da framework, onde era necessário um conhecimento mais extenso dos métodos e utilização bem como implicava escrever código mais longo.

No excerto do código C# que se segue, que está inserido na Script Task, num primeiro passo queremos identificar os grupos numa determinada organization Unit (OU) onde é suposto estarem inseridos os grupos, cujos utilizadores membros devem ser extraídos no processo. Nesta parte do código realizam-se os passos para fazer a pesquisa.

//Cria o contexto sobre o qual a pesquisa é feita. Os primeiros dois parâmetros são usados para definir o domínio e o terceiro é utilizado para definir a localização dentro da AD onde será feita a pesquisa.

PrincipalContext ouContext = new PrincipalContext(ContextType.Domain, “domain.com”, “OU=BIGroups,DC=domain,DC=com”);

//Cria um objeto GroupProncial que será usado como filtro na pesquisa na seguinte linha de código. Recebe o contexto de domínio a aplicar na pesquisa bem como o SamAccountName (nome único na AD) a pesquisar. Neste caso, utilizado o *, serão retornados todos os grupos existentes.

GroupPrincipal allGroupsInContext = new GroupPrincipal(ouContext, “*”);

//Instância do objeto que encapsula os métodos e padrões de pesquisa a executar no contexto especificado.

PrincipalSearcher ps = new PrincipalSearcher(allGroupsInContext);

//Executa a pesquisa. O resultado é uma coleção de objetos Principal (utilizadores ou grupos) que resultam da pesquisa.

PrincipalSearchResult<Principal> groupResults = ps.FindAll();

No segundo passo, o resultado da pesquisa é traduzido em utilizadores e respetivos grupos. É utilizado o objeto DataTable para preencher uma tabela com os dados enquanto o resultado da pesquisa é iterado. Finalmente, depois de todos os utilizadores estarem carregados na tabela em memória, os dados são inseridos na base de dados em Sql Server através da classe SqlBulkCopy.

//Cria o objeto DataTable para armazenar temporariamente os utilizadores e respetivo grupo da AD.

DataTable table = new DataTable();

table.Columns.Add(“User”, typeof(string));

table.Columns.Add(“Name”, typeof(string));

table.Columns.Add(“Email”, typeof(string));

table.Columns.Add(“Group”, typeof(string));

//Itera sobre os grupos na OU especificada na pesquisa

foreach (var group in groupResults)

{

    GroupPrincipal gr = (GroupPrincipal)group;

    //Obtém todos os membros de um determinado grupo

    PrincipalSearchResult<Principal> userResults = gr.GetMembers();

    //Itera sobre todos os membros existente dentro do grupo

    foreach (Principal result in userResults)

    {

        //Estamos a pesquisar utilizadores apenas. O resto é ignorado (ex: grupos dentro do grupo)

        if (result.StructuralObjectClass == “user”){

            UserPrincipal user = (UserPrincipal)result;

            //Guarda no datatable o utilizador

            table.Rows.Add(user.SamAccountName, user.Name, user.EmailAddress, group.Name);

        }

    }

}

//Transfere os dados para uma tabela em Sql Server

using (SqlConnection conn = new SqlConnection(“Connection”))

{

    conn.Open();

    SqlBulkCopy bulk = new SqlBulkCopy(conn);

    bulk.DestinationTableName = “StagingTable”;

    bulk.WriteToServer(table);

}

Desta forma temos uma solução simples para extrair utilizadores da Active Directory sem ser necessário ter um conhecimento profundo da AD e interfaces de acesso. A utilização do namespace .Net e criação de algumas linhas em C# revelou ser uma forma bastante simples de pesquisar e obter a informação de utilizadores e grupos.

Este é um exemplo para um problema específico no nosso projeto, contudo, existem outras operações que se podem fazer no que diz respeito a aceder e manipular utilizadores e grupos através de classes do mesmo namespace.

Existem ainda outras formas de processar informação da Active Directory num pacote em SSIS (se quisermos evitar escrever código em .Net) e que permite usar outros componentes nativos do SSIS, como o Data Flow Task como explicado no seguinte artigo. Contudo, na minha opinião, não é tão simples, intuitivo e flexível como recorrendo ao ScriptTask e namespace .Net descritos neste exemplo.

 

 .
.
.
.
.
.
    João Cordeiro
       Consultant