.NET - Acessando o Active Directory


Antes de iniciar o artigo é bom rever alguns conceitos básicos como Active Directory, LDAP, domínio,etc. Vamos lá...

O Active Directory (AD) é uma implementação de serviço de diretório no protocolo LDAP (Lightweight Directory Access Protocol) que armazena informações sobre objetos em uma rede e disponibiliza essas informações a usuários e administradores desta rede. (Pense no AD como um banco de dados hierárquico orientado a objetos que representa todos os seus recursos de rede.)

O LDAP é um protocolo para atualizar e pesquisar diretórios rodando sobre TCP/IP e segue o modelo de árvore de nós, onde cada nó representa um conjunto de atributo com seus valores. O LDAP é uma alternativa ao DAP - Directory Access Protocol .

Um Serviço de Diretório é um serviço de rede que identifica todos os recursos disponíveis em uma rede e mantém informações sobre estes dispositivos (contas de usuários, grupos, computadores, recursos, políticas de segurança etc.) em um banco de dados tornando estes recursos disponíveis para usuários e aplicações.

Um diretório é um banco de dados com informações sobre usuários, senhas, recursos e outros elementos necessários ao funcionamento de um sistema.

Um domínio pode ser visto como um conjunto de servidores, estações de trabalho, bem como as informações do diretório. Todos os servidores que contém uma cópia da base de dados do Active Directory fazem parte do domínio.

Desta forma, se o seu servidor Web é um membro de um domínio de um Active Directory você pode obter e até atualizar suas informações no Active Directory via código.

A plataforma .NET possui um diversas classes no namespace System.DirecotryServices (Active Directory Services Interfaces - ADSI) que fornecem acesso aos diretórios usando um dos seguintes protocolos:

Veremos a seguir alguns exemplos de como acessar o AD e em para que tudo funcione corretamente a conta da ASP.NET que estiver em execução deve possuir permissão para acessar o Active Directory. Se você estiver usando o Visual Studio ou o Visual Web Developer e testando as páginas usando o servidor web embutido provavelmente terá esse acesso habilitado, de outra forma tente efetuar o login na sua máquina com uma conta que possui permissão de administrador neste domínio.

Se você deseja acessar o AD a partir de uma aplicação rodando sob o IIS , você deverá desabilitar o acesso anônimo para a aplicação no Internet Services Manager, desta forma que os usuários tenham que fornecer credenciais do domínio quando forem acessar a aplicação. (Tome cuidado ao alterar a alocação da conta anônima IUSR ou ao alterar permissões ASP .NET para o AD. Se for efetuar restrições faça-as restringindo o mínimo necessário.)

As principais classes no namespace System.DirecotoryServices são :

O primeiro passo a ser dado para usar o ADSI é fazer uma conexão com o recurso que você deseja acessar (o nó específico da árvore). Para procurar por recursos de todo o domínio você deve se conectar ao topo do nó e assim obter uma referência a raiz do diretório, e, para fazer isso você precisa especificar o URI no formato LDAP correto.

Para acessar o Active Directory local usamos a sintaxe : "LDAP://domain/name" . Exemplo:

Dim recurso as new DirectoryEntry("LDAP://macoratti.net")    Obs: A definição do protocolo deve estar em letras maiúsculas: LDAP.

Após inicializar o recurso desejado (o nó da árvore) você precisa especificar uma string de consulta na classe DirectorySearcher. (Você pode definir diversos valores de parâmetros deste objeto para refinar a sua pesquisa). Assim, se você quer obter informações sobre o usuário Macoratti pode definir na propriedade Filter uma string de consulta como (cn=Macoratti) desta forma:

Dim busca As New DirectorySearcher(recurso)
busca.Filter = "(cn=Macoratti)"

Nota:

Ao definir a propriedade Filter você deve seguir as seguintes regras:
  1. A string precisa estar entre parênteses;
  2. Expressões podem usar os operadores relacionais: : <, <=, =, >=, e >. Ex: "(objectClass=user)" ou "(Nome>=Davis)".
  3. Expressões compostas são formadas com o operador & e !. Ex: "(&(objectClass=user)(Nome= Davis))".

em seguida você deve iniciar a busca chamando os seguintes métodos da classe DirectorySearcher:

O retorno é do tipo SearchResultCollection.

Outra propriedade que vale a pena citar é a PropertiesToLoad que permite a você especificar os valores que você deseja retornar na sua busca. Se você não especificar nada a busca irá retornar todas as propriedades, e , este é o valor padrão. Então se você tiver interesse somente em alguns valores defina os valores que você deseja usando esta propriedade; você faz isso incluindo as propriedades a esta coleção antes de iniciar a busca. Exemplo:

searcher.PropertiesToLoad.Add("nome")    irá incluir a propriedade nome a lista de propriedades para retornar na busca.

Com isso você evita que todos as propriedades sejam carregadas na memória.

Após isto você pode executar a busca da seguinte forma:

Dim resultados as SearchResultCollection
resultados = busca.FindAll()

Após realizar a busca você pode iterar sobre cada entrada SearchResult na coleção SearchResultCollection.

A classe SearchResult possui a propriedade Properties que retorna um objeto ResultPropertyCollection que contém todas as propriedades que você especificou. Ex:

For Each resultado As SearchResult In resultados
     Dim propColl As ResultPropertyCollection = resultado.Properties
Next

Onde ResultPropertyCollection expõe a propriedade PropertyNames que retorna uma coleção contendo nomes de todas as propriedades retornadas pela busca. Assim você pode percorrer esta coleção para obter os nomes. Ex:

For Each strKey As String In propColl.PropertyNames
        For Each obProp As Object In propColl(strKey)
             Me.AppendPropertyNode(obTopNode, strKey, obProp)
        Next
Next

Finalizando você pode usar a propriedade PropertyNames para extrair valores específicos do coleção ResultPropertyCollection.

Vejamos a seguir algumas tarefas usando o Active Directory

Você pode criar os exemplos abaixo no Visual Basic 2005 Express ou Visual Studio 2005.

Crie um novo projeto do tipo Windows Application e utilize os seguintes namespaces:

Imports system.text
Imports
System.DirectoryServices
Imports
System.Collections

Inclua no formulário o controle ListBox e o controle Button.

Obs: Se for necessário inclua uma referência a System.DirectoryServices clicando com o botão direito do mouse sobre o nome do projeto e selecione a opção Add Reference, em seguida na janela Add Reference , na aba .NET selecione System.DirectoryServices e clique em OK.

1- Listar os domínios de redes

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 

Dim root As System.DirectoryServices.DirectoryEntry

root = New System.DirectoryServices.DirectoryEntry("WinNT:")


Dim
dominio As System.DirectoryServices.DirectoryEntry


For
Each dominio In root.Children

      ListBox1.Items.Add(dominio.Name)

Next

End Sub

Acima estou apontando para o provedor ADSI WinNT: que traz os domínios da rede.

2- Listar os computadores na rede

Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click

 

Dim root As System.DirectoryServices.DirectoryEntry

root = New System.DirectoryServices.DirectoryEntry("WinNT:")

Dim dominio As System.DirectoryServices.DirectoryEntry

 

For Each dom In root.Children

    Dim computadores As System.DirectoryServices.DirectoryEntry

    computadores= New System.DirectoryServices.DirectoryEntry("WinNT://" + dominio.Name)


     Dim
comp As System.DirectoryServices.DirectoryEntry

     For Each comp In computers.Children

          If comp.SchemaClassName = "computador" Then

                 ListBox1.Items.Add((comp.Name)

          End If

       Next

Next

End Sub

3- Obtendo uma lista de usuários do Active Directory

Vamos aplicar esta teoria toda em um exemplo básico: retornar uma lista de usuários encontrados no container "Users" do Active Directory no domínio local.

O código mostrado a seguir faz exatamente isso.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click


Dim
builder As New StringBuilder()

' obtem uma reerencia ao Active Directory Atual

' e exibe o nome do dominio


Dim
dominio As Domain = Domain.GetCurrentDomain()

Dim nomeDominio As String = dominio.Name


builder.Append("List of Active Directory Users for Domain '" + nomeDominio + "'" & Chr(10) & "")


' obtem a entrada raiz no AD para o dominio

Using root As New DirectoryEntry("LDAP://" + nomeDominio)


   ' procura no AD por caminho filhos com o container CN=Users

    Using searcher As New DirectorySearcher(root, "CN=Users")

   ' retorna a primeira ocorrência

    Dim result As SearchResult = searcher.FindOne()


    If
result Is Nothing
Then

         builder.Append("No 'CN=Users' entry found.")

    Else

             ' obtem a entrada do diretorio para o caminho CN=Users

             Using entry As DirectoryEntry = result.GetDirectoryEntry()

        ' percorre todos as entradas filhas


             
For Each child As DirectoryEntry In entry.Children

              Dim userEntry As String = child.Name

              ' remove "CN=" do nome retornado

               builder.Append(userEntry.Substring(userEntry.IndexOf("=") + 1) + "" & Chr(10) & "")

         Next

          End Using

      End If

   End Using

End Using

resultado = builder.ToString()

ListBox1.Items.Add(resultado)

End Sub

 

A seguir temos uma função para listar todos os usuários usando o Active Directory :

 

    Public Function ListarTodosUsuariosAD() As DataTable
        Dim LDAP As String = "<ValorDoWebConfig>"
        Dim table As DataTable = New DataTable("Resultados")
        table.Columns.Add("Nome")
        table.Columns.Add("Usuario")
        table.Columns.Add("Email")
        Dim row As DataRow
        Dim deRoot As DirectoryEntry = New DirectoryEntry(LDAP)
        Dim deSrch As DirectorySearcher = New DirectorySearcher(deRoot, "(&(objectClass=user)(objectCategory=person))")
        deSrch.PropertiesToLoad.Add("cn")
        deSrch.PropertiesToLoad.Add("userPrincipalName")
        deSrch.PropertiesToLoad.Add("sAMAccountName")
        deSrch.PropertiesToLoad.Add("mail")
        deSrch.Sort.PropertyName = "sAMAccountName"
        Dim oRes As SearchResult
        For Each oRes In deSrch.FindAll()
            row = table.NewRow()
            row("Nome") = oRes.Properties("cn")(0).ToString()
            row("usuario") = oRes.Properties("sAMAccountName")(0).ToString()
            If oRes.Properties.Contains("mail") Then
                row("Email") = oRes.Properties("mail")(0).ToString()
            End If
            table.Rows.Add(row)
        Next
        Return table
    End Function

 

 

4- Autenticação de usuários

Para autenticar usuários no AD crie um novo web site no VS ou no VWD 2005 e inclua uma classe ao seu projeto chamada Autoriza.vb; a seguir crie uma função chamada Autentica  contendo o seguinte código:

Imports System.DirectoryServices
 

Public Class Autoriza
 

Public Function Autentica(ByVal IpServer As String, ByVal User As String, ByVal Senha As String) As String


Dim
  resutado As String =
""


Try

   Dim oAD As DirectoryEntry = New DirectoryEntry("LDAP://" + IpServer, User, Senha)

   resutado = oAD.Name

Catch ex As Exception

   Throw New Exception(ex.Message)

End Try

Return    resutado

End Function

End Class

 

Agora na página Default.aspx inclua dois controle TextBox : txtUsuario e txtSenha e um botão de comando Button : btnLogin;

Agora no evento Click do botão de comando inclua o seguinte código:

Protected Sub btnLogin_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnLogin.Click

Dim oAD As Autoriza = New Autoriza

Try
    Response.Write(oAD.Autentica("127.0.0.1", txtUsuario.Text, txtSenha.Text) + "<br>")
Catch
ex As Exception
   Response.Write(ex.Message)
End
Try

End Sub

 

Para um exemplo mais detalhado e robusto veja o link: http://www.microsoft.com/brasil/security/guidance/topics/devsec/secmod16.mspx

 

Na verdade o assunto sobre o Active Directory é muito amplo e o artigo pretende apenas mostrar o básico sobre este recurso mostrando algumas possibilidades de uso.

 

Nota: Em pesquisas que realizei na internet descobri que o Active Directory não é suportado pelo Windows XP.


Até o próximo artigo...


José Carlos Macoratti