none
phpLdapAdmin e VB.net RRS feed

  • Pergunta

  • Eu tenho um servidor, de IP: 192.168.0.1 (responde em http://ldap.compania.com.br).

    Este servidor está rodando o phpLdapAdmin.

    Nele tem uma entrada "cn=admin" que veio padrão, e para o propósito deste post, de senha 1234.

    Se eu usar o navegador do phpLdapAdmin, eu posso logar na página usando:

    Usuário: cn=admin,dc=compania,dc=com,dc=br
    Senha: 1234

    Como faço para o meu programa conectar neste servidor usando usuário e senha?

    Veja o que escrevi:

    'Este é o único código no programa até agora
    'Programa do tipo console.
    
    Public Module Core
        Public Function Authenticate(ByVal userName As String, ByVal password As String, ByVal domain As String) As Boolean
            Dim authentic As Boolean = False
            Try
                Dim Root As New System.DirectoryServices.DirectoryEntry("LDAP://" + domain, userName, password)
                Dim child As Object = Root.NativeObject
                authentic = True
            Catch
                'NOTHING
            End Try
            Return authentic
        End Function
    
        Friend Sub Main(ByVal Arg() As String)
            Dim Sc As Boolean = Authenticate("admin", "1234", "ldap.compania.com.br")
            System.Console.WriteLine("LDAP Connection Console for .Net 2.0.")
            System.Console.WriteLine("Used only by Web Application internal call.")
            System.Console.WriteLine("If you are running on the console then close it.")
            System.Console.WriteLine("Diagnostics: " + CStr(Sc))
            System.Console.Read()
        End Sub
    End Module

    Sempre retorna False na função "Authenticate". Já tentei usar o "cn=admin,dc=compania,dc=com,dc=br" no "UserName" e no "Domain". Ambos sem sucesso.

    Alguém sabe dizer o que estou fazendo errado?
    quinta-feira, 3 de julho de 2014 18:42

Respostas

  • Resolvido.

    O código final ficou assim:

    Public Module Connection
        Public Const DefaultFilter As String = "(objectClass=*)"
    
        Public Function GetRoot(ByVal UserName As String, ByVal Password As String, ByVal Path As String, Optional ByRef QueryUser As Boolean = False) As System.DirectoryServices.DirectoryEntry
            Dim ServerRoot As String = "LDAP://" + Path
            If QueryUser Then ServerRoot += "/" + UserName
            Try
                Dim Root As New System.DirectoryServices.DirectoryEntry(ServerRoot, UserName, Password, System.DirectoryServices.AuthenticationTypes.None)
                Dim child As Object = Root.NativeObject
                Return Root
            Catch
                Return Nothing
            End Try
        End Function
    
        Public Function GetChildren(ByRef Root As System.DirectoryServices.DirectoryEntry, Optional ByRef FullTree As Boolean = False, Optional ByRef Filter As String = LDAP.Connection.DefaultFilter) As System.DirectoryServices.DirectoryEntry()
            Dim Returns() As System.DirectoryServices.DirectoryEntry = {}
            Try
                Dim Searcher As New System.DirectoryServices.DirectorySearcher(Root)
                Searcher.Filter = Filter
                Select Case FullTree
                    Case True : Searcher.SearchScope = System.DirectoryServices.SearchScope.Subtree
                    Case Else : Searcher.SearchScope = System.DirectoryServices.SearchScope.OneLevel
                End Select
                Dim Results As System.DirectoryServices.SearchResultCollection = Searcher.FindAll()
                Dim Limit As Integer = Results.Count
                If Limit > 0 Then Limit -= 1
                ReDim Returns(0 To Limit)
                Dim Index As Integer = 0
                For Each Result As System.DirectoryServices.SearchResult In Results
                    Returns(Index) = Result.GetDirectoryEntry()
                    Index += 1
                Next Result
            Catch
                Returns = {}
            End Try
            Return Returns
        End Function
    
        Public Function GetChildren(ByVal UserName As String, ByVal Password As String, ByVal Path As String, Optional ByRef FullTree As Boolean = False, Optional ByRef Filter As String = LDAP.Connection.DefaultFilter) As System.DirectoryServices.DirectoryEntry()
            Dim Root As System.DirectoryServices.DirectoryEntry = LDAP.Connection.GetRoot(UserName, Password, Path, QueryUser:=False)
            If Root Is Nothing Then Return New System.DirectoryServices.DirectoryEntry() {} Else Return LDAP.Connection.GetChildren(Root, FullTree:=FullTree, Filter:=Filter)
        End Function
    
        Public Enum PasswordSecurity As Byte
            Clear = 0
            MD5 = 1
            SSHA = 2
        End Enum
    
        Private Function GenerateArray(ByRef Array1() As Byte, ByRef Array2() As Byte) As Byte()
            Dim byteArrayResult(Array1.Length + Array2.Length) As Byte
            System.Array.Copy(Array1, byteArrayResult, Array1.Length)
            System.Array.Copy(Array2, 0, byteArrayResult, Array1.Length, Array2.Length)
            Return byteArrayResult
        End Function
    
        Private Function GenerateHash(ByRef NewPassword As String, ByRef SecutiryMethod As LDAP.Connection.PasswordSecurity) As String
            Select Case SecutiryMethod
                Case LDAP.Connection.PasswordSecurity.Clear : Return NewPassword
                Case LDAP.Connection.PasswordSecurity.SSHA
                    Dim rng As New System.Security.Cryptography.RNGCryptoServiceProvider()
                    Dim Salt(4) As Byte
                    rng.GetBytes(Salt)
                    Dim algorithm As New System.Security.Cryptography.SHA1Managed()
                    Dim Hash() As Byte = algorithm.ComputeHash(LDAP.Connection.GenerateArray(System.Text.Encoding.ASCII.GetBytes(NewPassword), Salt))
                    Return "{SSHA}" + System.Convert.ToBase64String(LDAP.Connection.GenerateArray(Hash, Salt))
                Case LDAP.Connection.PasswordSecurity.MD5
                    Dim algorithm As New System.Security.Cryptography.MD5CryptoServiceProvider()
                    Dim Hash() As Byte = algorithm.ComputeHash(System.Text.Encoding.ASCII.GetBytes(NewPassword))
                    Return "{MD5}" + System.Convert.ToBase64String(Hash)
                Case Else : Return ""
            End Select
        End Function
    
        Public Function ResetPassword(ByRef Root As System.DirectoryServices.DirectoryEntry, ByVal NewPassword As String, ByRef SecutiryMethod As LDAP.Connection.PasswordSecurity) As Boolean
            Try
                NewPassword = GenerateHash(NewPassword, SecutiryMethod)
                Root.Properties.Item("userPassword").Clear()
                Root.Properties.Item("userPassword").Add(System.Text.Encoding.UTF8.GetBytes(NewPassword))
                Root.CommitChanges()
                Return True
            Catch
                Return False
            End Try
        End Function
    End Module
    • Marcado como Resposta SammuelMiranda sexta-feira, 18 de julho de 2014 17:57
    sexta-feira, 18 de julho de 2014 17:57

Todas as Respostas

  • quinta-feira, 3 de julho de 2014 19:01
  • Resolvido.

    O DirectoryEntry(String, String, String) assume automaticamente que é uma conexão segura.

    O argumento "System.DirectoryServices.AuthenticationTypes" deve ser "None" caso a autentificação não seja via SSL.

    O argumento admin deve conter todo o filtro, "cn=admin,dc=compania,dc=com,dc=br"

    • Marcado como Resposta SammuelMiranda sexta-feira, 4 de julho de 2014 11:59
    • Editado SammuelMiranda sexta-feira, 4 de julho de 2014 12:00
    • Não Marcado como Resposta SammuelMiranda terça-feira, 8 de julho de 2014 17:45
    sexta-feira, 4 de julho de 2014 11:59
  • Gente, eu consegui a resolução para autenticar o usuário, mas não consigo solicitar os atributos e valores das propriedades dele.

    Veja como ficou:

    Public Module Core
        Public Function Authenticate(ByVal UserName As String, ByVal Password As String, ByVal Path As String) As System.DirectoryServices.DirectoryEntry
            Try
                Dim Root As New System.DirectoryServices.DirectoryEntry("LDAP://" + Path, UserName, Password, System.DirectoryServices.AuthenticationTypes.None)
                Dim child As Object = Root.NativeObject
                Return Root
            Catch
                Return Nothing
            End Try
        End Function
    
        Public Function GetAttributes(ByRef Root As System.DirectoryServices.DirectoryEntry) As String()
            Dim Searcher As New System.DirectoryServices.DirectorySearcher(Root)
            Searcher.PropertyNamesOnly = False
            Searcher.PropertiesToLoad.Add("givenName")
            Searcher.PropertiesToLoad.Add("sn")
            Searcher.PropertiesToLoad.Add("uidNumber")
            'Searcher.PropertiesToLoad.Add("User Name")
            'Essa é a propriedade que eu quero!
            Searcher.SearchScope = System.DirectoryServices.SearchScope.Base
            Searcher.Filter = "(&(objectClass=*))"
            Dim Res As System.DirectoryServices.SearchResultCollection = Searcher.FindAll()
            Dim Nms() As String = {""}
            Dim inDEntry As System.DirectoryServices.DirectoryEntry = Nothing
            For Each Re As System.DirectoryServices.SearchResult In Res
                inDEntry = Re.GetDirectoryEntry()
                For Each prop As System.Collections.DictionaryEntry In inDEntry.Properties
                    'Da Erro desconhecido AQUI!
                    For Each A As String In CType(prop.Value, String())
                        If Nms(0) = "" Then
                            Nms(0) = prop.Key.ToString() + " = " + A
                        Else
                            ReDim Preserve Nms(0 To Nms.Length)
                            Nms(Nms.Length - 1) = prop.Key.ToString() + " = " + A
                        End If
                    Next A
                Next prop
            Next Re
            Return Nms
        End Function
    
        Friend Sub Main(ByVal Arg() As String)
            Dim Root As System.DirectoryServices.DirectoryEntry = LDAPConnection.Main.Authenticate("cn=nomedousuario,cn=operacional,cn=funcionarios,dc=minhaempresa,dc=com,dc=br", "minhasenha", "ldap.minhaempresa.com.br")
            System.Console.WriteLine("LDAP Connection Console for .Net 2.0.")
            System.Console.WriteLine("Used only by Web Application internal call.")
            System.Console.WriteLine("If you are running on the console then close it.")
            If Root Is Nothing Then
                System.Console.WriteLine("Authentication Test: Failed.")
            Else
                System.Console.WriteLine("Authentication Test: Success.")
                Dim Res() As String = LDAPConnection.Main.GetAttributes(Root)
                For Each Re As String In Res
                    System.Console.WriteLine("*> " + Re)
                Next Re
            End If
            System.Console.Read()
        End Sub
    End Module

    O usuário usa o template:

    Template: Generic: User Account (posixAccount)

    Do PHPLDAPADMIN. Tenho propriedades chamadas "sn", "User Name" (assim, separado), "uuid" etc. Quero busca-las.



    terça-feira, 8 de julho de 2014 17:48
  • Resolvido novamente...

    O problema está no "Authenticate" que escrevi. Eu assumi que o "UserName" usado já fizesse parte do resultado, mas "UserName" e "Password" são atributos usado para conectar no servidor LDAP. O resultado retornado é o "Path" usado, e o que tem alocado nele.

    Dessa forma, me desfiz da função "GetAttributes" e apenas concatenei o "UserName" ao "Path". Veja:

    Public Module Core
        Public Function Authenticate(ByVal UserName As String, ByVal Password As String, ByVal Path As String, ByRef GetAttributes As Boolean) As System.DirectoryServices.DirectoryEntry
            Dim ServerRoot As String = "LDAP://" + Path
            If GetAttributes Then ServerRoot += "/" + UserName
            Try
                Dim Root As New System.DirectoryServices.DirectoryEntry(ServerRoot, UserName, Password, System.DirectoryServices.AuthenticationTypes.None)
                Dim child As Object = Root.NativeObject
                Return Root
            Catch
                Return Nothing
            End Try
        End Function
    
        Friend Sub Main(ByVal Arg() As String)
            Dim Root As System.DirectoryServices.DirectoryEntry = LDAPConnection.Core.Authenticate("cn=meuusuario,cn=operacional,cn=funcionarios,dc=minhaempresa,dc=com,dc=br", "minhasenha", "ldap.varixx.com.br", True)
            System.Console.WriteLine("LDAP Connection Console for .Net 2.0.")
            System.Console.WriteLine("Used only by Web Application internal call.")
            System.Console.WriteLine("If you are running on the console then close it.")
            If Root Is Nothing Then
                System.Console.WriteLine("Authentication Test: Failed.")
            Else
                System.Console.WriteLine("Authentication Test: Success.")
                For Each Prop As System.DirectoryServices.PropertyValueCollection In Root.Properties
                    System.Console.WriteLine("*> " + Prop.PropertyName + " = " + Prop.Value.ToString())
                Next Prop
            End If
            System.Console.Read()
        End Sub
    End Module

    Dessa forma, se o argumento "GetAttributes (Boolean)" for True, então eu quero carregar o usuário, e seus atributos (definindo o Path como [endereço do servidor]/[nome do usuario] como alvo da busca) se não ele vai retornar o path que é a base do servidor LDAP - deixei assim pois pode ser útil para futuramente buscar os usuários cadastrados no servidor, por exemplo.

    • Editado SammuelMiranda quinta-feira, 10 de julho de 2014 12:46
    • Marcado como Resposta SammuelMiranda quinta-feira, 10 de julho de 2014 12:46
    • Não Marcado como Resposta SammuelMiranda quinta-feira, 10 de julho de 2014 19:15
    quinta-feira, 10 de julho de 2014 11:27
  • Hehe ... to vendo que eu nunca vou fechar este post...

    Meu problema agora é que eu quero alterar a senha do usuário...

    Basicamente o "Invoke("SetPassword", "1234")" e o "Invoke("ChangePassword", "123", "1234")" não funcionam.

    Eu poderia também dar "Properties("userPassword") = GetBytes("1234")" - mas a senha está sendo salva usando MD5 - no phpLdapAdmin.

    Carrego o "DirectoryEntry", o elemento "Properties("userPassword")" é um array de bytes que convertido em uma string sai "(md5)XXXXXXXXX/xxxxxxxxxxx==". Não sei como gerar isso.

    Atualmente o phpLdapAdmin permite que eu escolha salvar a senha utilizando os métodos:

    • clear - (que é o texto sem criptografia. Eu consigo altear a Properties para isso, mas não vai ser legal assim. Perderei a segurança).
    • blowfish
    • crypt
    • ext_des
    • md5
    • k5key
    • md5crypt
    • sha
    • smd5
    • ssha
    quinta-feira, 10 de julho de 2014 19:19
  • Mantendo o padrão, MD5, para por exemplo: "MinhaSenha", tenho este resultado "{MD5}d1twWIoTnJFEErf9vCDRxw==" ao invés de "775b70588a139c914412b7fdbc20d1c7" (que é o que os sites que simulam MD5 retornam).

    O "{MD5}" na frente eu entendo que o phpLdapAdmin coloca para que ele possa identificar a criptografia adotada, pois ele armazena um array de bytes de qualquer forma. Mas como "775b70588a139c914412b7fdbc20d1c7" (resultado de "MinhaSenha") vira "d1twWIoTnJFEErf9vCDRxw=="?

    Eu postei esta pergunta em um assunto específico, pois essa dúvida já é sobre MD5, MD5 - Conversão.
    quinta-feira, 10 de julho de 2014 19:45
  • Resolvido.

    O código final ficou assim:

    Public Module Connection
        Public Const DefaultFilter As String = "(objectClass=*)"
    
        Public Function GetRoot(ByVal UserName As String, ByVal Password As String, ByVal Path As String, Optional ByRef QueryUser As Boolean = False) As System.DirectoryServices.DirectoryEntry
            Dim ServerRoot As String = "LDAP://" + Path
            If QueryUser Then ServerRoot += "/" + UserName
            Try
                Dim Root As New System.DirectoryServices.DirectoryEntry(ServerRoot, UserName, Password, System.DirectoryServices.AuthenticationTypes.None)
                Dim child As Object = Root.NativeObject
                Return Root
            Catch
                Return Nothing
            End Try
        End Function
    
        Public Function GetChildren(ByRef Root As System.DirectoryServices.DirectoryEntry, Optional ByRef FullTree As Boolean = False, Optional ByRef Filter As String = LDAP.Connection.DefaultFilter) As System.DirectoryServices.DirectoryEntry()
            Dim Returns() As System.DirectoryServices.DirectoryEntry = {}
            Try
                Dim Searcher As New System.DirectoryServices.DirectorySearcher(Root)
                Searcher.Filter = Filter
                Select Case FullTree
                    Case True : Searcher.SearchScope = System.DirectoryServices.SearchScope.Subtree
                    Case Else : Searcher.SearchScope = System.DirectoryServices.SearchScope.OneLevel
                End Select
                Dim Results As System.DirectoryServices.SearchResultCollection = Searcher.FindAll()
                Dim Limit As Integer = Results.Count
                If Limit > 0 Then Limit -= 1
                ReDim Returns(0 To Limit)
                Dim Index As Integer = 0
                For Each Result As System.DirectoryServices.SearchResult In Results
                    Returns(Index) = Result.GetDirectoryEntry()
                    Index += 1
                Next Result
            Catch
                Returns = {}
            End Try
            Return Returns
        End Function
    
        Public Function GetChildren(ByVal UserName As String, ByVal Password As String, ByVal Path As String, Optional ByRef FullTree As Boolean = False, Optional ByRef Filter As String = LDAP.Connection.DefaultFilter) As System.DirectoryServices.DirectoryEntry()
            Dim Root As System.DirectoryServices.DirectoryEntry = LDAP.Connection.GetRoot(UserName, Password, Path, QueryUser:=False)
            If Root Is Nothing Then Return New System.DirectoryServices.DirectoryEntry() {} Else Return LDAP.Connection.GetChildren(Root, FullTree:=FullTree, Filter:=Filter)
        End Function
    
        Public Enum PasswordSecurity As Byte
            Clear = 0
            MD5 = 1
            SSHA = 2
        End Enum
    
        Private Function GenerateArray(ByRef Array1() As Byte, ByRef Array2() As Byte) As Byte()
            Dim byteArrayResult(Array1.Length + Array2.Length) As Byte
            System.Array.Copy(Array1, byteArrayResult, Array1.Length)
            System.Array.Copy(Array2, 0, byteArrayResult, Array1.Length, Array2.Length)
            Return byteArrayResult
        End Function
    
        Private Function GenerateHash(ByRef NewPassword As String, ByRef SecutiryMethod As LDAP.Connection.PasswordSecurity) As String
            Select Case SecutiryMethod
                Case LDAP.Connection.PasswordSecurity.Clear : Return NewPassword
                Case LDAP.Connection.PasswordSecurity.SSHA
                    Dim rng As New System.Security.Cryptography.RNGCryptoServiceProvider()
                    Dim Salt(4) As Byte
                    rng.GetBytes(Salt)
                    Dim algorithm As New System.Security.Cryptography.SHA1Managed()
                    Dim Hash() As Byte = algorithm.ComputeHash(LDAP.Connection.GenerateArray(System.Text.Encoding.ASCII.GetBytes(NewPassword), Salt))
                    Return "{SSHA}" + System.Convert.ToBase64String(LDAP.Connection.GenerateArray(Hash, Salt))
                Case LDAP.Connection.PasswordSecurity.MD5
                    Dim algorithm As New System.Security.Cryptography.MD5CryptoServiceProvider()
                    Dim Hash() As Byte = algorithm.ComputeHash(System.Text.Encoding.ASCII.GetBytes(NewPassword))
                    Return "{MD5}" + System.Convert.ToBase64String(Hash)
                Case Else : Return ""
            End Select
        End Function
    
        Public Function ResetPassword(ByRef Root As System.DirectoryServices.DirectoryEntry, ByVal NewPassword As String, ByRef SecutiryMethod As LDAP.Connection.PasswordSecurity) As Boolean
            Try
                NewPassword = GenerateHash(NewPassword, SecutiryMethod)
                Root.Properties.Item("userPassword").Clear()
                Root.Properties.Item("userPassword").Add(System.Text.Encoding.UTF8.GetBytes(NewPassword))
                Root.CommitChanges()
                Return True
            Catch
                Return False
            End Try
        End Function
    End Module
    • Marcado como Resposta SammuelMiranda sexta-feira, 18 de julho de 2014 17:57
    sexta-feira, 18 de julho de 2014 17:57
  • Mais dúvidas surgem a cada nova linha de código...
    terça-feira, 22 de julho de 2014 16:43