![]() |
||||||||
|
|
||||||||


| com exemplos em VB |
| Componente para deixar forms em Vb semelhantes às telas do winnamp |
| Componente para colocar sua aplicação VB no Systray |
| Componente para transformar sua aplicação VB em serviço |
| Ferramentas úteis para quem usa Olap Server |
| |

|
||||
Pesquisa personalizada
Implementando a segurança de WebServices Os WebServices em geral já são conhecidos de todos, todos já viram e/ou ouviram falar do poder dos webServices para comunicação entre aplicações. Mas como controlar a segurança de uma ferramenta tão versátil mas ao mesmo tempo exposta na web ? Foi pensando nisso que o W3C criou padrões a mais de segurança para os webServices, o WS-Security e o WS-Policy. Para entendermos como isso funciona precisamos entender melhor a estrutura dos pacotes SOAP e a forma como o padrão XML deixa essa estrutura extensível. O pacote SOAP possui uma estrutura com uma mensagem e esta mensagem contendo um cabeçalho e um corpo da mensagem. Algo mais ou menos como abaixo :
Normalmente muita gente se confunde com a relação entre o SOAP e o XML. O XML define o padrão de escrita, a forma de escrita em tags, abertura e fechamento, estrutura hierárquica, assim por diante. Mas quando resolvemos escrever um documento XML, começamos a nomear as tags. Ao dar nomes as tags estamos criando um formato de documento, um padrão de documento, assim sendo estamos criando uma nova linguagem. É isso que o SOAP é : uma nova linguagem baseada na escrita XML. A escrita SOAP determina este formato que citamos : Mensagem, cabeçalho, rodapé. Um documento, para ser SOAP, tem que estar neste formato. Assim um documento é um documento XML e é um documento SOAP devido ao formato que atende. Para identificar as inúmeras linguagens existentes foram criados nomes para as linguagens. Como essas linguagens seriam criadas aos milhares ao redor do mundo, para ter certeza que os nomes seriam únicos convencionou-se que os nomes conteriam o nome de domínio da empresa que criou a linguagem mais o nome da linguagem propriamente, formando um endereço HTTP. Muitos, ao olharem esse endereço HTTP, costumam se confundir perguntando se isso é um endereço válido e o porque de estar ali no documento, perguntando-se até mesmo se para interpretar o documento é necessário ter acesso a web. Então fica respondido : Este "endereço" http representa apenas o nome da linguagem, é apenas uma nomenclatura, nada mais. Não haverá tentativa de acesso durante a interpretação do documento. A essa nomenclatura de linguagens passamos a dar o nome de NameSpace. A identificação do NameSpace SOAP é :
Para entender com mais detalhes o SOAP e sua necessidade veja a apresentação em http://www.bufaloinfo.com.br/Artigos/artigo1408.asp A questão é que, como citei, o SOAP não resolve todos os problemas. Alguns problemas ficam pendentes, como por exemplo, segurança, o assunto deste nosso artigo. Como autenticar, como transmitir logins e senhas de forma segura ? O SOAP foi de fato desenvolvido prevendo sua ampliação para incluir futuros recurso. Dai o cabeçalho da mensagem, que vimos anteriormente. Neste cabeçalho podemos transmitir tags adicionais, informações adicionais sobre a comunicação. Um exemplo dessas informações adicionais é a transmissão de login e senha de usuários. É ai que entra a necessidade de novos padrões. Uma aplicação client pode inserir login e senha de usuário no cabeçalho da mensagem. O servidor lê a informação e autentica. A questão é que o formato que for utilizado pelo client precisa ser corretamente interpretado pelo servidor. Então torna-se necessário um padrão para isso : WS-Security. O WS-Security define o padrão de nomes de tags que serão utilizadas para transmitir dados de autenticação, entre outras informações. É ai que entra a extensibilidade do XML e, consequentemente, do SOAP. O SOAP tem um namespace, as tags pertencem a ele. Mas podemos adicionar na raiz do documento outros namespaces, como por exemplo do WS-Security. Assim sendo podemos inserir tags do WS-Security dentro do cabeçalho da mensagem. A mensagem assim passa a envolver mais de uma linguagem, mais de um namespace, essa é a grande vantagem da extensibilidade do XML O WS-Security é um padrão especificado pelo W3C. É uma nova linguagem formada por tags para serem inseridas no cabeçalho da mensagem SOAP, funcionando como uma extensão SOAP. Mas como montar o documento, concatenando texto ? A questão é que, para o padrão, a forma como o documento é construida não importa em nada. Cabe a cada fabricante criar simplificações, Wizards, para que o programador não tenha que recorrer ao nível mais baixo de montagem : A concatenação de texto. Desta forma a Microsoft criou o WSE - Web Services Enhancements . O WSE se agrega ao Visual Studio permitindo a criação de WebServices seguros, implementando o protocolo WS-Security, entre outros. O WSE possui a versão 2.0, para o framework 1.1 e a versão 3.0 para o Framework 2.0, sendo que a versão 3.0 encontra-se ainda em Beta. Vamos então começar vendo um passo a passo para a construção de um WebService que utilize recursos de autenticação. Como primeiro passo vamos criar um webService simples, sem mistérios, com 2 métodos : 1 devolvendo a lista de produtos da empresa, outro devolvendo a lista de clientes. 289 <WebMethod()> _ 290 Public Function ListarClientes() As dsDados 291 DA.Fill(DsDados1) 292 Return DsDados1 293 End Function 294 295 <WebMethod()> _ 296 Public Function ListarProdutos() As dsDados 297 daProdutos.Fill(DsDados1) 298 Return DsDados1 299 End Function Feito o WebService, para darmos prosseguimento precisaremos instalar o WSE. O WSE tem várias opções de instalação, de acordo com a forma como se pretende utiliza-lo. As opções de instalação permitem instalar apenas o RunTime, o RunTime e ferramentas administrativas, tudo isso mais os addIns para o Visual Studio ou uma instalação customizada.
Após a instalação podemos configurar o WebService para fazer uso do WSE. A instalação adiciona ao menu de contexto do projeto uma opção para que façamos a configuração do WSE.
Na primeira tela, general, habilitamos as duas checkbox. A primeira adiciona um references para a biblioteca do WSE. Já a 2a só pode ser habilitada em projetos web. Esta 2a opção adiciona ao web.config as configurações de soap extensions para o funcionamento do WSE.
Feito isso devemos especificas as policys de acesso ao serviço. As policies determinam quem pode ou não acessar o serviço. Essa determinação pode ser feita de duas formas : por código ou pelas policies. A especificação das policies vai gerar um novo arquivo XML, PolicyCache.config . Temos então mais uma linguagem, mais um padrão envolvendo os webServices : WS-Policy. Por código teriamos que a cada método testar as características do usuário que foram transmitidas, isso não é bom. Pelas policies fazemos com que seja gerado um documento XML especificando quem pode ou não acessar o serviço. A execução da policy, ou seja, a restrição dos usuários, é executada por uma SoapExtension que foi adicionada ao Web.Config. Essa SoapExtension intercepta eventos dos WebServices de forma a validar a transmissão SOAP - no caso, a presença dos requisitos determinados na policy - antes que os métodos do webService sejam executados. Uma execução simples da aplicação client resulta em uma PolicyException, ou seja, o pacote SOAP não atende as policies exigidas pelo servidor. Para adicionar a Policy entraremos na aba correspondente - Policy - habilitaremos as policies e faremos um add para adicionarmos uma nova policy.
Somos então interrogados sobre o endPoint para o qual desejamos adicionar a policy. Um endPoint, no caso, representa um arquivo .ASMX. Poderiamos diferenciar as policies por arquivos ASMX, mas não vamos fazer isso por enquanto. Mantendo a configuração default endPoint a policy que estaremos criando irá valer para todos os ASMX dentro deste projeto (exceto aqueles que tenham policies separadas, veremos isso depois).
Feito isso é aberto um pequeno wizard para nos auxiliar com a configuração. Na primeira tela devemos indicar se estamos fazendo uma configuração para um serviço no servidor ou para uma aplicação client. As policies para um serviço no servidor irão restringir o tipo de mensagem que o servidor aceitará receber do client. Já as policies em um client irão restringir o tipo de mensagem que o client aceitará receber do servidor. Nesta mesma tela temos uma opção adicional "Secure conversation". Se o client irá fazer diversas chamadas em sequencia para o servidor então pode-se utilizar o padrão "Secure conversation", através do qual o client se autentica uma vez e estabelece uma comunicação segura com o servidor. Não abordarei este assunto neste artigo.
Nos passos seguintes indicamos quais as restrições desejamos manter com essa policie que estamos criando. As restrições referem-se a mensagem que será recebida (Request) e as mensagens que serão devolvidas (Response). Para cada uma das duas mensagens podemos determinar que desejaremos que a mensagem seja assinada ou criptografada. Assinatura : A assinatura é feita através de algorítimos de hash aplicados sobre a mensagem (veja um artigo sobre hash em http://www.bufaloinfo.com.br/artigos/artigo2405.asp ) . A assinatura garante que a mensagem não possa ser alterada durante sua transmissão. Criptografia : A criptografia garante que a mensagem não possa ser lida durante sua transmissão.
Vamos começar nosso exemplo apenas requisitando a assinatura da mensagem de Request. No passo seguinte devemos definir como será feita a transmissão da identidade do usuário. As opções são as seguintes : UserName : A identidade do usuário é transmitidade através de um token contendo o nome de usuário e sua senha. Kerberos : Autenticação padrão Kerberos, com um servidor KDC fornecendo chaves Kerberos2 : Uma versão melhorada do padrão Kerberos X509 : A identidade é transmitida através do uso de certificados digitais para a assinatura da mensagem.
Na tela seguinte devemos adicionar as restrições sobre quem poderá acessar o serviço. Essas restrições podem ser adicionadas por nome de usuário ou por grupo. Os nomes e grupos podem ou não pertencer ao active directory, isso depende da forma de autenticação que estiver sendo utilizada. Na autenticação padrão, vamos utilizar identidades do Active Directory.
Na tela final, O WSE resume para nós a policy que foi aplicada.
Ao tentarmos rodar a aplicação client imediatamente após essa configuração no servidor receberemos uma mensagem de erro indicando que a transmissão do client não está de acordo com as políticas do servidor.
Precisamos então configurar a aplicação client para poder fazer o disparo do webService no servidor. Para isso vamos utilizar mais uma vez o menu de contexto do WSE, mas dessa vez habilitando apenas a 1a opção na aba general - a única possível. Na verdade isso é apenas uma forma rápida de fazermos uma references para a biblioteca do WSE. Feito isso devemos também fazer um update na WebReferences. Uma referencia tradicional gera apenas uma classe de proxy. Uma referencia a um serviço com WSE gera 2 classes de proxy : Uma tradicional, como a conhecemos e uma segunda classe, que nos permite transmitir as informações de segurança junto ao pacote SOAP. Observe que as policies do servidor não apenas definem os usuários que poderiam acessar o webService, mas também determinam que a mensagem deveria estar assinada. A assinatura é um recurso que envolve criptografia de forma que haja uma garantia de que a mensagem não poderá ser adulterada durante seu caminho entre o client e o servidor. A assinatura tanto pode ser feita a partir do client para o servidor como do servidor para o client e é indispensável na transmissão de uma identificação de usuário para que assim se tenha certeza de que a transmissão não foi adulterada. Assim sendo, para fazermos com que o client possa se identificar para o servidor o client deverá não só inserir na chamada SOAP a sua identificação mas também inserir na chamada SOAP uma assinatura. Veja o passo a passo para fazer isso :
Veja como fica o código : 153 Private Sub cmdClientes_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdClientes.Click 154 155 156 Dim obj As New Servico.srvDadosWse 157 158 Dim tk As New UsernameToken("ALUNO7\ADMINISTRATOR", "bufalo", PasswordOption.SendPlainText) 159 160 161 Dim rc As SoapContext 162 rc = obj.RequestSoapContext 163 164 rc.Security.Tokens.Add(tk) 165 rc.Security.Elements.Add(New MessageSignature(tk)) 166 167 168 DsDados1.Merge(obj.ListarClientes) 169 End Sub Porém, para que este cenário funcione precisamos de alguns cuidados adicionais. Dois erros típicos irão ocorrer rodando esta aplicação neste ponto. Primeiro erro : Falha de autenticação, logon failed.
Segundo erro : A mensagem não está em conformidade com as policies Ocorre que em alguns casos o arquivo de policy possui alguns problemas nas partes referentes a exigência do token de usuário e da assinatura. Veja como deve ser este trecho :
Claro que poderão haver variações, mas aqui temos o exemplo mais simples, com a senha transmitida em texto aberto. Para fazer com que nosso exemplo funcione é necessário corrigir o arquivo Policycache.config substituindo a tag TokenInfo por esta nova que está acima. É importante observar que no exemplo acima a restrição de acesso está sendo feita para um usuário especifico. Poderia ser feita para um grupo de usuários. Veja como ficaria :
Definindo a segurança por métodos Em nosso primeiro exemplo fizemos a policy com a configuração "default end point". Isso indica que as policies serão aplicadas para qualquer serviço que seja disparado. Porém podemos aplicar policies diferenciadas por serviço e por método. Para diferenciar as policies por serviço (arquivo .ASMX) é muito fácil : Basta definir como endPoint a URL do arquivo .ASMX. Porém para diferenciar por método complica um pouco mais : A ferramenta de geração de policies do WSE não diferencia as policies por métodos (que são chamados de operations), apenas permite que as policies sejam diferenciadas por .ASMX (EndPoints). Então para diferenciarmos as policies por métodos deveremos editar diretamente o arquivo XML das policies, adicionando a configuração por operations. Inicialmente fizemos a configuração de um defaultEndPoint e as policies para ele. Veja como fica trecho do arquivo com o defaultEndPoint :
A configuração de um novo endPoint podemos fazer através da ferramenta de configuração do WSE. Na tela onde é perguntado qual o nome do endPoint devemos indicar a URL do ASMX. Dentro do endPoint será criada uma defaultOperation. Isso precisaremos alterar manualmente, dentro do arquivo, para determinarmos as policies de cada método.
Todas as chamadas para srvDados.asmx irão cair neste endPoint para definição das policies. Como não existe defaulOperation, todos os demais métodos - exceto ListarProdutos - serão barrados. Isso mesmo tendo mantido o defaultEndPoint, porque todas as chamadas do srvDados.asmx cairão com este, não com o default. Para resolver isso e fazer o ListarClientes funcionar podemos copiar a defaultOperation que fizemos inicialmente dentro do defaultEndPoint para dentro do novo endPoint. Veja como fica :
A ordem de colocação é muito importante. O pacote recebido é analisado, operation por operation. Na primeira que se encaixar a análise para. Assim sendo se a defaultOperation estivesse primeiro a policie do ListarProdutos não seria aplicada. Por fim basta observar que a mesma configuração que ajustamos anteriormente (re-escrevendo a tag tokeninfo) precisaremos acertar novamente para a policy Sign-Username-1, mais uma vez criada automaticamente pela ferramenta do WSE. Feitas essas configurações poderemos brincar com a aplicação client, fazendo testes de acesso aos métodos com diferentes usuários. Se o usuário pertencer ao grupo configurado, funcionará. Caso contrário o acesso falhará. Por que não garantir a autenticação windows no IIS ao invés de no WSE ?
Aumentando a segurança na comunicação Nos exemplos que fizemos até agora nós fizemos a transmissão da senha em PlainText. Isso é ruim, pois a transmissão de rede poderia ser capturada e, se isso ocorrer, a senha estará exposta. Ocorre que com a senha em PlainText o WSE automaticamente autentica o usuário junto ao ActiveDirectory. Nos exemplos até este momento estávamos nos aproveitando deste recurso para a autenticação do usuário. A partir do momento em que optarmos por transmitir a senha em forma de hash o WSE não mais irá validar o usuário automaticamente junto ao Active Directory. Então para resolver isso precisaremos fazer a validação por conta própria. Para isso devemos criar uma classe herdando de UserNameTokenManager. Configurando adequadamente, esta classe será utilizada pelo WSE para validar os usuários. Para testar esta validação vamos criar no banco de dados duas tabelas, uma tabela usuarios e uma tabela grupos. A tabela usuarios será relacionada com a tabela grupos, cada usuário pertencerá a um único grupo. Neste exemplo criarei a classe em um projeto a parte. O WebService terá references para a classe. Veja como fica o código : 1 Imports System.Web.Security 2 Imports System.Security.Principal 3 Public Class AutenticarUsuario 4 Inherits Microsoft.Web.Services2.Security.Tokens.UsernameTokenManager 5 6 7 Protected Overrides Function AuthenticateToken(ByVal token As Microsoft.Web.Services2.Security.Tokens.UsernameToken) As String 8 9 10 If IsNothing(token) Then 11 Throw New ArgumentNullException("token", "Não foi recebida a autenticação do usuário") 12 13 14 End If 15 16 Dim cn As New OleDb.OleDbConnection 17 Dim cmd As New OleDb.OleDbCommand 18 Dim appReader As New Configuration.AppSettingsReader 19 20 21 cmd.Connection = cn 22 cn.ConnectionString = appReader.GetValue("StringConexao", GetType(String)) 23 24 cmd.CommandText = "select senha,grupo from usuarios a,grupos b where a.idgrupo=b.idgrupo and login=?" 25 26 27 Dim dr As OleDb.OleDbDataReader 28 Dim grupo, senha As String 29 30 cmd.Parameters.Add(New OleDb.OleDbParameter("login", token.Username)) 31 cn.Open() 32 dr = cmd.ExecuteReader(CommandBehavior.SingleResult Or CommandBehavior.SequentialAccess Or CommandBehavior.SingleRow) 33 34 35 36 If Not dr.Read() Then 37 Throw New ApplicationException("Login Inválido !") 38 39 End If 40 41 senha = dr("senha").ToString 42 grupo = dr("grupo").ToString 43 cn.Close() 44 45 46 Dim gp As GenericPrincipal 47 Dim gi As GenericIdentity 48 49 gi = New GenericIdentity(token.Username) 50 gp = New GenericPrincipal(gi, New String() {grupo}) 51 52 token.Principal = gp 53 54 Return (senha) 55 End Function 56 End Class Vamos analisar esse código passo-a-passo.
Criada a classe e feito o references do webService para ela vamos então configurar a classe como sendo um novo TokenManager. Na janela de propriedades do WSE, em Security, vamos adicionar um novo Security Token Manager. Na janela de adição de um novo tokenManager são feitas 3 perguntas : Type : O tipo da classe do tokenManager. No nosso caso, o seguinte - libUser.AutenticarUsuario, libUser NameSpace : Tenha muito cuidado para não confundir isso com os NameSpaces do .NET . Não é. O NameSpace aqui refere-se ao tipo de token que a classe irá tratar. Trata-se do nameSpace XML que identifica o formato do token. No nosso caso - http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd qName : O nome do token dentro do documento soap. No nosso caso - wsse:UsernameToken
Detalhes para execução e teste Para fazer os testes devemos nos lembrar dos seguintes detalhes : Alterar a forma de transmissão da senha para hashed, além do próprio login e senha
Alterar na policy a exigência da senha em PlainText para Hashed, bem como alterar o grupo com permissão de acesso
Pronto, já podemos testar o acesso e o login e senha serão validados no banco, com a senha transmitida na forma de hash. Dennes Torres |
||||
|
Veja abaixo os comentários já enviados :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Quer
saber mais?
Faça um curso na Búfalo Informática, Treinamento e Consultoria e Prepare-se para o Mercado! Veja o que a Búfalo tem para você. |
||||
© Búfalo Informática,
Treinamento e Consultoria -
Rua Álvaro Alvim, 37 Sala 920 • Cinelândia • Rio de Janeiro • RJ
Tel.: (21)2262-1368 • (11) 3170-3056 • e-Mail: contato@bufaloinfo.com.br