Translate this page now :



Gostou da Página?
Clique no botão abaixo para indicar esta página para um amigo!



Pesquisa personalizada
Pesquisar Dicas:








Quer saber mais?
Torne-se um MCP em Visual Basic
Faça um treinamento na Búfalo Informática


Utilizando ADSI para criar uma segurança integrada


Todo dia ouvimos falar de novas falhas descobertas no sistema operacional. Os mais distraidos podem acreditar que a segurança do sistema operacional é mais parecida com um queijo suiço, quando na verdade o que ocorre é justamente o contrário : milhões de pessoas no mundo estão empenhadas em descobrir e dar solução ao maior número de falhas possível, o que faz com que o sistema operacional hoje seja extremamente seguro.

Esse é, com certeza, o primeiro motivo para você fugir de um velho e tradicional hábito : Criar uma tela de login e um cadastro de usuários para sua aplicação.

Você com certeza irá perguntar : Qual a alternativa ? A alternativa é confiar na segurança do sistema operacional. Desta forma você não precisa ter telas de login nem cadastros de usuários, basta confiar que, se o usuário está logado no domínio é porque ele é ele mesmo e o sistema operacional garante isso. Assim sendo, ao invés de criar seu próprio cadastro de usuários sua aplicação pode atribuir permissões aos usuários do domínio, utilizando o que é chamado por alguns softwares de "segurança integrada".

Veja algumas vantagens :

Os passos para a montagem da segurança integrada são :

Neste artigo demonstraremos apenas a atribuição de permissões a usuários. Deixaremos a atribuição de permissões a grupos para um 2o artigo

Como você deve ter observado necessitaremos obter muitas informações do sistema operacional, é ai que entra o ADSI (Active Directory Services Interfaces).

A forma como alguns softwares Microsoft armazenam seus dados é chamada de Directory Services, ou serviço de diretórios. Isso vale para o NT com todos seus usuários e grupos, o W2K, com o Active Directory, o Exchange Server que na versão 5.5 tinha seu próprio serviço de diretórios (acessível usando adsi) e na versão 2000 se integrou ao Active Directory e o Internet Information Server (IIS) que utiliza seu próprio banco, chamado de Metabase, para guardar sua configuração. Todos esses softwares podem ser manipulados através do ADSI.

Para permitir tal diversidade o ADSI utiliza o conceito de Provider de forma muito semelhante ao ADO/OLEDB : Especifica-se ao ADSI o provider que será utilizado para podermos acessar um determinado objeto dentro do serviço de diretório dos servidores, conforme veremos mais adiante.

Mas esse não é o primeiro passo. O 1o passo será criar o banco de dados com tabelas que permitam o controle do permissionamento. Precisaremos de 2 tabelas : Uma que guarde as permissões possíveis ou, poderíamos dizer, as "tarefas permissionáveis" de nossa aplicação (incluir, excluir, etc). Já a 2a tabela guardará a relação dos usuários com estas tarefas permissionáveis.

Veja a estrutura recomendada para as 2 tabelas :

Permissoes
USU_PERMISSAO
CodPermissao AutoNumber SID Text
Permissao Text Permissao Number - Long Integer

 

Como pode observar o campo CodPermissao da tabela Permissoes se relaciona com o campo Permissao da tabela USU_PERMISSAO

Para efeito de exemplo vamos criar um form MDI e alguns Menus para os quais poderemos atribuir permissões de acesso. Este será o nosso sistema de menus :

Como pode observar, teremos que atribuir permissão para o próprio ato de atribuir permissão, afinal não são todos os usuários que podem fazer isso. Veja como ficarão os registros da tabela Permissões com base nos menus acima :

CodPermissao
Permissao
1
cliente
2
vendas
3
relatorios
4
usuarios
5
grupos

Selecionando os menus pela janela de propriedades devemos preencher a propriedade TAG dos menus com o código da permissão que será necessária para acessar o referido menu. Vamos usar a letra "P" na frete do número, isso evitará eventuais confusões com outros objetos que tenham a propriedade TAG preenchida.

Vamos começar montando a tela de atribuição de permissões a usuários. A imagem a seguir mostra como a tela irá parecer : Na combo estará a lista de usuários disponíveis no domínio em questão, na janela de permissões da esquerda aparecerá a lista de permissões disponíveis e na da direita a lista de permissões já atribuidas ao usuário.

A cada vez que um novo nome for selecionado na combo será necessário alterar tanto a listbox da esquerda como a da direita, fazendo com que elas reflitam a permissão que o usuário possui.

O primeiro passo será programarmos o carregamento da combo, que deverá ser feito no load do form. Para obtermos a lista de usuários do domínio deveremos usar o ADSI, portanto faremos uma referencia para a ActiveDS Type Library para que desta forma possamos utilizar early binding.

Os objetos do ADSI, porém, são tratados de forma diferente de outros tradicionais, como o ADO. Se observar a ActiveDS pelo Object Browser poderá ver que ela possui muitas interfaces (objetos iniciados por I), mas poucos objetos. Os principais objetos do ADSI não são instanciáveis, mas obtidos através de um GetObject com o caminho adequado. As interfaces da TLB do ADSI permitem que façamos early binding mesmo usando GetObject.

Deve-se destacar ainda que um objeto ADSI pode estar implementando várias destas interfaces, o que faz com que possamos utilizar interfaces diferentes com o mesmo objeto sem problemas e, conforme a interface que utilizarmos, veremos diferentes métodos e propriedades daquele objeto.

Outra questão importante é que não devemos utilizar apenas o nome do usuário como garantia de segurança, seria algo frágil. Sempre que um objeto é criado no servidor (e isso inclui usuários) esse objeto ganha um ID único chamado de SID. Assim sendo devemos registrar no banco de dados o SID do usuário e não o seu nome, tornando o sistema mais seguro contra fraudes. Teremos um pequeno problema pelo fato de que a propriedade que guarda o SID (objectSID) o guarda na forma de um array variant, o que nos obriga a criarmos uma pequena função para convertermos o valor do SID para string.

Outro problema é que, sendo string, não poderemos guardar o SID dentro do ItemData da Listbox. Teremos que definir uma Collection que guardará o SID de cada usuário até precisarmos dele.

Veja como fica :

'A definição da collection que será utilizada para guardar os SID's
Dim SIDs As New Collection


Private Sub Form_Load()

'Faz a definição das variáveis com as interfaces
'do ADSI
Dim user As IADsUser
Dim dom As IADsContainer
'centralização do form dentro do MDI
Me.Left = (frmMain.ScaleWidth - Me.Width) / 2 Me.Top = (frmMain.ScaleHeight - Me.Height) / 2 'Obtenção do objeto de domínio - observe o provider WinNT 'Foi utilizada a interface IaDsContainer, para acessarmos 'os objetos contidos no domínio Set dom = GetObject("WinNT://bufalo") 'Filtragem dos objetos contidos no domínio, desejamos ver apenas 'os usuários. É necessário que o parâmetro seja um Array 'por isso o uso da função Array dom.Filter = Array("user") 'Um For Each a ser executado para cada usuário do 'domínio For Each user In dom 'Adiciona o nome do usuário na combo cmbusuarios.AddItem user.Name 'Adiciona o SID do usuário na collection, 'usando o nome como key SIDs.Add sSID(user.objectsId), user.Name Next 'Destroi os objetos Set user = Nothing Set dom = Nothing 'Carrega as combo de permissões CarregaPermissoes End Sub

 

Observe que ao final do form_load a sub CarregaPermissoes é chamada para realizar o preenchimento das combos.

Veja como fica o código da função sSID, inserido em um módulo devido a ser de utilidade para toda a aplicação :

Function sSID(vSID As Variant) As String
    Dim i As Integer
    Dim res As String
    
    'Faz uma varredura do vetor, do 1o ao último item
    For i = LBound(vSID) To UBound(vSID)
        'Concatena o item com a variável string
        res = res & vSID(i)
    Next
    'Devolve a string resultante
    sSID = res
End Function

O próximo passo é analisarmos a sub CarregaPermissoes. Considerando o ponto inicial da tela, momento em que não temos nenhum usuário selecionado, é fácil imaginarmos que vamos apenas abrir a tabela de permissões e preencher toda a lista. Porém quando já tivermos usuários selecionados as permissões que os usuários já possuem não podem aparecer na lista da esquerda, apenas na lista da direita. Portanto conforme inserimos os nomes das permissões na lista da esquerda devemos verificar se a permissão em questão não existe na lista da direita e só inserir caso não exista.

Para acessar o banco vamos fazer uso de um Data Environment (DE) e de um Command (cmdpermissoes) vinculado a tabela Permissoes. Veja o código :


Sub CarregaPermissoes()
'Abre o RecordSet
'Como não existe nenhum vinculo de controle visual
'a abertura precisa ser "manual"
    DE.cmdPermissoes
    
'Limpa a lista
    lstDisponiveis.Clear
    
'Inicia um laço através do recordset
    While Not DE.rscmdPermissoes.EOF
    
'Utiliza a função ExistenaLista para verificar
'Se a permissão em questão já existe na lista da
'esquerda
         If Not ExistenaLista(DE.rscmdPermissoes.Fields("permissao").Value) Then
    'Caso não exista adiciona na listbox
            lstDisponiveis.AddItem DE.rscmdPermissoes.Fields("permissao").Value
            
            ' ...e preenche o itemData com o código da permissão
            lstDisponiveis.ItemData(lstDisponiveis.NewIndex) = DE.rscmdPermissoes.Fields("codpermissao").Value
                        
         End If
         
         'Passa para a próxima permissão
         DE.rscmdPermissoes.MoveNext
    Wend
    
    'Fecha tudo
    DE.rscmdPermissoes.Close
End Sub

Temos então mais uma função sendo utilizada : ExistenaLista, para verificar se o usuário já possui a permissão em questão ou não. Veja o código desta função :

Function ExistenaLista(sPermissao As String) As Boolean
'Define um contador
Dim iCNT As Integer

'Faz uma busca através de todo o conteúdo da lista
'da direita (lstAtuais)
For iCNT = 0 To lstAtuais.ListCount - 1
    'Verifica se encontrou
    If UCase(sPermissao) = UCase(lstAtuais.List(iCNT)) Then
       'Se sim devolve true e sai, não precisa continuar
       ExistenaLista = True
       Exit Function
    End If
Next

'Se chegou aqui é porque não existe
ExistenaLista = False

End Function

Conforme o código demonstra, ela faz a busca na lstAtuais, se encontrar devolve true, caso contrário False.

Agora devemos programar a alteração do usuário na combo, que é programada no evento click da combo. Precisaremos de um Command no DE que nos devolva um recordset com as permissões que o usuário possui. Para isso precisaremos criar um Command parametrizado e isso é tarefa simples : quando optamos por montar a instrução SQL do command, qualquer coisa na instrução que não seja um nome de campo é interpretada como um parâmetro.

Além da questão de ser parametrizado, a instrução SQL deverá também fazer um join entre as duas tabelas para poder trazer a descrição da permissão. Veja como fica a instrução SQL :

select SID,codpermissao,b.permissao from usu_permissao a,permissoes b where b.codpermissao=a.permissao and SID=parSID

 

O nome do parâmetro, como pode observar, é parSID. A partir do momento que utilizamos uma instrução SQL com parâmetros o parâmetro aparece na guia "Parameters" para que possamos configurar os destalhes sobre ele. No nosso caso basta garantir que Data Type e Host Data Type se referem a tipos string (VarChar).

Ao abrir este command deveremos passar o parâmetro parSID para que ele seja executado. Veja abaixo o código do Click na combo :

Private Sub cmbusuarios_Click()
    CarregaPermissoesUsuario
    CarregaPermissoes
    bAlterado = False
    cmdAplicar.Enabled = False
End Sub

As tarefas ficaram bem divididas, assim sendo, no momento do click da combo são chamadas 2 subs, uma para carregar as permissões do usuário (lista da direita) outra para carregar as permissões disponíveis (lista da esquerda). Observe que a ordem não pode ser mudada, pois a função ExistenaLista que foi utilizada no carregamento das permissões disponíveis depende das permissões do usuário já estarem carregadas.

Além disso o click da combo faz o controle de alteração nas permissões. No momento em que a combo foi clicada as permissões estão sendo recarregadas, portanto não existe nada a ser gravado : atribui-se false em uma variável bAlterado (definida no general como boolean) e desabilita-se o botão "Aplicar".

Veja como fica a Sub para carregar as permissões do usuário :

Sub CarregaPermissoesUsuario()

    'Abre o command transmitindo o SID como parâmetro
    'Lembre que utilizamos o nome do usuário como
    'key na collection, por isso podemos utiliza-lo para recuperar o SID
    DE.cmdUsuario SIDs.Item(cmbusuarios.List(cmbusuarios.ListIndex))
    
    'Apaga a lista de permissões
    lstAtuais.Clear
    
    'Inicia o laço no recordset recuperado
    While Not DE.rscmdUsuario.EOF
    
            'Adiciona a permissão na lista, preenche
            'o itemdata com o código da permissão
            'e segue adiante
            lstAtuais.AddItem DE.rscmdUsuario.Fields("permissao").Value
            lstAtuais.ItemData(lstAtuais.NewIndex) = DE.rscmdUsuario.Fields("codpermissao").Value
            DE.rscmdUsuario.MoveNext

    Wend
    
    'Fecha Tudo
    DE.rscmdUsuario.Close
    
End Sub

Observem a forma como chamamos o command transmitindo o parâmetro e a forma como recuperamos o SID do objeto collection.

O próximo passo são os botões cmdpermitir e cmdnegar, cuja função é transferir as permissões de uma lista para outra. Ambas as listas estão com a propriedade MultiSelect como True, o que nos obriga a vasculharmos o vetor SELECTED. Veja como fica o código :

Private Sub cmdNegar_Click()
    Dim iCNT As Integer

'Vasculha todos os itens da lista verificando se o item está marcado ou não
    For iCNT = lstDisponiveis.ListCount - 1 To 0 Step -1
        If lstDisponiveis.Selected(iCNT) Then
        'Se estiver selecionado transfere a opção para a outra lista
        'não esquecendo de transferir o ItemData
           lstAtuais.AddItem lstDisponiveis.List(iCNT)
           lstAtuais.ItemData(lstAtuais.NewIndex) = lstDisponiveis.ItemData(iCNT)
           'E remove da lista atual
           lstDisponiveis.RemoveItem iCNT
        End If
    Next
    
    'Ativa o alterado e o botão aplicar
    bAlterado = True
    cmdAplicar.Enabled = True
    
End Sub

Private Sub cmdPermitir_Click()
    Dim iCNT As Integer
    
'Vasculha todos os itens da lista verificando se o item está marcado ou não
    For iCNT = lstAtuais.ListCount - 1 To 0 Step -1
        If lstAtuais.Selected(iCNT) Then
        'Se estiver selecionado transfere a opção para a outra lista
        'não esquecendo de transferir o ItemData
           lstDisponiveis.AddItem lstAtuais.List(iCNT)
           lstDisponiveis.ItemData(lstDisponiveis.NewIndex) = lstAtuais.ItemData(iCNT)
           'E remove da lista atual
           lstAtuais.RemoveItem iCNT
        End If
    Next
    
    'Ativa o alterado e o botão aplicar
    bAlterado = True
    cmdAplicar.Enabled = True
End Sub

Precisamos agora nos preocupar com a atualização das permissões que será feita ao clicarmos no botão "Aplicar". O código do botão em si é simples :

Private Sub cmdAplicar_Click()
    AtualizaPermissoes
    cmdAplicar.Enabled = False
    bAlterado = False
End Sub

A parte complexa foi encapsulada na sub "AtualizaPermissoes". Algumas permissões terão que ser incluidas, outras excluidas, por isso precisaremos de 2 Commands parametrizados para realizar esta tarefa : cmdApagar para apagar uma permissão de determinado usuário e cmdInserir para inserir a permissão para um determinado usuário. Veja as instruções SQL utilizadas :

cmdApagar
DELETE FROM USU_PERMISSAO WHERE permissao= ? AND SID = ?
cmdInserir
INSERT INTO `USU_PERMISSAO` VALUES (?,?)

Não podendo esquecer de configurar o nome e o tipo dos parâmetros na guia "Parameters", nas propriedades de cada command.

A sub "AtualizaPermissoes" deverá, de fato, realizar 2 processamentos : Descobrir quais itens de permissões do banco não estão mais na lista e deleta-los; e descobrir quais itens de permissões da lista não estão no banco e inclui-los. Para ambos os casos será necessário novamente o uso do cmdUsuario.

Veja como fica o código :

Sub AtualizaPermissoes()

Dim iCNT As Integer

'Abre o cmdUsuario, recuperando as permissões cadastradas para este usuário
DE.cmdUsuario SIDs.Item(cmbusuarios.List(cmbusuarios.ListIndex))

'Faz o primeiro laço através das permissões cadastradas
While Not DE.rscmdUsuario.EOF

      If Not ExistenaLista(DE.rscmdUsuario.Fields("permissao").Value) Then
         'Se a permissão não estiver na lista é eliminada
         'observe mais um interessante uso para a função ExistenaLista
         DE.cmdApagar DE.rscmdUsuario.Fields("codpermissao").Value, DE.rscmdUsuario.Fields("SID").Value
      End If
      
      'Passa para a próxima permissão
      DE.rscmdUsuario.MoveNext
Wend

'Faz um laço através dos itens da lista
For iCNT = 0 To lstAtuais.ListCount - 1
'Verifica se existe algo cadastrado. O find daria erro se não existisse
    If DE.rscmdUsuario.RecordCount > 0 Then
    'Vai ao primeiro registro e localiza a permissão do usuário
        DE.rscmdUsuario.MoveFirst
        DE.rscmdUsuario.Find "permissao='" & lstAtuais.List(iCNT) & "'", 0
    End If
    
    If DE.rscmdUsuario.EOF Then
       'Se não achou é porque é nova, portanto insere no banco
       DE.cmdInserir SIDs.Item(cmbusuarios.List(cmbusuarios.ListIndex)), lstAtuais.ItemData(iCNT)
    End If

Next

'Fecha o cmdUsuario
DE.rscmdUsuario.Close

End Sub

Com o código do botão Ok logo abaixo (observe a checagem do bAlterado) encerramos o código da tela de atribuição de permissões aos usuários.

Private Sub cmdOk_click()
    If bAlterado Then
        AtualizaPermissoes
    End If
    Unload Me
End Sub

O próximo passo será criarmos a entrada na aplicação. Veja qual seria o algorítimo para isso :

Neste ponto devemos tomar muito cuidado para não inserirmos nenhuma falha de segurança indesejada. De fato, o algorítimo acima já está fazendo isso : Não é possível obter o SID do usuário logado (se alguém descobrir como, email-me), por isso teremos que ir ao servidor, procurar pelo nome de usuário e enfim obter seu SID.

Porém o usuário pode trapacear. Ele pode se conectar como um usuário local de mesmo nome que um administrador do servidor ("Administrator", por exemplo) e isso confundiria nosso algorítimo, fazendo-o recuperar o SID do administrator e consequentemente suas permissões, o que é muito mal. Podemos obtar por duas saídas :

A primeira opção é a mais recomendável na maioria dos casos, mas para efeito de demonstração vamos optar pela 2a opção. Transformar o código posteriormente será simples.

Outra questão a ser observada é que nossa tabela de permissões está vazia na primeira execução da aplicação. Mesmo que tudo funcione corretamente ninguém terá permissão alguma, nem de atribuir permissão.

Para corrigir esse problema deveremos fazer com que em sua primeira execução a aplicação atribua permissões para o administrator do domínio. Apenas as permissões 4 e 5 são necessárias (permissão para atribuir permissão). Vejamos como fica nosso algorítimo corrigido :

Para fazer o teste para determinar se precisaremos ou não cadastrar as permissões para o Administrator precisaremos utilizar mais um Command, cmdQTD, com a seguinte instrução SQL :

Select count(*) as total from USU_PERMISSAO

Esse Command obterá para nós a quantidade de registros na tabela de permissões (USU_PERMISSAO). Se for 0 então deveremos cadastrar o administrator.

Para gerenciar as informações do usuário precisaremos de variáveis globais (definidas em um módulo). Veja :

Public Usuario As String    'Guarda o nome do usuário
Public Permissoes As New Collection     'Coleção de permissões que o usuário possui
Public SID As String    'SID do usuário

 

Vejamos o código do form_load do MDI :

Private Sub MDIForm_Load()
'Abre o command
    DE.cmdQTD
    
    'Verifica a quantidade de registros
    'Se 0 chama a sub AtribuiAdm
    If DE.rscmdQTD.Fields("total") = 0 Then
       AtribuiAdm
    End If
    DE.rscmdQTD.Close
    
    'Obtem nome do usuário e seu SID
    Usuario = NomeUsuario()
    
    'Testa a sessão do usuário
    If Not TestaSessao Then
       MsgBox "Tentativa de burlar o sistema. Operação encerrada!"
       Unload Me
       Exit Sub
    End If
    
    'Obtem o SID do usuário
    SID = SIDUsuario(Usuario)
    
    'Lê as permissões do banco para RAM
    LerPermissoes
    
    'Atribui as permissões nos objetos do MDI
    AtribuirPermissoes Me

End Sub

Como pode notar, dividimos as tarefas entre diversas subs e funções. Vejamos cada uma delas :

Sub AtribuiAdm()
'Define as variáveis para localizar o usuário
Dim user As IADsUser
Dim dom As IADsContainer

'Obtem o container (domínio)
    Set dom = GetObject("WinNT://bufalo")
    
    'Filtra os objetos
    dom.Filter = Array("user")
    
    'Faz um laço para localizar o usuário
    For Each user In dom
        If UCase(user.Name) = "ADMINISTRATOR" Then
        'Encontrando, faz a inserção das permissões 4 e 5
        'Observe novamente a utilização do DE
        'e da função sSID para converter o SID para string
            DE.cmdInserir sSID(user.objectsId), 5
            DE.cmdInserir sSID(user.objectsId), 4
        End If
    Next
    
End Sub

Nenhuma grande novidade nesta primeira função, apenas um interessante uso conjunto de muitos conceitos que já vimos.

A função NomeUsuário, porém, terá que fazer uso de uma função da API para obter o nome do usuário logado na máquina local. Veja :


Public Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long

Function NomeUsuario() As String

    Dim sBuffer As String
    Dim lSize As Long
    
    'Preenche a variável com espaços em branco
    'isso é necessário para a função da API
    sBuffer = Space$(255)
    
    'Define o tamanho máximo a ser recuperado
    lSize = 255
    Call GetUserName(sBuffer, lSize)
    
    'A variável lsize voltou corrigida para o tamanho verdadeiro
    'da informação, mas com um byte a mais, dai a utilização do
    'left com lsize - 1
    NomeUsuario = Left$(sBuffer, lSize - 1)

End Function

A função Testasessao também precisará fazer uso de uma função da API, neste caso para obter o nome da máquina local. Veja o código :


Private Declare Function GetComputerName Lib "kernel32" _
Alias "GetComputerNameA" (ByVal sBuffer As String, lSize As Long) _
As Long

Function TestaSessao() As Boolean

Dim X As Long
Dim machinename As String
Dim adsFSOps As IADsFileServiceOperations
Dim adsSession As IADsSession
Dim adsSessions As IADsCollection

'Recupera o nome da máquina atual
machinename = Space$(16)
X = GetComputerName(machinename, 16)
machinename = Left(Trim(machinename), Len(Trim(machinename)) - 1)


' Obtem o objeto referente ao serviço lanmanserver do servidor
' de domínio. Assim podemos obter as sessões conectadas no servidor
Set adsFSOps = GetObject("WinNT://BUFALO/MAQ3/lanmanserver")

' Obtem a coleção de sessões conectadas
Set adsSessions = adsFSOps.Sessions

'Inicializa a variável com false
TestaSessao = False

'Faz um laço através de todas as sessões conectadas
For Each adsSession In adsSessions
    'Verifica se achou a sessão referente a máquina local
    If UCase(adsSession.Computer) = UCase(machinename) Then
    
       'Se achou verifica se o nome de usuário é igual
       If UCase(adsSession.user) = UCase(Usuario) Then
          'Se sim então está tudo correto
          TestaSessao = True
          Exit Function
       Else
          'caso contrário ocorreu uma falha
          TestaSessao = False
		  Exit Function
       End If
    End If
Next adsSession

End Function

Como mencionamos anteriormente, haveria outra opção : Ao invés de simplesmente retornar false caso o nome do usuário não bata pode-se assumir o nome de usuário encontrado como sendo o nome de usuário válido e passar a utilizar suas permissões. Veja como ficaria :


Private Declare Function GetComputerName Lib "kernel32" _
Alias "GetComputerNameA" (ByVal sBuffer As String, lSize As Long) _
As Long

Function TestaSessao() As Boolean

Dim X As Long
Dim machinename As String
Dim adsFSOps As IADsFileServiceOperations
Dim adsSession As IADsSession
Dim adsSessions As IADsCollection

'Recupera o nome da máquina atual
machinename = Space$(16)
X = GetComputerName(machinename, 16)
machinename = Left(Trim(machinename), Len(Trim(machinename)) - 1)


' Obtem o objeto referente ao serviço lanmanserver do servidor
' de domínio. Assim podemos obter as sessões conectadas no servidor
Set adsFSOps = GetObject("WinNT://BUFALO/MAQ3/lanmanserver")

' Obtem a coleção de sessões conectadas
Set adsSessions = adsFSOps.Sessions

'Inicializa a variável com false
TestaSessao = False

'Faz um laço através de todas as sessões conectadas
For Each adsSession In adsSessions
    'Verifica se achou a sessão referente a máquina local
    If UCase(adsSession.Computer) = UCase(machinename) Then
    
       'Se achou verifica se o nome de usuário é igual
       If UCase(adsSession.user) = UCase(Usuario) Then
          'Se sim então está tudo correto
          TestaSessao = True
          Exit Function
       Else
          'caso contrário ocorreu uma falha
		  Usuario=adsSession.user
          TestaSessao = False
		  Exit Function
       End If
    End If
Next adsSession

End Function

Usuario é uma variável global, portanto pode ser alterado de dentro da função. A função então está assumindo o nome de usuário encontrado na sessão como sendo o nome de usuário válido. A chamada da TestaSessao foi feita antes do SID do usuário ser recuperado, portanto o que será recuperado será o SID do usuário identificado na sessão.

A função TestaSessao sem dúvida é uma forma versátil de mudar entre um método e outro de trabalho, mas talvez você prefira apenas reconhecer o usuário por sua sessão mantida com o servidor. Neste caso você não precisaria fazer a busca do nome do usuário via API, faria apenas pela TestaSessao, que poderia não ser uma função mas uma sub. Deixo estes detalhes de otimização para vocês.

A função sidUsuario tem por objetivo capturar o SID do usuário a partir do seu nome. Tarefa simples, bastando usar o próprio nome do usuário no caminho do getobject. Veja :

Function SIDUsuario(sUserName As String) As String
Dim user As IADsUser

    Set user = GetObject("WinNT://bufalo/" & sUserName)
    
    SIDUsuario = sSID(user.objectsid)

End Function

 

A sub LerPermissoes é bem simples, apenas faz a leitura do banco para uma collection global, sem novidades.

Sub LerPermissoes()
'Abre o command com as permissões
    DE.cmdUsuario SID
    
    'Faz o laço através das permissões
    While Not DE.rscmdUsuario.EOF
    
        'Adiciona a permissão na collection e passa para
        'a próxima
        Permissoes.Add DE.rscmdUsuario.Fields("codpermissao").Value
        DE.rscmdUsuario.MoveNext
        
    Wend
    
    'Fecha tudo
    DE.rscmdUsuario.Close
End Sub

A sub atribuirpermissoes tem algumas complexidades a mais : A atribuição de permissões não será feita apenas para menus, mas para qualquer componente de um form. Além disso não será um forma específico, esta sub poderá ser chamada para fazer a atribuição de qualquer form, portanto terá que receber o form como parâmetro e vasculhar a coleção controls procurando por controles que precisem de alguma permissão para estarem habilitados (que tem "P" na tag). Encontrando verifica se o usuário possui a devida permissão. Se não possui, desabilita o componente.

Veja o código :

Sub AtribuirPermissoes(f As Form)
Dim cnt As Control
Dim iPer As Integer

'Vasculha todos os controls do form recebido
For Each cnt In f.Controls
    'Verifica se o tag inicia-se com "P"
    If cnt.Tag Like "P*" Then
       'Extrai o número da permissão
       iPer = Right(cnt.Tag, Len(cnt.Tag) - 1)
       
       'Verifica se a permissão existe na collection
       If Not Localizar(iPer) Then
          'caso não exista desabilita o control
          cnt.Enabled = False
       End If
    End If
Next

End Sub

Como pode observar utilizamos mais uma função, a Localizar, para verificar a existência de uma permissão dentro da collection. Veja o código :

Function Localizar(iPer As Integer) As Boolean
Dim iCNT As Integer

For iCNT = 1 To Permissoes.Count
    If Permissoes(iCNT) = iPer Then
       Localizar = True
       Exit Function
    End If
Next

Localizar = False

End Function

Com isso temos todo o permissionamento em nossa aplicação exemplo funcionando. De fato, ela tem 2 bugs :

Resolveremos estas questões nos próximos artigos, transformando isso em uma pequena série.

Vale destacar algo que você já deve ter notado com base no texto deste artigo : A importância de associar conhecimentos de programação com o de rede para que no atual panorama tecnológico possamos tomar as melhores decisões na definição das arquiteturas dos softwares que desenvolvemos e desta forma fazer jus ao título de "analista de sistemas".

Você pode baixar os arquivos referentes a esse artigo de nossa área de download, mas não esqueça que para testa-los você precisa ter um domínio do NT e corrigir os nomes de máquina e domínio no código da aplicação deste artigo.


Dennes Torres
MCSD,MCSE,MCDBA

 

 

 

 



� Búfalo Informática, Treinamento e Consultoria - Rua Álvaro Alvim, 37 Sala 920 - Cinelândia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail:
contato@bufaloinfo.com.br