![]() |
||||||||
|
|
||||||||
| Gostou
da Página? Clique no botão abaixo para indicar esta página para um amigo! |
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 • e-Mail: contato@bufaloinfo.com.br